From 85c1a8d3be5179c8ad49a06d629c240bfa358647 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 18 Aug 2024 16:47:04 +0200 Subject: [PATCH 01/66] Working on point lights --- data/shader/clouds/clouds.hsh | 2 +- data/shader/clouds/integrate.csh | 2 +- data/shader/clouds/shadow.csh | 2 +- data/shader/clouds/shadow.hsh | 2 +- data/shader/deferred/decal.fsh | 2 +- data/shader/deferred/direct.csh | 2 +- data/shader/deferred/point.fsh | 2 +- data/shader/deferred/point.vsh | 2 +- data/shader/globals.hsh | 6 ++ data/shader/ocean/caustics.csh | 2 +- data/shader/ocean/ocean.fsh | 2 +- data/shader/ocean/sharedUniforms.hsh | 2 +- data/shader/ocean/underwater.csh | 2 +- data/shader/raytracer/common.hsh | 3 + data/shader/raytracer/direct.hsh | 20 ++++- data/shader/raytracer/structures.hsh | 2 + data/shader/reflection/rtreflection.csh | 21 +++-- data/shader/rtgi/rtgi.csh | 19 +++-- data/shader/shadow.hsh | 2 +- data/shader/{structures => structures.hsh} | 0 data/shader/volumetric/volumetric.csh | 2 +- .../ui/panels/EntityPropertiesPanel.cpp | 4 + .../panels/components/LightComponentPanel.cpp | 12 ++- src/engine/graphics/Image.cpp | 27 +++---- src/engine/lighting/Shadow.cpp | 12 +-- src/engine/lighting/Shadow.h | 4 +- src/engine/renderer/DDGIRenderer.cpp | 2 +- src/engine/renderer/DirectLightRenderer.cpp | 4 +- src/engine/renderer/MainRenderer.cpp | 47 ++++++++++- src/engine/renderer/MainRenderer.h | 77 +----------------- src/engine/renderer/OceanRenderer.cpp | 2 +- src/engine/renderer/RTGIRenderer.cpp | 2 +- src/engine/renderer/RTReflectionRenderer.cpp | 2 +- src/engine/renderer/ShadowRenderer.cpp | 6 +- src/engine/renderer/TerrainShadowRenderer.cpp | 6 +- src/engine/renderer/VolumetricRenderer.cpp | 2 +- src/engine/renderer/helper/CommonStructures.h | 81 ++++++++++++++++++- src/engine/renderer/helper/LightData.cpp | 7 ++ src/engine/renderer/helper/LightData.h | 21 +++++ .../renderer/helper/RayTracingHelper.cpp | 10 ++- src/engine/scene/Scene.cpp | 6 +- .../scene/components/ComponentSerializer.cpp | 14 ++-- .../scene/components/LightComponent.cpp | 6 +- 43 files changed, 292 insertions(+), 161 deletions(-) rename data/shader/{structures => structures.hsh} (100%) create mode 100644 src/engine/renderer/helper/LightData.cpp create mode 100644 src/engine/renderer/helper/LightData.h diff --git a/data/shader/clouds/clouds.hsh b/data/shader/clouds/clouds.hsh index de2ac5995..4deb0c5e1 100644 --- a/data/shader/clouds/clouds.hsh +++ b/data/shader/clouds/clouds.hsh @@ -1,5 +1,5 @@ #include <../common/utility.hsh> -#include <../structures> +#include <../structures.hsh> layout(set = 3, binding = 1) uniform sampler2D depthTexture; layout(set = 3, binding = 2) uniform sampler3D shapeTexture; diff --git a/data/shader/clouds/integrate.csh b/data/shader/clouds/integrate.csh index 62072e567..0df456bb1 100644 --- a/data/shader/clouds/integrate.csh +++ b/data/shader/clouds/integrate.csh @@ -1,5 +1,5 @@ #include <../globals.hsh> -#include <../structures> +#include <../structures.hsh> #include <../common/stencil.hsh> #include <../common/convert.hsh> #include <../common/utility.hsh> diff --git a/data/shader/clouds/shadow.csh b/data/shader/clouds/shadow.csh index 6eb2b169d..01490c8ac 100644 --- a/data/shader/clouds/shadow.csh +++ b/data/shader/clouds/shadow.csh @@ -1,5 +1,5 @@ #include <../globals.hsh> -#include <../structures> +#include <../structures.hsh> #include <../common/convert.hsh> #include <../common/utility.hsh> #include <../common/random.hsh> diff --git a/data/shader/clouds/shadow.hsh b/data/shader/clouds/shadow.hsh index 2474a8ce5..a1f54db09 100644 --- a/data/shader/clouds/shadow.hsh +++ b/data/shader/clouds/shadow.hsh @@ -1,4 +1,4 @@ -#include <../structures> +#include <../structures.hsh> #include <../globals.hsh> #include <../common/convert.hsh> diff --git a/data/shader/deferred/decal.fsh b/data/shader/deferred/decal.fsh index 86a46edef..1cc45dda3 100644 --- a/data/shader/deferred/decal.fsh +++ b/data/shader/deferred/decal.fsh @@ -1,4 +1,4 @@ -#include "../structures" +#include <../structures.hsh> #include <../common/convert.hsh> in vec3 fTexCoordProj; diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 33d39911a..3740c5bda 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -3,7 +3,7 @@ #include -#include <../structures> +#include <../structures.hsh> #include <../shadow.hsh> #include <../globals.hsh> diff --git a/data/shader/deferred/point.fsh b/data/shader/deferred/point.fsh index b8a107239..b0acdc56e 100644 --- a/data/shader/deferred/point.fsh +++ b/data/shader/deferred/point.fsh @@ -1,4 +1,4 @@ -#include "../structures" +#include <../structures.hsh> #include <../common/convert.hsh> #include <../common/material.hsh> diff --git a/data/shader/deferred/point.vsh b/data/shader/deferred/point.vsh index 8064b9fd8..293b16be0 100644 --- a/data/shader/deferred/point.vsh +++ b/data/shader/deferred/point.vsh @@ -1,4 +1,4 @@ -#include "../structures" +#include <../structures.hsh> layout(location=0)in vec3 vPosition; diff --git a/data/shader/globals.hsh b/data/shader/globals.hsh index 73d7bccbc..54fa3acbf 100644 --- a/data/shader/globals.hsh +++ b/data/shader/globals.hsh @@ -1,7 +1,11 @@ #ifdef AE_BINDLESS #define TEXTURE_COUNT 16384 +#define CUBEMAP_COUNT 1024 +#define TEXTURE_ARRAY_COUNT 128 #else #define TEXTURE_COUNT 1 +#define CUBEMAP_COUNT 1 +#define TEXTURE_ARRAY_COUNT 1 #endif layout(set = 1, binding = 31, std140) uniform GlobalBuffer { @@ -31,6 +35,8 @@ layout(set = 1, binding = 31, std140) uniform GlobalBuffer { } globalData; layout(set = 0, binding = 3) uniform texture2D bindlessTextures[TEXTURE_COUNT]; +layout(set = 0, binding = 4) uniform texture2D bindlessCubemaps[CUBEMAP_COUNT]; +layout(set = 0, binding = 5) uniform texture2D bindlessTextureArrays[TEXTURE_ARRAY_COUNT]; layout(set = 1, binding = 12) uniform sampler2D dfgTexture; diff --git a/data/shader/ocean/caustics.csh b/data/shader/ocean/caustics.csh index 597eeeca2..b64c7534f 100644 --- a/data/shader/ocean/caustics.csh +++ b/data/shader/ocean/caustics.csh @@ -2,7 +2,7 @@ layout (local_size_x = 8, local_size_y = 8) in; #define SHADOW_FILTER_3x3 -#include <../structures> +#include <../structures.hsh> #include <../shadow.hsh> #include <../globals.hsh> #include <../common/convert.hsh> diff --git a/data/shader/ocean/ocean.fsh b/data/shader/ocean/ocean.fsh index 0803a5f4e..8aff85811 100644 --- a/data/shader/ocean/ocean.fsh +++ b/data/shader/ocean/ocean.fsh @@ -8,7 +8,7 @@ #include <../common/normalreconstruction.hsh> #include <../clouds/shadow.hsh> #include <../volumetric/volumetric.hsh> -#include <../structures> +#include <../structures.hsh> #include diff --git a/data/shader/ocean/sharedUniforms.hsh b/data/shader/ocean/sharedUniforms.hsh index 2ed613413..57006bb81 100644 --- a/data/shader/ocean/sharedUniforms.hsh +++ b/data/shader/ocean/sharedUniforms.hsh @@ -1,5 +1,5 @@ #include <../globals.hsh> -#include <../structures> +#include <../structures.hsh> #include <../volumetric/fog.hsh> layout (set = 3, binding = 11, std140) uniform UniformBuffer { diff --git a/data/shader/ocean/underwater.csh b/data/shader/ocean/underwater.csh index bfbd3d327..60bf8b067 100644 --- a/data/shader/ocean/underwater.csh +++ b/data/shader/ocean/underwater.csh @@ -5,7 +5,7 @@ layout (local_size_x = 8, local_size_y = 8) in; #include #include -#include <../structures> +#include <../structures.hsh> #include <../shadow.hsh> #include <../globals.hsh> #include <../common/convert.hsh> diff --git a/data/shader/raytracer/common.hsh b/data/shader/raytracer/common.hsh index 1b1d888a7..529005bc6 100644 --- a/data/shader/raytracer/common.hsh +++ b/data/shader/raytracer/common.hsh @@ -10,6 +10,7 @@ #define DIRECTIONAL_LIGHT 0 #define TRIANGLE_LIGHT 1 +#define POINT_LIGHT 1 #define INSTANCE_MASK_ALL (1 << 7) #define INSTANCE_MASK_SHADOW (1 << 6) @@ -114,6 +115,8 @@ Light UnpackLight(PackedLight compressed) { light.pdf = compressed.data.y; light.area = compressed.data.z; + light.radius = compressed.data.z; + light.attenuation = compressed.data.w; light.brightness = dot(light.radiance, vec3(0.33333)); return light; diff --git a/data/shader/raytracer/direct.hsh b/data/shader/raytracer/direct.hsh index ec3e32a43..54253cd41 100644 --- a/data/shader/raytracer/direct.hsh +++ b/data/shader/raytracer/direct.hsh @@ -32,7 +32,15 @@ Light GetLight(Surface surface, float seed0, float seed1, out float lightPdf) { else if (light.type == uint(DIRECTIONAL_LIGHT)) { weight = light.brightness; } - weight = clamp(weight, 0.0000001, 1.0); + else if (light.type == uint(POINT_LIGHT)) { + vec3 pointToLight = light.P - surface.P; + float sqrDistance = dot(pointToLight, pointToLight); + float lightDistance = sqrt(sqrDistance); + + weight = light.brightness * light.radius / sqrDistance; + } + + weight = clamp(weight, 0.0000001, 1000000000000.0); totalWeight += weight; float rnd = random(seed0, seed1); @@ -80,7 +88,17 @@ void SampleLight(Light light, inout Surface surface, float seed0, float seed1, if (light.type == uint(DIRECTIONAL_LIGHT)) { surface.L = normalize(-light.N); UpdateSurface(surface); + solidAngle = 1.0; dist = INF; } + else { + vec3 pointToLight = light.P - surface.P; + float sqrDistance = dot(pointToLight, pointToLight); + dist = sqrt(sqrDistance); + solidAngle = pow(max(light.radius - dist, 0.0001) / light.radius, light.attenuation); + + surface.L = pointToLight / dist; + UpdateSurface(surface); + } } } \ No newline at end of file diff --git a/data/shader/raytracer/structures.hsh b/data/shader/raytracer/structures.hsh index 7d2a31254..ae1dfb48d 100644 --- a/data/shader/raytracer/structures.hsh +++ b/data/shader/raytracer/structures.hsh @@ -156,6 +156,8 @@ struct Light { float pdf; float area; + float radius; + float attenuation; float brightness; }; diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index 66efc078f..c4109dfac 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -54,7 +54,7 @@ layout(std140, set = 3, binding = 9) uniform UniformBuffer { } uniforms; vec3 EvaluateHit(inout Ray ray); -vec3 EvaluateDirectLight(inout Surface surface); +vec3 EvaluateDirectLight(inout Surface surface, inout float seed); float CheckVisibility(Surface surface, float lightDistance); void main() { @@ -181,8 +181,14 @@ vec3 EvaluateHit(inout Ray ray) { radiance += surface.material.emissiveColor; + int directSampleCount = 4; + float curSeed = float(uniforms.frameSeed) / 255.0; // Evaluate direct light - radiance += EvaluateDirectLight(surface); + for (int i = 0; i < directSampleCount; i++) { + radiance += EvaluateDirectLight(surface, curSeed); + } + + radiance /= float(directSampleCount); // Evaluate indirect lighting #ifdef DDGI @@ -198,19 +204,18 @@ vec3 EvaluateHit(inout Ray ray) { } -vec3 EvaluateDirectLight(inout Surface surface) { +vec3 EvaluateDirectLight(inout Surface surface, inout float seed) { if (GetLightCount() == 0) return vec3(0.0); - - float curSeed = float(uniforms.frameSeed) / 255.0; - float raySeed = float(gl_GlobalInvocationID.x); + + float raySeed = float(gl_GlobalInvocationID.x * uniforms.resolution.y + gl_GlobalInvocationID.y); float lightPdf; - Light light = GetLight(surface, raySeed, curSeed, lightPdf); + Light light = GetLight(surface, raySeed, seed, lightPdf); float solidAngle, lightDistance; - SampleLight(light, surface, raySeed, curSeed, solidAngle, lightDistance); + SampleLight(light, surface, raySeed, seed, solidAngle, lightDistance); // Evaluate the BRDF vec3 reflectance = EvaluateDiffuseBRDF(surface) + EvaluateSpecularBRDF(surface); diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index 7da8e2401..a8a410b95 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -54,7 +54,7 @@ layout(std140, set = 3, binding = 9) uniform UniformBuffer { } uniforms; vec3 EvaluateHit(inout Ray ray); -vec3 EvaluateDirectLight(inout Surface surface); +vec3 EvaluateDirectLight(inout Surface surface, inout float seed); float CheckVisibility(Surface surface, float lightDistance); void main() { @@ -170,8 +170,14 @@ vec3 EvaluateHit(inout Ray ray) { radiance += surface.material.emissiveColor; + int directSampleCount = 4; + float curSeed = float(uniforms.frameSeed) / 255.0; // Evaluate direct light - radiance += EvaluateDirectLight(surface); + for (int i = 0; i < directSampleCount; i++) { + radiance += EvaluateDirectLight(surface, curSeed); + } + + radiance /= float(directSampleCount); // Evaluate indirect lighting #ifdef DDGI @@ -187,19 +193,18 @@ vec3 EvaluateHit(inout Ray ray) { } -vec3 EvaluateDirectLight(inout Surface surface) { +vec3 EvaluateDirectLight(inout Surface surface, inout float seed) { if (GetLightCount() == 0) return vec3(0.0); - float curSeed = float(uniforms.frameSeed) / 255.0; - float raySeed = float(gl_GlobalInvocationID.x); + float raySeed = float(gl_GlobalInvocationID.x * uniforms.resolution.y + gl_GlobalInvocationID.y); float lightPdf; - Light light = GetLight(surface, raySeed, curSeed, lightPdf); + Light light = GetLight(surface, raySeed, seed, lightPdf); float solidAngle, lightDistance; - SampleLight(light, surface, raySeed, curSeed, solidAngle, lightDistance); + SampleLight(light, surface, raySeed, seed, solidAngle, lightDistance); // Evaluate the BRDF vec3 reflectance = EvaluateDiffuseBRDF(surface) + EvaluateSpecularBRDF(surface); diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh index 260c45125..256381056 100644 --- a/data/shader/shadow.hsh +++ b/data/shader/shadow.hsh @@ -30,7 +30,7 @@ struct Shadow { int cascadeCount; - float aligment1; + float mapIdx; vec2 resolution; diff --git a/data/shader/structures b/data/shader/structures.hsh similarity index 100% rename from data/shader/structures rename to data/shader/structures.hsh diff --git a/data/shader/volumetric/volumetric.csh b/data/shader/volumetric/volumetric.csh index e5affd9e2..d9c47d7d7 100644 --- a/data/shader/volumetric/volumetric.csh +++ b/data/shader/volumetric/volumetric.csh @@ -5,7 +5,7 @@ layout (local_size_x = 8, local_size_y = 8) in; #include <../globals.hsh> -#include <../structures> +#include <../structures.hsh> #include <../common/ign.hsh> #include <../common/convert.hsh> #include <../common/stencil.hsh> diff --git a/src/editor/ui/panels/EntityPropertiesPanel.cpp b/src/editor/ui/panels/EntityPropertiesPanel.cpp index 748beccb9..07ce4a9ab 100644 --- a/src/editor/ui/panels/EntityPropertiesPanel.cpp +++ b/src/editor/ui/panels/EntityPropertiesPanel.cpp @@ -102,6 +102,8 @@ namespace Atlas::Editor::UI { entity.AddComponent(mat4(1.0f), false); if (!entity.HasComponent() && ImGui::MenuItem("Add mesh component")) entity.AddComponent(); + if (!entity.HasComponent() && ImGui::MenuItem("Add light component")) + entity.AddComponent(LightType::PointLight); if (!entity.HasComponent() && ImGui::MenuItem("Add audio component")) entity.AddComponent(); if (!entity.HasComponent() && ImGui::MenuItem("Add audio volume component")) @@ -157,6 +159,8 @@ namespace Atlas::Editor::UI { entity.RemoveComponent(); if (entity.HasComponent() && ImGui::MenuItem("Remove mesh component")) entity.RemoveComponent(); + if (entity.HasComponent() && ImGui::MenuItem("Remove light component")) + entity.RemoveComponent(); if (entity.HasComponent() && ImGui::MenuItem("Remove audio component")) entity.RemoveComponent(); if (entity.HasComponent() && ImGui::MenuItem("Remove audio volume component")) diff --git a/src/editor/ui/panels/components/LightComponentPanel.cpp b/src/editor/ui/panels/components/LightComponentPanel.cpp index a2a1c26e9..7b3f23f20 100644 --- a/src/editor/ui/panels/components/LightComponentPanel.cpp +++ b/src/editor/ui/panels/components/LightComponentPanel.cpp @@ -9,7 +9,7 @@ namespace Atlas::Editor::UI { bool LightComponentPanel::Render(Ref& scene, Scene::Entity entity, LightComponent &lightComponent) { - const char* typeItems[] = { "Directional" }; + const char* typeItems[] = { "Directional", "Point" }; int typeItem = static_cast(lightComponent.type); ImGui::Combo("Light type", &typeItem, typeItems, IM_ARRAYSIZE(typeItems)); lightComponent.type = static_cast(typeItem); @@ -25,10 +25,13 @@ namespace Atlas::Editor::UI { if (lightComponent.type == LightType::DirectionalLight) { ImGui::Checkbox("Main", &lightComponent.isMain); auto& directional = lightComponent.properties.directional; - ImGui::DragFloat3("Direction", &directional.direction[0], 0.005f, -1.0f, 1.0f); + ImGui::DragFloat3("Direction", glm::value_ptr(directional.direction), 0.005f, -1.0f, 1.0f); } else if (lightComponent.type == LightType::PointLight) { - + auto& point = lightComponent.properties.point; + ImGui::DragFloat3("Position", glm::value_ptr(point.position), 0.1f, -10000.0f, 10000.0f); + ImGui::DragFloat("Radius", &point.radius, 0.1f, 0.01f, 10000.0f); + ImGui::DragFloat("Attenuation", &point.attenuation, 0.01f, -0.01f, 10.0f); } ImGui::Separator(); @@ -44,6 +47,9 @@ namespace Atlas::Editor::UI { if (lightComponent.type == LightType::DirectionalLight) { lightComponent.AddDirectionalShadow(300.0f, 3.0f, 1024, 0.05f, 3, 0.95f, true, 2048.0f); } + if (lightComponent.type == LightType::PointLight) { + lightComponent.AddPointShadow(0.1f, 1024); + } } else if (lightComponent.shadow && !castShadow) { lightComponent.shadow = nullptr; diff --git a/src/engine/graphics/Image.cpp b/src/engine/graphics/Image.cpp index 19e251c6d..32d9744e1 100644 --- a/src/engine/graphics/Image.cpp +++ b/src/engine/graphics/Image.cpp @@ -68,22 +68,19 @@ namespace Atlas { imageViewInfo.subresourceRange.levelCount = mipLevels; } VK_CHECK(vkCreateImageView(device->device, &imageViewInfo, nullptr, &view)) - - // This will just duplicate the view for single-layered images, don't care for now - if (desc.type != ImageType::ImageCube) { - attachmentViews.resize(layers); - for (uint32_t i = 0; i < layers; i++) { - imageViewInfo.subresourceRange.baseArrayLayer = i; - imageViewInfo.subresourceRange.layerCount = 1; - // For attachments, we only want one mip level - imageViewInfo.subresourceRange.levelCount = 1; - VK_CHECK(vkCreateImageView(device->device, &imageViewInfo, nullptr, &attachmentViews[i])) - } + + if (desc.type == ImageType::ImageCube) { + // We need to set it back to a 2D view type when rendering to each cubemap face + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; } - else { - // A cubemap can only have one valid view - attachmentViews.resize(1); - VK_CHECK(vkCreateImageView(device->device, &imageViewInfo, nullptr, &attachmentViews[0])) + + attachmentViews.resize(layers); + for (uint32_t i = 0; i < layers; i++) { + imageViewInfo.subresourceRange.baseArrayLayer = i; + imageViewInfo.subresourceRange.layerCount = 1; + // For attachments, we only want one mip level + imageViewInfo.subresourceRange.levelCount = 1; + VK_CHECK(vkCreateImageView(device->device, &imageViewInfo, nullptr, &attachmentViews[i])) } if (desc.data) SetData(desc.data, 0, 0, 0, desc.width, desc.height, desc.depth, 0, desc.layers); diff --git a/src/engine/lighting/Shadow.cpp b/src/engine/lighting/Shadow.cpp index 3d5ac61a4..5e97a69a7 100644 --- a/src/engine/lighting/Shadow.cpp +++ b/src/engine/lighting/Shadow.cpp @@ -14,7 +14,7 @@ namespace Atlas { isCascaded = true; useCubemap = false; - maps = Texture::Texture2DArray(resolution, resolution, cascadeCount, + maps = CreateRef(resolution, resolution, cascadeCount, VK_FORMAT_D16_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); views = std::vector(cascadeCount); @@ -24,20 +24,20 @@ namespace Atlas { } Shadow::Shadow(float distance, float bias, int32_t resolution, float edgeSoftness, bool useCubemap) : - distance(distance), bias(bias), resolution(resolution), useCubemap(useCubemap), edgeSoftness(edgeSoftness) { + distance(distance), bias(bias), resolution(resolution), useCubemap(useCubemap), edgeSoftness(edgeSoftness) { isCascaded = false; if (useCubemap) { viewCount = 6; - cubemap = Texture::Cubemap(resolution, resolution, VK_FORMAT_D16_UNORM, + cubemap = CreateRef(resolution, resolution, VK_FORMAT_D16_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); } else { viewCount = 1; - maps = Texture::Texture2DArray(resolution, resolution, 1, VK_FORMAT_D16_UNORM, + maps = CreateRef(resolution, resolution, 1, VK_FORMAT_D16_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); } @@ -52,11 +52,11 @@ namespace Atlas { this->resolution = resolution; if (useCubemap) { - cubemap = Texture::Cubemap(resolution, resolution, VK_FORMAT_D16_UNORM, + cubemap = CreateRef(resolution, resolution, VK_FORMAT_D16_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); } else { - maps = Texture::Texture2DArray(resolution, resolution, viewCount, VK_FORMAT_D16_UNORM, + maps = CreateRef(resolution, resolution, viewCount, VK_FORMAT_D16_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); } diff --git a/src/engine/lighting/Shadow.h b/src/engine/lighting/Shadow.h index 89cc9aab3..f71beee16 100644 --- a/src/engine/lighting/Shadow.h +++ b/src/engine/lighting/Shadow.h @@ -55,8 +55,8 @@ namespace Atlas { std::vector views; int32_t viewCount; - Texture::Texture2DArray maps; - Texture::Cubemap cubemap; + Ref maps; + Ref cubemap; bool isCascaded = false; bool followMainCamera = false; diff --git a/src/engine/renderer/DDGIRenderer.cpp b/src/engine/renderer/DDGIRenderer.cpp index 1dbd13361..c58765b5b 100644 --- a/src/engine/renderer/DDGIRenderer.cpp +++ b/src/engine/renderer/DDGIRenderer.cpp @@ -144,7 +144,7 @@ namespace Atlas { shadowUniform.cascadeCount = shadow->viewCount; shadowUniform.resolution = vec2(shadow->resolution); - commandList->BindImage(shadow->maps.image, shadowSampler, 3, 0); + commandList->BindImage(shadow->maps->image, shadowSampler, 3, 0); auto componentCount = shadow->viewCount; for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index 3c99ed226..e0afa978a 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -63,10 +63,10 @@ namespace Atlas { shadowUniform.resolution = vec2(shadow->resolution); if (shadow->useCubemap) { - commandList->BindImage(shadow->cubemap.image, shadowSampler, 3, 1); + commandList->BindImage(shadow->cubemap->image, shadowSampler, 3, 1); } else { - commandList->BindImage(shadow->maps.image, shadowSampler, 3, 1); + commandList->BindImage(shadow->maps->image, shadowSampler, 3, 1); } auto componentCount = shadow->viewCount; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 8dca4f868..b847229ae 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -5,6 +5,7 @@ #include "../common/Packing.h" #include "../tools/PerformanceCounter.h" #include "../Clock.h" +#include #define FEATURE_BASE_COLOR_MAP (1 << 1) #define FEATURE_OPACITY_MAP (1 << 2) @@ -213,7 +214,7 @@ namespace Atlas { auto shadow = light.shadow; imageBarriers.push_back({ shadow->useCubemap ? - shadow->cubemap.image : shadow->maps.image, layout, access }); + shadow->cubemap->image : shadow->maps->image, layout, access }); } commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); @@ -1071,6 +1072,50 @@ namespace Atlas { impostor->impostorInfoBuffer.SetData(&impostorInfo, 0); } + + std::vector lightComponents; + auto lightSubset = scene->GetSubset(); + for (auto& lightEntity : lightSubset) { + auto& light = lightEntity.GetComponent(); + lightComponents.emplace_back(light); + } + + std::sort(lightComponents.begin(), lightComponents.end(), + [&](const LightComponent& light0, const LightComponent& light1) { + if (light0.isMain) + return true; + + if (light0.type == LightType::DirectionalLight) + return true; + + if (light0.type == LightType::PointLight && + light1.type == LightType::PointLight) { + return glm::distance2(light0.transformedProperties.point.position, camera.GetLocation()) + < glm::distance2(light1.transformedProperties.point.position, camera.GetLocation()); + } + + return false; + }); + + std::vector lights; + for (const auto& comp : lightComponents) { + Light light { + .color = vec4(Common::ColorConverter::ConvertSRGBToLinear(comp.color), 0.0f), + .intensity = comp.intensity, + .scatteringFactor = 1.0f, + }; + + const auto& prop = comp.transformedProperties; + if (comp.type == LightType::DirectionalLight) { + light.direction = vec4(prop.directional.direction, 0.0f); + } + else if (comp.type == LightType::PointLight) { + light.location = vec4(prop.point.position, 1.0f); + light.radius = prop.point.radius; + light.attenuation = prop.point.attenuation; + } + } + } void MainRenderer::PrepareMaterials(Ref scene, std::vector& materials, diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index 620183526..dfaa3d458 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -69,82 +69,6 @@ namespace Atlas { Ref font; private: - struct alignas(16) PackedMaterial { - - int32_t baseColor; - int32_t emissiveColor; - int32_t transmissionColor; - - uint32_t emissiveIntensityTiling; - - int32_t data0; - int32_t data1; - int32_t data2; - - int32_t features; - - }; - - struct alignas(16) GlobalUniforms { - vec4 frustumPlanes[6]; - mat4 vMatrix; - mat4 pMatrix; - mat4 ivMatrix; - mat4 ipMatrix; - mat4 pvMatrixLast; - mat4 pvMatrixCurrent; - mat4 ipvMatrixLast; - mat4 ipvMatrixCurrent; - vec2 jitterLast; - vec2 jitterCurrent; - vec4 cameraLocation; - vec4 cameraDirection; - vec4 cameraUp; - vec4 cameraRight; - vec4 planetCenter; - vec2 windDir; - float windSpeed; - float planetRadius; - float time; - float deltaTime; - uint32_t frameCount; - float mipLodBias; - }; - - struct alignas(16) DDGICascade { - vec4 volumeMin; - vec4 volumeMax; - vec4 cellSize; - ivec4 offsetDifference; - }; - - struct alignas(16) DDGIUniforms { - - DDGICascade cascades[MAX_IRRADIANCE_VOLUME_CASCADES]; - - vec4 volumeCenter; - ivec4 volumeProbeCount; - int32_t cascadeCount; - - float volumeBias; - - int32_t volumeIrradianceRes; - int32_t volumeMomentsRes; - - uint32_t rayCount; - uint32_t inactiveRayCount; - - float hysteresis; - - float volumeGamma; - float volumeStrength; - - float depthSharpness; - int optimizeProbes; - - int32_t volumeEnabled; - }; - void CreateGlobalDescriptorSetLayout(); void SetUniforms(const Ref& target, const Ref& scene, const CameraComponent& camera); @@ -170,6 +94,7 @@ namespace Atlas { Ref globalUniformBuffer; Ref pathTraceGlobalUniformBuffer; Ref ddgiUniformBuffer; + Ref lightUniformBuffer; Ref globalDescriptorSetLayout; Ref globalSampler; Ref globalNearestSampler; diff --git a/src/engine/renderer/OceanRenderer.cpp b/src/engine/renderer/OceanRenderer.cpp index 1e532302e..69c2fc3bc 100644 --- a/src/engine/renderer/OceanRenderer.cpp +++ b/src/engine/renderer/OceanRenderer.cpp @@ -81,7 +81,7 @@ namespace Atlas { shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; shadowUniform.resolution = vec2(shadow->resolution); - commandList->BindImage(shadow->maps.image, shadowSampler, 3, 8); + commandList->BindImage(shadow->maps->image, shadowSampler, 3, 8); auto componentCount = shadow->viewCount; for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { diff --git a/src/engine/renderer/RTGIRenderer.cpp b/src/engine/renderer/RTGIRenderer.cpp index c7f0cca9e..6fa3324ad 100644 --- a/src/engine/renderer/RTGIRenderer.cpp +++ b/src/engine/renderer/RTGIRenderer.cpp @@ -148,7 +148,7 @@ namespace Atlas { shadowUniform.cascadeCount = shadow->viewCount; shadowUniform.resolution = vec2(shadow->resolution); - commandList->BindImage(shadow->maps.image, shadowSampler, 3, 6); + commandList->BindImage(shadow->maps->image, shadowSampler, 3, 6); auto componentCount = shadow->viewCount; for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index b7380d876..317e47c2e 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -143,7 +143,7 @@ namespace Atlas { shadowUniform.cascadeCount = shadow->viewCount; shadowUniform.resolution = vec2(shadow->resolution); - commandList->BindImage(shadow->maps.image, shadowSampler, 3, 6); + commandList->BindImage(shadow->maps->image, shadowSampler, 3, 6); auto componentCount = shadow->viewCount; for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index 92c526a49..9e20568b1 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -206,8 +206,8 @@ namespace Atlas { */ Graphics::RenderPassDepthAttachment attachment = { - .imageFormat = shadow->useCubemap ? shadow->cubemap.format : - shadow->maps.format, + .imageFormat = shadow->useCubemap ? shadow->cubemap->format : + shadow->maps->format, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL @@ -219,7 +219,7 @@ namespace Atlas { Graphics::FrameBufferDesc frameBufferDesc = { .renderPass = renderPass, - .depthAttachment = { shadow->useCubemap ? shadow->cubemap.image : shadow->maps.image, 0, true}, + .depthAttachment = { shadow->useCubemap ? shadow->cubemap->image : shadow->maps->image, 0, true}, .extent = { uint32_t(shadow->resolution), uint32_t(shadow->resolution) } }; return device->CreateFrameBuffer(frameBufferDesc); diff --git a/src/engine/renderer/TerrainShadowRenderer.cpp b/src/engine/renderer/TerrainShadowRenderer.cpp index 4122fb1f8..b30ca57bd 100644 --- a/src/engine/renderer/TerrainShadowRenderer.cpp +++ b/src/engine/renderer/TerrainShadowRenderer.cpp @@ -147,8 +147,8 @@ namespace Atlas { */ Graphics::RenderPassDepthAttachment attachment = { - .imageFormat = shadow->useCubemap ? shadow->cubemap.format : - shadow->maps.format, + .imageFormat = shadow->useCubemap ? shadow->cubemap->format : + shadow->maps->format, .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL @@ -160,7 +160,7 @@ namespace Atlas { Graphics::FrameBufferDesc frameBufferDesc = { .renderPass = renderPass, - .depthAttachment = { shadow->useCubemap ? shadow->cubemap.image : shadow->maps.image, 0, true}, + .depthAttachment = { shadow->useCubemap ? shadow->cubemap->image : shadow->maps->image, 0, true}, .extent = { uint32_t(shadow->resolution), uint32_t(shadow->resolution) } }; return device->CreateFrameBuffer(frameBufferDesc); diff --git a/src/engine/renderer/VolumetricRenderer.cpp b/src/engine/renderer/VolumetricRenderer.cpp index 9024baa03..b7301ba65 100644 --- a/src/engine/renderer/VolumetricRenderer.cpp +++ b/src/engine/renderer/VolumetricRenderer.cpp @@ -88,7 +88,7 @@ namespace Atlas { uniforms.light.shadow.cascadeCount = shadow->viewCount; uniforms.light.shadow.edgeSoftness = shadow->edgeSoftness; - commandList->BindImage(shadow->maps.image, shadowSampler, 3, 2); + commandList->BindImage(shadow->maps->image, shadowSampler, 3, 2); auto& shadowUniform = uniforms.light.shadow; for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index 30def4a6f..088ab0333 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -23,7 +23,7 @@ namespace Atlas { int cascadeCount; - float aligment1; + float mapIdx; vec2 resolution; @@ -40,8 +40,7 @@ namespace Atlas { float scatteringFactor; float radius; - - float alignment; + float attenuation; Shadow shadow; }; @@ -65,6 +64,82 @@ namespace Atlas { float ambientFactor; }; + struct alignas(16) PackedMaterial { + + int32_t baseColor; + int32_t emissiveColor; + int32_t transmissionColor; + + uint32_t emissiveIntensityTiling; + + int32_t data0; + int32_t data1; + int32_t data2; + + int32_t features; + + }; + + struct alignas(16) GlobalUniforms { + vec4 frustumPlanes[6]; + mat4 vMatrix; + mat4 pMatrix; + mat4 ivMatrix; + mat4 ipMatrix; + mat4 pvMatrixLast; + mat4 pvMatrixCurrent; + mat4 ipvMatrixLast; + mat4 ipvMatrixCurrent; + vec2 jitterLast; + vec2 jitterCurrent; + vec4 cameraLocation; + vec4 cameraDirection; + vec4 cameraUp; + vec4 cameraRight; + vec4 planetCenter; + vec2 windDir; + float windSpeed; + float planetRadius; + float time; + float deltaTime; + uint32_t frameCount; + float mipLodBias; + }; + + struct alignas(16) DDGICascade { + vec4 volumeMin; + vec4 volumeMax; + vec4 cellSize; + ivec4 offsetDifference; + }; + + struct alignas(16) DDGIUniforms { + + DDGICascade cascades[MAX_IRRADIANCE_VOLUME_CASCADES]; + + vec4 volumeCenter; + ivec4 volumeProbeCount; + int32_t cascadeCount; + + float volumeBias; + + int32_t volumeIrradianceRes; + int32_t volumeMomentsRes; + + uint32_t rayCount; + uint32_t inactiveRayCount; + + float hysteresis; + + float volumeGamma; + float volumeStrength; + + float depthSharpness; + int optimizeProbes; + + int32_t volumeEnabled; + }; + } } \ No newline at end of file diff --git a/src/engine/renderer/helper/LightData.cpp b/src/engine/renderer/helper/LightData.cpp new file mode 100644 index 000000000..173e8a5cb --- /dev/null +++ b/src/engine/renderer/helper/LightData.cpp @@ -0,0 +1,7 @@ +#include "LightData.h" + +namespace Atlas::Renderer::Helper { + + + +} \ No newline at end of file diff --git a/src/engine/renderer/helper/LightData.h b/src/engine/renderer/helper/LightData.h new file mode 100644 index 000000000..70cb5ccf6 --- /dev/null +++ b/src/engine/renderer/helper/LightData.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../../System.h" + +#include + +namespace Atlas::Renderer::Helper { + + class LightData { + + public: + LightData() = default; + + private: + struct Light { + + }; + + }; + +} \ No newline at end of file diff --git a/src/engine/renderer/helper/RayTracingHelper.cpp b/src/engine/renderer/helper/RayTracingHelper.cpp index b27d676fe..91c31495c 100644 --- a/src/engine/renderer/helper/RayTracingHelper.cpp +++ b/src/engine/renderer/helper/RayTracingHelper.cpp @@ -8,6 +8,7 @@ #define DIRECTIONAL_LIGHT 0 #define TRIANGLE_LIGHT 1 +#define POINT_LIGHT 2 namespace Atlas { @@ -448,6 +449,7 @@ namespace Atlas { vec3 N = vec3(0.0f); float weight = 0.0f; float area = 0.0f; + float specific = 0.0f; uint32_t data = 0; @@ -458,7 +460,11 @@ namespace Atlas { N = light.transformedProperties.directional.direction; } else if (light.type == LightType::PointLight) { - + data |= (POINT_LIGHT << 28u); + weight = brightness; + P = light.transformedProperties.point.position; + area = light.transformedProperties.point.radius; + specific = light.transformedProperties.point.attenuation; } data |= uint32_t(lights.size()); @@ -468,7 +474,7 @@ namespace Atlas { gpuLight.P = vec4(P, 1.0f); gpuLight.N = vec4(N, 0.0f); gpuLight.color = vec4(radiance, 0.0f); - gpuLight.data = vec4(cd, weight, area, 0.0f); + gpuLight.data = vec4(cd, weight, area, specific); lights.push_back(gpuLight); } diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index a282e5c83..7ffdabcd5 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -836,8 +836,10 @@ namespace Atlas { auto otherComp = srcEntity.GetComponent(); auto& comp = dstEntity.AddComponent(otherComp); // Need to create a new shadow, since right now the memory is shared between components - comp.shadow = CreateRef(*otherComp.shadow); - comp.shadow->SetResolution(comp.shadow->resolution); + if (otherComp.shadow) { + comp.shadow = CreateRef(*otherComp.shadow); + comp.shadow->SetResolution(comp.shadow->resolution); + } comp.isMain = false; } if (srcEntity.HasComponent()) { diff --git a/src/engine/scene/components/ComponentSerializer.cpp b/src/engine/scene/components/ComponentSerializer.cpp index 0a17e4815..3ee1b9b09 100644 --- a/src/engine/scene/components/ComponentSerializer.cpp +++ b/src/engine/scene/components/ComponentSerializer.cpp @@ -124,24 +124,23 @@ namespace Atlas::Scene::Components { {"color", p.color}, {"intensity", p.intensity}, {"properties", typeProperties}, - {"shadow", *p.shadow}, {"isMain", p.isMain}, {"volumetric", p.volumetric} }; + + if (p.shadow) + j["shadow"] = *p.shadow; } void from_json(const json& j, LightComponent& p) { json typeProperties; - int type, mobility; - - p.shadow = CreateRef(); + int type, mobility; j.at("type").get_to(type); j.at("mobility").get_to(mobility); j.at("color").get_to(p.color); j.at("intensity").get_to(p.intensity); j.at("properties").get_to(typeProperties); - j.at("shadow").get_to(*p.shadow); j.at("isMain").get_to(p.isMain); j.at("volumetric").get_to(p.volumetric); @@ -156,6 +155,11 @@ namespace Atlas::Scene::Components { typeProperties.at("radius").get_to(p.properties.point.radius); typeProperties.at("attenuation").get_to(p.properties.point.attenuation); } + + if (j.contains("shadow")) { + p.shadow = CreateRef(); + j.at("shadow").get_to(*p.shadow); + } } void to_json(json& j, const MeshComponent& p) { diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index d968ffeca..886ca95bf 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -60,7 +60,7 @@ namespace Atlas { shadow->views[0].frustumMatrix = clipMatrix * orthoProjection; shadow->views[0].terrainFrustumMatrix = clipMatrix * orthoProjection; shadow->views[0].viewMatrix = glm::lookAt(shadowCenter, shadowCenter + - properties.directional.direction, vec3(0.0f, 1.0f, 0.0f)); + properties.directional.direction, vec3(0.0f, 1.0f, 0.0f)); } @@ -68,7 +68,7 @@ namespace Atlas { AE_ASSERT(type == LightType::PointLight && "Component must be of type point light"); - shadow = CreateRef(0.0f, bias, resolution, true); + shadow = CreateRef(0.0f, bias, resolution, 0.0f, true); } @@ -118,7 +118,7 @@ namespace Atlas { else if (type == LightType::PointLight) { vec3 position = transformedProperties.point.position; - mat4 projectionMatrix = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, properties.point.radius); + mat4 projectionMatrix = glm::perspective(glm::radians(90.0f), 1.0f, 0.01f, properties.point.radius); const vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; From 804eb363540179b716f9f00b3a3ec75d48b04b0f Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 18 Aug 2024 20:20:07 +0200 Subject: [PATCH 02/66] Some more changes, needs visual debugging --- data/shader/common/light.hsh | 0 data/shader/deferred/direct.csh | 156 +++++--- data/shader/raytracer/common.hsh | 2 +- data/shader/shadow.hsh | 354 +++++++++++++++++- data/shader/structures.hsh | 9 +- src/engine/Engine.cpp | 2 +- src/engine/renderer/DirectLightRenderer.cpp | 72 ++-- src/engine/renderer/DirectLightRenderer.h | 7 +- src/engine/renderer/MainRenderer.cpp | 52 +-- src/engine/renderer/MainRenderer.h | 2 + src/engine/renderer/helper/CommonStructures.h | 2 +- src/engine/renderer/helper/LightData.cpp | 113 ++++++ src/engine/renderer/helper/LightData.h | 19 +- 13 files changed, 641 insertions(+), 149 deletions(-) create mode 100644 data/shader/common/light.hsh diff --git a/data/shader/common/light.hsh b/data/shader/common/light.hsh new file mode 100644 index 000000000..e69de29bb diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 3740c5bda..91c2f93be 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -1,3 +1,5 @@ +#extension GL_EXT_nonuniform_qualifier : require + #define SHADOW_FILTER_VOGEL #define SHADOW_CASCADE_BLENDING @@ -16,24 +18,31 @@ layout (local_size_x = 8, local_size_y = 8) in; layout(set = 3, binding = 0, rgba16f) uniform image2D image; -#ifdef SHADOWS -layout(set = 3, binding = 1) uniform sampler2DArrayShadow cascadeMaps; -#endif + #ifdef SCREEN_SPACE_SHADOWS -layout(set = 3, binding = 2) uniform sampler2D sssTexture; +layout(set = 3, binding = 1) uniform sampler2D sssTexture; #endif #ifdef CLOUD_SHADOWS -layout(set = 3, binding = 3) uniform sampler2D cloudMap; +layout(set = 3, binding = 2) uniform sampler2D cloudMap; #endif -layout(std140, set = 3, binding = 4) uniform UniformBuffer { - Light light; +layout(std140, set = 3, binding = 3) uniform UniformBuffer { + int mapIndices[16]; + int lightCount; } uniforms; -layout(std140, set = 3, binding = 5) uniform CloudShadowUniformBuffer { +layout(std140, set = 3, binding = 4) uniform CloudShadowUniformBuffer { CloudShadow cloudShadow; } cloudShadowUniforms; +layout(set = 3, binding = 5) uniform sampler shadowSampler; + +layout(set = 3, binding = 6) uniform texture2DArray cascadeMaps[8]; +layout(set = 3, binding = 14) uniform textureCube cubeMaps[8]; + +vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMain); +float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain); + void main() { ivec2 resolution = imageSize(image); @@ -47,25 +56,105 @@ void main() { if (depth < 1.0) { vec3 geometryNormal; // We don't have any light direction, that's why we use vec3(0.0, -1.0, 0.0) as a placeholder - Surface surface = GetSurface(texCoord, depth, -uniforms.light.direction.xyz, geometryNormal); + Surface surface = GetSurface(texCoord, depth, vec3(0.0, -1.0, 0.0), geometryNormal); + + for (int i = 0; i < uniforms.lightCount && i < 8; i++) { + Light light = lights[i]; + + light.shadow.mapIdx = uniforms.mapIndices[i]; + bool isMain = i == 0 ? true : false; + direct += EvaluateLight(light, surface, geometryNormal, isMain); + } + + if (dot(surface.material.emissiveColor, vec3(1.0)) > 0.01) { + direct += surface.material.emissiveColor; + } + } + + imageStore(image, pixel, vec4(direct, 1.0)); + +} + +uint GetLightType(Light light) { + + return floatBitsToUint(light.color.a); + +} + +vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMain) { + + uint lightType = GetLightType(light); + + float lightMultiplier = 1.0; + + if (lightType == DIRECTIONAL_LIGHT) { + surface.L = normalize(-light.direction.xyz); + } + else if (lightType == POINT_LIGHT) { + vec3 pointToLight = light.location.xyz - surface.P; + float sqrDistance = dot(pointToLight, pointToLight); + float dist = sqrt(sqrDistance); + lightMultiplier = pow(max(light.radius - dist, 0.0001) / light.radius, light.attenuation); + + surface.L = pointToLight / dist; + } + + UpdateSurface(surface); + + // Direct diffuse + specular BRDF + vec3 directDiffuse = EvaluateDiffuseBRDF(surface); + vec3 directSpecular = EvaluateSpecularBRDF(surface); - float shadowFactor = 1.0; + vec3 direct = directDiffuse + directSpecular; - // Direct diffuse + specular BRDF - vec3 directDiffuse = EvaluateDiffuseBRDF(surface); - vec3 directSpecular = EvaluateSpecularBRDF(surface); + float shadowFactor = GetShadowFactor(light, surface, lightType, geometryNormal, isMain); - direct = directDiffuse + directSpecular; + vec3 radiance = light.color.rgb * light.intensity; + direct = direct * radiance * surface.NdotL * shadowFactor; -#ifdef SHADOWS - // Only need to test in the direction of the light and can the be used - // for both the transmission and reflection. The inversion is only done - // for transmissive materials - vec3 shadowNormal = surface.material.transmissive ? dot(-uniforms.light.direction.xyz, geometryNormal) < 0.0 ? + if (surface.material.transmissive) { + Surface backSurface = CreateSurface(surface.V, -surface.N, surface.L, surface.material); + + float viewDependency = saturate(dot(-surface.V, surface.L)); + // viewDependency = sqr(viewDependency); + + // Direct diffuse BRDF backside + directDiffuse = viewDependency * surface.material.transmissiveColor * EvaluateDiffuseBRDF(backSurface); + // Need to change this back + // direct += directDiffuse * radiance * backSurface.NdotL * shadowFactorTransmissive; + direct += directDiffuse * radiance * backSurface.NdotL * shadowFactor; + } + + return direct; + +} + +float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain) { + + if (light.shadow.cascadeCount <= 0) + return 1.0; + + ivec2 resolution = imageSize(image); + ivec2 pixel = ivec2(gl_GlobalInvocationID); + vec2 texCoord = (vec2(pixel) + 0.5) / vec2(resolution); + + float shadowFactor = 1.0; + + vec3 shadowNormal = surface.material.transmissive ? dot(surface.L, geometryNormal) < 0.0 ? -geometryNormal : geometryNormal : geometryNormal; - shadowFactor = CalculateCascadedShadow(uniforms.light.shadow, cascadeMaps, surface.P, vec3(vec2(pixel) + 0.5, 0.0), - shadowNormal, saturate(dot(-uniforms.light.direction.xyz, shadowNormal))); -#endif + + if (lightType == DIRECTIONAL_LIGHT) { + /* + shadowFactor = CalculateCascadedShadow(light.shadow, cascadeMaps[nonuniformEXT(light.shadow.mapIdx)], + shadowSampler, surface.P, vec3(vec2(pixel) + 0.5, 0.0), + shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); + */ + } + else if (lightType == POINT_LIGHT) { + + } + + if (isMain) { #ifdef CLOUD_SHADOWS float cloudShadowFactor = CalculateCloudShadow(surface.P, cloudShadowUniforms.cloudShadow, cloudMap); @@ -76,29 +165,8 @@ void main() { float sssFactor = textureLod(sssTexture, texCoord, 0).r; shadowFactor = min(sssFactor, shadowFactor); #endif - - vec3 radiance = uniforms.light.color.rgb * uniforms.light.intensity; - direct = direct * radiance * surface.NdotL * shadowFactor; - - if (surface.material.transmissive) { - Surface backSurface = CreateSurface(surface.V, -surface.N, surface.L, surface.material); - - float viewDependency = saturate(dot(-surface.V, surface.L)); - // viewDependency = sqr(viewDependency); - - // Direct diffuse BRDF backside - directDiffuse = viewDependency * surface.material.transmissiveColor * EvaluateDiffuseBRDF(backSurface); - direct += directDiffuse * radiance * backSurface.NdotL * shadowFactorTransmissive; - } - - if (dot(surface.material.emissiveColor, vec3(1.0)) > 0.01) { - direct += surface.material.emissiveColor; - } - - //direct = cloudShadowFactor; - } - imageStore(image, pixel, vec4(direct, 1.0)); + return shadowFactor; } \ No newline at end of file diff --git a/data/shader/raytracer/common.hsh b/data/shader/raytracer/common.hsh index 529005bc6..9d8a71045 100644 --- a/data/shader/raytracer/common.hsh +++ b/data/shader/raytracer/common.hsh @@ -10,7 +10,7 @@ #define DIRECTIONAL_LIGHT 0 #define TRIANGLE_LIGHT 1 -#define POINT_LIGHT 1 +#define POINT_LIGHT 2 #define INSTANCE_MASK_ALL (1 << 7) #define INSTANCE_MASK_SHADOW (1 << 6) diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh index 256381056..0262a61fb 100644 --- a/data/shader/shadow.hsh +++ b/data/shader/shadow.hsh @@ -30,7 +30,7 @@ struct Shadow { int cascadeCount; - float mapIdx; + int mapIdx; vec2 resolution; @@ -401,4 +401,356 @@ float CalculateShadowWorldSpace(Shadow shadow, sampler2DArrayShadow cascadeMaps, return cascadeLookup(shadow, cascadeMaps, 0.0, cascadeMatrix, position, position, 0.0, false); +} + +float offsetLookup(texture2DArray cascadeMaps, sampler shadowSampler, vec2 flooredUV, float u, float v, float cascadeIndex, + vec2 texelSize, float depth, float bias) { + + vec2 uv = 0.5 * (flooredUV + vec2(u, v) * texelSize) + 0.5; + +#ifdef AE_TEXTURE_SHADOW_LOD + // This fixes issues that can occur at cascade borders + return textureLod(sampler2DArrayShadow(cascadeMaps, shadowSampler), + vec4(uv, cascadeIndex, depth + bias), 0); +#else + return texture(sampler2DArrayShadow(cascadeMaps, shadowSampler), + vec4(uv, cascadeIndex, depth + bias)); +#endif + +} + +float offsetLookup(texture2DArray cascadeMaps, sampler shadowSampler, vec2 uv, float cascadeIndex, float edgeSoftness, + vec2 texelSize, vec2 invResolution, vec3 fragmentPosition, int lookupIndex, float depth, float bias) { + + uv = 0.5 * (uv * invResolution) + 0.5; + vec2 samplingSpread = edgeSoftness * invResolution * 64.0; + + float phi = 2.0 * PI * GetInterleavedGradientNoise(fragmentPosition.xy); + vec2 offset = VogelDiskSample(lookupIndex, 16, phi) * samplingSpread; + +#ifdef AE_TEXTURE_SHADOW_LOD + // This fixes issues that can occur at cascade borders + return textureLod(sampler2DArrayShadow(cascadeMaps, shadowSampler), + vec4(uv + offset, cascadeIndex, depth + bias), 0); +#else + return texture(sampler2DArrayShadow(cascadeMaps, shadowSampler), + vec4(uv + offset, cascadeIndex, depth + bias)); +#endif + +} + + +float cascadeLookup(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, float cascadeIndex, mat4 cascadeTransform, + vec3 fragmentPosition, vec3 position, float bias, bool fade) { + + vec4 shadowCoords = cascadeTransform * vec4(fragmentPosition, 1.0); + shadowCoords.xyz /= shadowCoords.w; + + float fadeout = fade ? clamp((-fragmentPosition.z + 2.0 - shadow.distance) * 0.5, 0.0, 1.0) : 0.0; + + //shadowCoords.z = shadowCoords.z * 0.5 + 0.5; + + if (abs(fadeout - 1.0) < 1e-6) + return 1.0; + + vec2 res = shadow.resolution; + vec2 resInv = 1.0 / res; + + vec2 uv = shadowCoords.xy * res; + + vec2 flooredUV = vec2(floor(uv.x), floor(uv.y)); + + float s = fract(uv.x); + float t = fract(uv.y); + + flooredUV *= resInv; + + float visibility = 0.0; + +#ifdef SHADOW_FILTER_1x1 + visibility += offsetLookup(cascadeMaps, shadowSampler, shadowCoords.xy, 0.0, 0.0, float(cascadeIndex), resInv, shadowCoords.z, bias); +#endif +#ifdef SHADOW_FILTER_3x3 + float uw0 = (3.0 - 2.0 * s); + float uw1 = (1.0 + 2.0 * s); + + float u0 = (2.0 - s) / uw0 - 1.0; + float u1 = s / uw1 + 1.0; + + float vw0 = (3.0 - 2.0 * t); + float vw1 = (1.0 + 2.0 * t); + + float v0 = (2.0 - t) / vw0 - 1.0; + float v1 = t / vw1 + 1.0; + + visibility += uw0 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw0 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility /= 16.0; +#endif +#ifdef SHADOW_FILTER_5x5 + float uw0 = (4.0 - 3.0 * s); + float uw1 = 7.0; + float uw2 = (1.0 + 3.0 * s); + + float u0 = (3.0 - 2.0 * s) / uw0 - 2.0; + float u1 = (3.0 + s) / uw1; + float u2 = s / uw2 + 2.0; + + float vw0 = (4.0 - 3.0 * t); + float vw1 = 7.0; + float vw2 = (1.0 + 3.0 * t); + + float v0 = (3.0 - 2.0 * t) / vw0 - 2.0; + float v1 = (3.0 + t) / vw1; + float v2 = t / vw2 + 2.0; + + visibility += uw0 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw2 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility += uw0 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw2 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility += uw0 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw2 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility /= 144.0; +#endif +#ifdef SHADOW_FILTER_7x7 + float uw0 = (5.0 * s - 6.0); + float uw1 = (11.0 * s - 28.0); + float uw2 = -(11.0 * s + 17.0); + float uw3 = -(5.0 * s + 1.0); + + float u0 = (4.0 * s - 5.0) / uw0 - 3.0; + float u1 = (4.0 * s - 16.0) / uw1 - 1.0; + float u2 = -(7.0 * s + 5.0) / uw2 + 1.0; + float u3 = -s / uw3 + 3.0; + + float vw0 = (5.0 * t - 6.0); + float vw1 = (11.0 * t - 28.0); + float vw2 = -(11.0 * t + 17.0); + float vw3 = -(5.0 * t + 1.0); + + float v0 = (4.0 * t - 5.0) / vw0 - 3.0; + float v1 = (4.0 * t - 16.0) / vw1 - 1.0; + float v2 = -(7.0 * t + 5.0) / vw2 + 1.0; + float v3 = -t / vw3 + 3.0; + + visibility += uw0 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw2 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw3 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility += uw0 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw2 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw3 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility += uw0 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw2 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw3 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility += uw0 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw1 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw2 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); + visibility += uw3 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); + + visibility /= 2704.0; +#endif + +#ifdef SHADOW_FILTER_VOGEL + vec2 texelSize = vec2(shadow.cascades[int(cascadeIndex)].texelSize); + for (int i = 0; i < 16; i++) { + visibility += offsetLookup(cascadeMaps, shadowSampler, uv, float(cascadeIndex), shadow.edgeSoftness, texelSize, resInv, position, i, shadowCoords.z, bias); + } + + visibility /= 16.0; +#endif + + // Fade out shadow in the distance + return clamp(visibility + fadeout, 0.0, 1.0); + +} + +float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 fragmentPosition, vec3 normal, float cosTheta) { + + // Note: The code below is actually the fastest code on every platform tested + // Some platforms have problems directly indexing the cascade array. + // We allow 6 cascades +#ifdef SHADOW_CASCADE_BLENDING + float distance = -fragmentPosition.z - shadow.cascadeBlendDistance; +#else + float distance = -fragmentPosition.z; +#endif + int cascadeIndex = 0; + cascadeIndex = distance >= shadow.cascades[0].distance ? 1 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[1].distance ? 2 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[2].distance ? 3 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[3].distance ? 4 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[4].distance ? 5 : cascadeIndex; + cascadeIndex = min(shadow.cascadeCount - 1, cascadeIndex); + + mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; + + float texelSize = shadow.cascades[0].texelSize; + texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; + texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; + texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; + texelSize = cascadeIndex > 3 ? shadow.cascades[4].texelSize : texelSize; + texelSize = cascadeIndex > 4 ? shadow.cascades[5].texelSize : texelSize; + + vec3 bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5); + fragmentPosition += bias; + + float visibility = cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), + cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true); + +#ifdef SHADOW_CASCADE_BLENDING + if (cascadeIndex < shadow.cascadeCount - 1) { + + float cascadeDistance = shadow.cascades[0].distance; + cascadeDistance = cascadeIndex > 0 ? shadow.cascades[1].distance : cascadeDistance; + cascadeDistance = cascadeIndex > 1 ? shadow.cascades[2].distance : cascadeDistance; + cascadeDistance = cascadeIndex > 2 ? shadow.cascades[3].distance : cascadeDistance; + cascadeDistance = cascadeIndex > 3 ? shadow.cascades[4].distance : cascadeDistance; + + float blend = (cascadeDistance - distance) + / shadow.cascadeBlendDistance; + blend = clamp(blend, 0.0, 1.0); + + if (blend <= 1.0) { + + cascadeIndex += 1; + fragmentPosition -= bias; + + mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; + + float texelSize = shadow.cascades[0].texelSize; + texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; + texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; + texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; + texelSize = cascadeIndex > 3 ? shadow.cascades[4].texelSize : texelSize; + texelSize = cascadeIndex > 4 ? shadow.cascades[5].texelSize : texelSize; + + bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5); + fragmentPosition += bias; + + visibility = mix(cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), + cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true), visibility, blend); + } + } +#endif + + return visibility; +} + +float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, + vec3 fragmentPosition, vec3 position, vec3 normal, float cosTheta) { + + // Note: The code below is actually the fastest code on every platform tested + // Some platforms have problems directly indexing the cascade array. + // We allow 6 cascades +#ifdef SHADOW_CASCADE_BLENDING + float distance = -fragmentPosition.z - shadow.cascadeBlendDistance; +#else + float distance = -fragmentPosition.z; +#endif + int cascadeIndex = 0; + cascadeIndex = distance >= shadow.cascades[0].distance ? 1 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[1].distance ? 2 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[2].distance ? 3 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[3].distance ? 4 : cascadeIndex; + cascadeIndex = distance >= shadow.cascades[4].distance ? 5 : cascadeIndex; + cascadeIndex = min(shadow.cascadeCount - 1, cascadeIndex); + + mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; + + float texelSize = shadow.cascades[0].texelSize; + texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; + texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; + texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; + texelSize = cascadeIndex > 3 ? shadow.cascades[4].texelSize : texelSize; + texelSize = cascadeIndex > 4 ? shadow.cascades[5].texelSize : texelSize; + + vec3 bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5); + fragmentPosition += bias; + + float visibility = cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), + cascadeMatrix, fragmentPosition, position, 0.0, true); + +#ifdef SHADOW_CASCADE_BLENDING + if (cascadeIndex < shadow.cascadeCount - 1) { + + float cascadeDistance = shadow.cascades[0].distance; + cascadeDistance = cascadeIndex > 0 ? shadow.cascades[1].distance : cascadeDistance; + cascadeDistance = cascadeIndex > 1 ? shadow.cascades[2].distance : cascadeDistance; + cascadeDistance = cascadeIndex > 2 ? shadow.cascades[3].distance : cascadeDistance; + cascadeDistance = cascadeIndex > 3 ? shadow.cascades[4].distance : cascadeDistance; + + float blend = (cascadeDistance - distance) + / shadow.cascadeBlendDistance; + blend = clamp(blend, 0.0, 1.0); + + if (blend <= 1.0) { + + cascadeIndex += 1; + fragmentPosition -= bias; + + mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; + + float texelSize = shadow.cascades[0].texelSize; + texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; + texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; + texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; + texelSize = cascadeIndex > 3 ? shadow.cascades[4].texelSize : texelSize; + texelSize = cascadeIndex > 4 ? shadow.cascades[5].texelSize : texelSize; + + bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5); + fragmentPosition += bias; + + visibility = mix(cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), + cascadeMatrix, fragmentPosition, position, 0.0, true), visibility, blend); + } + } +#endif + + return visibility; +} + +float CalculateShadowWorldSpace(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 position, vec3 normal, float cosTheta) { + mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + float texelSize = shadow.cascades[0].texelSize; + + vec3 bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5); + position += bias; + + return cascadeLookup(shadow, cascadeMaps, shadowSampler, 0.0, + cascadeMatrix, position, position, 0.0, false); } \ No newline at end of file diff --git a/data/shader/structures.hsh b/data/shader/structures.hsh index b1a1234e5..3b746981d 100644 --- a/data/shader/structures.hsh +++ b/data/shader/structures.hsh @@ -1,5 +1,8 @@ #include +#define DIRECTIONAL_LIGHT 0 +#define POINT_LIGHT 1 + //Light struct has to be implemented like this struct Light { @@ -12,7 +15,7 @@ struct Light { float scatteringFactor; float radius; - float alignment; + float attenuation; Shadow shadow; @@ -26,4 +29,8 @@ struct CloudShadow { mat4 ivMatrix; mat4 ipMatrix; +}; + +layout (std430, set = 1, binding = 16) buffer Lights { + Light lights[]; }; \ No newline at end of file diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 8b22c8185..c3559c8a9 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -52,7 +52,7 @@ namespace Atlas { #ifdef AE_BUILDTYPE_DEBUG .enableValidationLayers = true, #else - .enableValidationLayers = false, + .enableValidationLayers = true, #endif .validationLayerSeverity = config.validationLayerSeverity, #ifndef AE_HEADLESS diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index e0afa978a..3d0d4bc83 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -27,7 +27,8 @@ namespace Atlas { } - void DirectLightRenderer::Render(Ref target, Ref scene, Graphics::CommandList* commandList) { + void DirectLightRenderer::Render(Ref target, Ref scene, + Helper::LightData& lightData, Graphics::CommandList* commandList) { auto mainLightEntity = GetMainLightEntity(scene); if (!mainLightEntity.IsValid()) return; @@ -39,74 +40,45 @@ namespace Atlas { auto sss = scene->sss; auto clouds = scene->sky.clouds; - vec3 direction = normalize(vec3(camera.viewMatrix * - vec4(light.transformedProperties.directional.direction, 0.0f))); + std::vector> cascadeMaps; + std::vector> cubeMaps; Uniforms uniforms; - - auto& lightUniform = uniforms.light; - lightUniform.location = vec4(0.0f); - lightUniform.direction = vec4(direction, 0.0f); - lightUniform.color = vec4(Common::ColorConverter::ConvertSRGBToLinear(light.color), 0.0f); - lightUniform.intensity = light.intensity; - lightUniform.scatteringFactor = 1.0f; - lightUniform.radius = 1.0f; - - if (light.shadow) { - auto shadow = light.shadow; - auto& shadowUniform = lightUniform.shadow; - shadowUniform.distance = !shadow->longRange ? shadow->distance : shadow->longRangeDistance; - shadowUniform.bias = shadow->bias; - shadowUniform.edgeSoftness = shadow->edgeSoftness; - shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; - shadowUniform.cascadeCount = shadow->viewCount; - shadowUniform.resolution = vec2(shadow->resolution); - - if (shadow->useCubemap) { - commandList->BindImage(shadow->cubemap->image, shadowSampler, 3, 1); - } - else { - commandList->BindImage(shadow->maps->image, shadowSampler, 3, 1); - } - - auto componentCount = shadow->viewCount; - for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { - if (i < componentCount) { - auto cascade = &shadow->views[i]; - auto frustum = Volume::Frustum(cascade->frustumMatrix); - auto corners = frustum.GetCorners(); - auto texelSize = glm::max(abs(corners[0].x - corners[1].x), - abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; - shadowUniform.cascades[i].distance = cascade->farDistance; - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix; - shadowUniform.cascades[i].texelSize = texelSize; + uniforms.lightCount = std::min(8, int32_t(lightData.lightEntities.size())); + for (int32_t i = 0; i < uniforms.lightCount; i++) { + auto& comp = lightData.lightEntities[i].comp; + + if (comp.shadow) { + auto& shadow = comp.shadow; + if (shadow->useCubemap) { + uniforms.mapIndices[i] = int32_t(cubeMaps.size()); + cubeMaps.push_back(shadow->cubemap->image); } else { - auto cascade = &shadow->views[componentCount - 1]; - shadowUniform.cascades[i].distance = cascade->farDistance; + uniforms.mapIndices[i] = int32_t(cascadeMaps.size()); + cascadeMaps.push_back(shadow->maps->image); } } } - uniformBuffer.SetData(&uniforms, 0); + commandList->BindSampledImages(cascadeMaps, 3, 6); + commandList->BindSampledImages(cubeMaps, 3, 14); - pipelineConfig.ManageMacro("SHADOWS", light.shadow != nullptr); pipelineConfig.ManageMacro("SCREEN_SPACE_SHADOWS", sss && sss->enable); pipelineConfig.ManageMacro("CLOUD_SHADOWS", clouds && clouds->enable && clouds->castShadow); auto pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); commandList->BindImage(target->lightingTexture.image, 3, 0); - uniformBuffer.Bind(commandList, 3, 4); + uniformBuffer.Bind(commandList, 3, 3); if (sss && sss->enable) { - commandList->BindImage(target->sssTexture.image, target->sssTexture.sampler, 3, 2); + commandList->BindImage(target->sssTexture.image, target->sssTexture.sampler, 3, 1); } CloudShadow cloudShadowUniform; if (clouds && clouds->enable && clouds->castShadow) { - clouds->shadowTexture.Bind(commandList, 3, 3); + clouds->shadowTexture.Bind(commandList, 3, 2); clouds->GetShadowMatrices(camera, glm::normalize(light.transformedProperties.directional.direction), cloudShadowUniform.vMatrix, cloudShadowUniform.pMatrix); @@ -118,7 +90,9 @@ namespace Atlas { } cloudShadowUniformBuffer.SetData(&cloudShadowUniform, 0); - cloudShadowUniformBuffer.Bind(commandList, 3, 5); + cloudShadowUniformBuffer.Bind(commandList, 3, 4); + + commandList->BindSampler(shadowSampler, 3, 5); ivec2 res = ivec2(target->GetScaledWidth(), target->GetScaledHeight()); int32_t groupSize = 8; diff --git a/src/engine/renderer/DirectLightRenderer.h b/src/engine/renderer/DirectLightRenderer.h index dab537b2e..696c7f9dd 100644 --- a/src/engine/renderer/DirectLightRenderer.h +++ b/src/engine/renderer/DirectLightRenderer.h @@ -1,6 +1,7 @@ #pragma once #include "Renderer.h" +#include "helper/LightData.h" namespace Atlas { @@ -13,11 +14,13 @@ namespace Atlas { void Init(Graphics::GraphicsDevice* device); - void Render(Ref target, Ref scene, Graphics::CommandList* commandList); + void Render(Ref target, Ref scene, + Helper::LightData& lightData, Graphics::CommandList* commandList); private: struct alignas(16) Uniforms { - Light light; + int32_t mapIndices[16]; + int32_t lightCount; }; PipelineConfig pipelineConfig; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index b847229ae..cc727a33d 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -5,7 +5,6 @@ #include "../common/Packing.h" #include "../tools/PerformanceCounter.h" #include "../Clock.h" -#include #define FEATURE_BASE_COLOR_MAP (1 << 1) #define FEATURE_OPACITY_MAP (1 << 2) @@ -113,6 +112,8 @@ namespace Atlas { JobGroup fillRenderListGroup { JobPriority::High }; JobSystem::Execute(fillRenderListGroup, [&](JobData&) { FillRenderList(scene, camera); }); + lightData.CullAndSort(scene); + Ref materialBuffer; std::vector materials; std::unordered_map materialMap; @@ -173,6 +174,7 @@ namespace Atlas { // Wait as long as possible for this to finish JobSystem::WaitSpin(prepareBindlessGroup); + lightData.UpdateBindlessIndices(scene); commandList->BindBuffers(triangleBuffers, 0, 1); if (images.size()) commandList->BindSampledImages(images, 0, 3); @@ -222,6 +224,8 @@ namespace Atlas { JobSystem::WaitSpin(scene->rayTracingWorldUpdateJob); + lightData.lightBuffer.Bind(commandList, 1, 16); + ddgiRenderer.TraceAndUpdateProbes(scene, commandList); // Only here does the main pass need to be ready @@ -338,7 +342,7 @@ namespace Atlas { commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - directLightRenderer.Render(target, scene, commandList); + directLightRenderer.Render(target, scene, lightData, commandList); if (!scene->rtgi || !scene->rtgi->enable || !scene->IsRtDataValid()) { commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, @@ -1072,50 +1076,6 @@ namespace Atlas { impostor->impostorInfoBuffer.SetData(&impostorInfo, 0); } - - std::vector lightComponents; - auto lightSubset = scene->GetSubset(); - for (auto& lightEntity : lightSubset) { - auto& light = lightEntity.GetComponent(); - lightComponents.emplace_back(light); - } - - std::sort(lightComponents.begin(), lightComponents.end(), - [&](const LightComponent& light0, const LightComponent& light1) { - if (light0.isMain) - return true; - - if (light0.type == LightType::DirectionalLight) - return true; - - if (light0.type == LightType::PointLight && - light1.type == LightType::PointLight) { - return glm::distance2(light0.transformedProperties.point.position, camera.GetLocation()) - < glm::distance2(light1.transformedProperties.point.position, camera.GetLocation()); - } - - return false; - }); - - std::vector lights; - for (const auto& comp : lightComponents) { - Light light { - .color = vec4(Common::ColorConverter::ConvertSRGBToLinear(comp.color), 0.0f), - .intensity = comp.intensity, - .scatteringFactor = 1.0f, - }; - - const auto& prop = comp.transformedProperties; - if (comp.type == LightType::DirectionalLight) { - light.direction = vec4(prop.directional.direction, 0.0f); - } - else if (comp.type == LightType::PointLight) { - light.location = vec4(prop.point.position, 1.0f); - light.radius = prop.point.radius; - light.attenuation = prop.point.attenuation; - } - } - } void MainRenderer::PrepareMaterials(Ref scene, std::vector& materials, diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index dfaa3d458..f363dbabc 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -4,6 +4,7 @@ #include "../graphics/GraphicsDevice.h" #include "PrimitiveBatch.h" +#include "helper/LightData.h" #include "OpaqueRenderer.h" #include "ImpostorRenderer.h" @@ -128,6 +129,7 @@ namespace Atlas { FSR2Renderer fsr2Renderer; RenderList renderList; + Helper::LightData lightData; std::vector haltonSequence; size_t haltonIndex = 0; diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index 088ab0333..1350235e4 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -23,7 +23,7 @@ namespace Atlas { int cascadeCount; - float mapIdx; + int32_t mapIdx; vec2 resolution; diff --git a/src/engine/renderer/helper/LightData.cpp b/src/engine/renderer/helper/LightData.cpp index 173e8a5cb..71578d61f 100644 --- a/src/engine/renderer/helper/LightData.cpp +++ b/src/engine/renderer/helper/LightData.cpp @@ -1,7 +1,120 @@ #include "LightData.h" +#include "CommonStructures.h" + +#include "common/ColorConverter.h" +#include namespace Atlas::Renderer::Helper { + void LightData::CullAndSort(const Ref& scene) { + + auto& camera = scene->GetMainCamera(); + + lightEntities.clear(); + auto lightSubset = scene->GetSubset(); + for (auto& lightEntity : lightSubset) { + auto& light = lightEntity.GetComponent(); + lightEntities.emplace_back(LightEntity { lightEntity, light, -1 }); + } + + if (lightEntities.size() <= 1) + return; + + std::sort(lightEntities.begin(), lightEntities.end(), + [&](const LightEntity& light0, const LightEntity& light1) { + if (light0.comp.isMain) + return true; + + if (light0.comp.type == LightType::DirectionalLight) + return true; + + if (light0.comp.type == LightType::PointLight && + light1.comp.type == LightType::PointLight) { + return glm::distance2(light0.comp.transformedProperties.point.position, camera.GetLocation()) + < glm::distance2(light1.comp.transformedProperties.point.position, camera.GetLocation()); + } + + return false; + }); + + } + + void LightData::UpdateBindlessIndices(const Ref& scene) { + + + + } + + void LightData::FillBuffer(const Ref& scene) { + + auto& camera = scene->GetMainCamera(); + + std::vector lights; + lights.reserve(lightEntities.size()); + for (const auto& entity : lightEntities) { + auto& light = entity.comp; + + auto type = static_cast(light.type); + auto packedType = reinterpret_cast(type); + Light lightUniform { + .color = vec4(Common::ColorConverter::ConvertSRGBToLinear(light.color), packedType), + .intensity = light.intensity, + .scatteringFactor = 1.0f, + }; + + const auto& prop = light.transformedProperties; + if (light.type == LightType::DirectionalLight) { + lightUniform.direction = camera.viewMatrix * vec4(prop.directional.direction, 0.0f); + } + else if (light.type == LightType::PointLight) { + lightUniform.location = camera.viewMatrix * vec4(prop.point.position, 1.0f); + lightUniform.radius = prop.point.radius; + lightUniform.attenuation = prop.point.attenuation; + } + + auto& shadowUniform = lightUniform.shadow; + if (light.shadow) { + auto shadow = light.shadow; + auto& shadowUniform = lightUniform.shadow; + shadowUniform.distance = !shadow->longRange ? shadow->distance : shadow->longRangeDistance; + shadowUniform.bias = shadow->bias; + shadowUniform.edgeSoftness = shadow->edgeSoftness; + shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; + shadowUniform.cascadeCount = shadow->viewCount; + shadowUniform.resolution = vec2(shadow->resolution); + shadowUniform.mapIdx = entity.mapIdx; + + auto componentCount = shadow->viewCount; + for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { + if (i < componentCount) { + auto cascade = &shadow->views[i]; + auto frustum = Volume::Frustum(cascade->frustumMatrix); + auto corners = frustum.GetCorners(); + auto texelSize = glm::max(abs(corners[0].x - corners[1].x), + abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; + shadowUniform.cascades[i].distance = cascade->farDistance; + shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * + cascade->viewMatrix * camera.invViewMatrix; + shadowUniform.cascades[i].texelSize = texelSize; + } + else { + auto cascade = &shadow->views[componentCount - 1]; + shadowUniform.cascades[i].distance = cascade->farDistance; + } + } + } + + lights.emplace_back(std::move(lightUniform)); + } + + if (lightBuffer.GetElementCount() < lightEntities.size()) { + lightBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit + | Buffer::BufferUsageBits::UniformBufferBit, sizeof(Light), lightEntities.size(), lights.data()); + } + else { + lightBuffer.SetData(lights.data(), 0, lights.size()); + } + } } \ No newline at end of file diff --git a/src/engine/renderer/helper/LightData.h b/src/engine/renderer/helper/LightData.h index 70cb5ccf6..80eacbf9b 100644 --- a/src/engine/renderer/helper/LightData.h +++ b/src/engine/renderer/helper/LightData.h @@ -4,17 +4,30 @@ #include +#include "scene/Scene.h" + namespace Atlas::Renderer::Helper { class LightData { public: + struct LightEntity { + Scene::Entity entity; + LightComponent comp; + int32_t mapIdx = -1; + }; + LightData() = default; - private: - struct Light { + void CullAndSort(const Ref& scene); - }; + void UpdateBindlessIndices(const Ref& scene); + + void FillBuffer(const Ref& scene); + + Buffer::Buffer lightBuffer; + + std::vector lightEntities; }; From f14eb6a30572f37bf622e9ac9a93f5c714b69af8 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 18 Aug 2024 22:47:15 +0200 Subject: [PATCH 03/66] More changes --- data/scenes/sponza.aescene | 2 +- data/shader/deferred/direct.csh | 44 ++++++++++++++----- data/shader/deferred/point.fsh | 2 +- src/engine/renderer/DirectLightRenderer.cpp | 19 +++----- src/engine/renderer/DirectLightRenderer.h | 8 ++-- src/engine/renderer/MainRenderer.cpp | 1 + src/engine/renderer/helper/LightData.cpp | 16 +++++-- .../scene/components/LightComponent.cpp | 7 ++- 8 files changed, 67 insertions(+), 32 deletions(-) diff --git a/data/scenes/sponza.aescene b/data/scenes/sponza.aescene index 80a1641a0..9203f2724 100644 --- a/data/scenes/sponza.aescene +++ b/data/scenes/sponza.aescene @@ -1 +1 @@ -{"aabb":{"max":{"x":128.0,"y":128.0,"z":128.0},"min":{"x":-128.0,"y":-128.0,"z":-128.0}},"ao":{"enable":false,"halfResolution":true,"opacityCheck":false,"radius":3.0,"rt":true,"sampleCount":16,"strength":1.0},"depth":5.0,"entities":[{"entities":[{"id":1,"light":{"color":{"x":1.0,"y":0.9254902005195618,"z":0.8196078538894653},"intensity":10.0,"isMain":true,"mobility":0,"properties":{"direction":{"x":0.0,"y":-1.0,"z":0.2800000011920929}},"shadow":{"allowDynamicEntities":false,"allowTerrain":true,"bias":0.800000011920929,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":75.0,"edgeSoftness":0.05000000074505806,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":2048,"splitCorrection":0.0,"useCubemap":false,"viewCount":1,"views":[{"farDistance":75.0,"frustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"nearDistance":0.0,"orthoSize":{"w":43.0,"x":-50.0,"y":50.0,"z":-41.0},"projectionMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.26962992548942566,"z":0.9629640579223633},"j2":{"w":0.0,"x":0.0,"y":0.9629640579223633,"z":-0.26962992548942566},"j3":{"w":1.0,"x":-0.0,"y":-0.0,"z":0.0}}}]},"type":0,"volumetric":true},"name":{"name":"Directional light"}},{"id":2,"mesh":{"dontCull":false,"resourcePath":"sponza/meshes/sponza.aemesh","visible":true},"name":{"name":"Sponza"},"rigidBody":{"bodyIndex":0,"creationSettings":{"angularDampening":0.0,"linearDampening":0.0,"shape":{"meshSettings":{"resourcePath":"sponza/meshes/sponza.aemesh","scale":{"x":0.012193998321890831,"y":0.012000000104308128,"z":0.012193998321890831}}}},"layer":0},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.012193998321890831,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":0.012000000104308128,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":0.012193998321890831},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}}}},{"id":3,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":1,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.000000238418579,"y":1.000000238418579,"z":1.000000238418579}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.4756948947906494,"y":0.00011953715875279158,"z":-0.8796106576919556},"j1":{"w":0.0,"x":0.5917145013809204,"y":-0.739871621131897,"z":-0.32010072469711304},"j2":{"w":0.0,"x":-0.6508373022079468,"y":-0.6727486252784729,"z":0.3518824875354767},"j3":{"w":1.0,"x":-15.995047569274902,"y":0.9694054126739502,"z":0.2113814800977707}}}},{"id":4,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Wall"},"rigidBody":{"bodyIndex":2,"creationSettings":{"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":1.0,"scale":{"x":0.1481112539768219,"y":0.17914418876171112,"z":2.874448299407959}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.12404608726501465,"y":-7.875383403188607e-07,"z":0.08092907071113586},"j1":{"w":0.0,"x":-6.167340416141087e-07,"y":0.17914418876171112,"z":2.688605945877498e-06},"j2":{"w":0.0,"x":-1.5706194639205933,"y":-4.1537619836162776e-05,"z":2.407406806945801},"j3":{"w":1.0,"x":7.4162163734436035,"y":-0.04500603675842285,"z":-0.9572893381118774}}}},{"id":5,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":3,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.9999986290931702,"y":0.9999986290931702,"z":0.9999986290931702}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.30071619153022766,"y":0.9535101652145386,"z":0.01963132992386818},"j1":{"w":0.0,"x":-0.02151578664779663,"y":-0.013796210289001465,"z":0.9996733665466309},"j2":{"w":0.0,"x":0.9534696936607361,"y":-0.3010404407978058,"z":0.016366761177778244},"j3":{"w":1.0,"x":4.233027935028076,"y":0.966492235660553,"z":1.2846850156784058}}}},{"id":6,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":4,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0475580133497715,"y":-8.188627589333919e-07,"z":0.06712339073419571},"j1":{"w":0.0,"x":-3.60343005922914e-06,"y":-0.1039920523762703,"z":1.2844517414123402e-06},"j2":{"w":0.0,"x":0.8159534335136414,"y":-3.541418118402362e-05,"z":-0.5781162977218628},"j3":{"w":1.0,"x":-9.601022720336914,"y":1.530970811843872,"z":-0.44825008511543274}}}},{"camera":{"aspectRatio":2.0,"exposure":1.0,"farPlane":400.0,"fieldOfView":55.20000076293945,"isMain":true,"location":{"x":0.0,"y":1.2000000476837158,"z":0.0},"nearPlane":1.0,"rotation":{"x":51.511505126953125,"y":0.15597067773342133},"thirdPerson":true,"thirdPersonDistance":3.0,"useEntityRotation":true,"useEntityTranslation":true},"id":7,"mesh":{"dontCull":false,"resourcePath":"meshes/capsule.aemesh","visible":true},"name":{"name":"Player"},"player":{"allowInput":true,"creationSettings":{"shape":{"capsuleShapeSettings":{"density":1.0,"height":1.2000000476837158,"radius":0.30000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"fastVelocity":4.0,"jumpVelocity":4.0,"slowVelocity":1.600000023841858},"text":{"halfSize":{"x":0.5,"y":1.0},"outlineColor":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"outlineFactor":0.0,"position":{"x":0.0,"y":1.600000023841858,"z":0.0},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"This is the player","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.07999999821186066},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-10.923478126525879,"y":-0.030071211978793144,"z":-1.5454801321029663}}}},{"audio":{"cutoff":0.0010000000474974513,"falloffFactor":0.10000000149011612,"falloffPower":2.0,"permanentPlay":false,"stream":{"loop":false,"pitch":1.0,"resourcePath":"/music.wav","time":0.0,"volume":0.0},"volume":1.0},"id":8,"name":{"name":"WelcomeText"},"text":{"halfSize":{"x":1.899999976158142,"y":1.0},"outlineColor":{"w":1.0,"x":1.0,"y":0.0,"z":0.0},"outlineFactor":0.15000000596046448,"position":{"x":0.0,"y":0.0,"z":1.2999999523162842},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"Welcome to this demo scene!","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.1899999976158142},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.01578390598297119,"y":0.00355260306969285,"z":0.9998670816421509},"j1":{"w":0.0,"x":0.40691956877708435,"y":0.9134560227394104,"z":0.003178075887262821},"j2":{"w":0.0,"x":-0.913324773311615,"y":0.4069172441959381,"z":-0.015863558277487755},"j3":{"w":1.0,"x":2.9802322387695313e-08,"y":4.168000221252441,"z":-0.02871951460838318}}}},{"entities":[{"id":10,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":5,"creationSettings":{"angularVelocity":{"x":0.3400594890117645,"y":0.002075438853353262,"z":-0.2711464762687683},"linearVelocity":{"x":0.027797559276223183,"y":-0.06926704198122025,"z":0.03678030148148537},"motionQuality":1,"objectLayer":1,"restitution":-0.0,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226305991411209,"y":0.10399112105369568,"z":0.24259740114212036}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.06749320030212402,"y":-0.0013515298487618566,"z":0.04701119661331177},"j1":{"w":0.0,"x":-0.05943548306822777,"y":-5.547449109144509e-05,"z":-0.08533213287591934},"j2":{"w":0.0,"x":0.003344531636685133,"y":-0.2425646185874939,"z":-0.0021718384232372046},"j3":{"w":1.0,"x":-6.993166923522949,"y":0.07752954214811325,"z":-0.49586528539657593}}}},{"id":11,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":6,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226487040519714,"y":0.10399449616670609,"z":1.000009298324585}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.001214503077790141,"y":4.0089940739562735e-05,"z":0.08225589245557785},"j1":{"w":0.0,"x":-0.10398011654615402,"y":-0.000795417174231261,"z":0.0015356455696746707},"j2":{"w":0.0,"x":0.0076551553793251514,"y":-0.9999799728393555,"z":0.00037435046397149563},"j3":{"w":1.0,"x":-0.18109244108200073,"y":1.1424553394317627,"z":-2.4032680988311768}}}},{"id":12,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":7,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399213433265686,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004975396674126387,"y":-3.6774740692635532e-06,"z":0.0821131020784378},"j1":{"w":0.0,"x":-0.10380175709724426,"y":-6.8306521825434174e-06,"z":-0.006289551965892315},"j2":{"w":0.0,"x":6.824726733611897e-05,"y":-0.9999992847442627,"z":-4.065033863298595e-05},"j3":{"w":1.0,"x":0.49817052483558655,"y":0.3519432246685028,"z":-2.3503992557525635}}}},{"id":13,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":8,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.10399220138788223,"z":0.9999990463256836}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006919844541698694,"y":0.0009341590339317918,"z":0.08196679502725601},"j1":{"w":0.0,"x":-0.10362283140420914,"y":-0.00030928864725865424,"z":0.008751623332500458},"j2":{"w":0.0,"x":0.003919091075658798,"y":-0.9999301433563232,"z":0.011065145023167133},"j3":{"w":1.0,"x":2.0737833976745605,"y":0.3635621964931488,"z":-1.7112125158309937}}}},{"id":14,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":9,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.10399205982685089,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.00037123600486665964,"y":-0.00020935118664056063,"z":0.08226258307695389},"j1":{"w":0.0,"x":-0.10399100184440613,"y":-7.686027743147861e-07,"z":0.000469290855107829},"j2":{"w":0.0,"x":-4.082914983882802e-06,"y":-0.9999959468841553,"z":-0.0025448778178542852},"j3":{"w":1.0,"x":3.7019379138946533,"y":0.35346531867980957,"z":-2.4043333530426025}}}},{"id":15,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":10,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.0822637677192688,"y":0.10399221628904343,"z":1.0000003576278687}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0014320656191557646,"y":-0.005514409858733416,"z":0.08206624537706375},"j1":{"w":0.0,"x":-0.1039608046412468,"y":-0.0019218007801100612,"z":0.0016850243555381894},"j2":{"w":0.0,"x":0.01734951324760914,"y":-0.9975799322128296,"z":-0.06733495742082596},"j3":{"w":1.0,"x":1.3664464950561523,"y":1.2094060182571411,"z":-2.3293323516845703}}}},{"id":16,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":11,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007250844966620207,"y":-0.00029188839835114777,"z":0.08194299042224884},"j1":{"w":0.0,"x":-0.10357026010751724,"y":0.0019194179913029075,"z":-0.009157725609838963},"j2":{"w":0.0,"x":-0.01807291805744171,"y":-0.9998225569725037,"z":-0.005160685162991285},"j3":{"w":1.0,"x":3.177853584289551,"y":1.137428641319275,"z":-2.286043643951416}}}},{"id":17,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":12,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999994039535522}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007074753753840923,"y":-0.0009124425705522299,"z":0.08195383846759796},"j1":{"w":0.0,"x":-0.10360674560070038,"y":2.178741397074191e-06,"z":-0.008943937718868256},"j2":{"w":0.0,"x":0.0009330803295597434,"y":-0.999937891960144,"z":-0.01105236355215311},"j3":{"w":1.0,"x":4.739034652709961,"y":1.1431937217712402,"z":-2.344177484512329}}}},{"id":18,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":13,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-2.9814507797709666e-05,"y":-0.00011468570301076397,"z":0.08226361125707626},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-5.103151488583535e-05,"z":-3.7763817090308294e-05},"j2":{"w":0.0,"x":0.0004912313306704164,"y":-0.9999982118606567,"z":-0.0013939131749793887},"j3":{"w":1.0,"x":5.269709587097168,"y":0.3537576496601105,"z":-2.396353006362915}}}},{"id":19,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":14,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226397633552551,"y":0.10399535298347473,"z":1.0000017881393433}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0029943662229925394,"y":-0.004902660381048918,"z":0.08206314593553543},"j1":{"w":0.0,"x":-0.1038932278752327,"y":-0.00239846995100379,"z":-0.0039341989904642105},"j2":{"w":0.0,"x":0.025261566042900085,"y":-0.9979578852653503,"z":-0.05869881808757782},"j3":{"w":1.0,"x":0.4539576470851898,"y":1.9912066459655762,"z":-2.3605332374572754}}}},{"id":20,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":15,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999991059303284}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0047220797277987,"y":-0.006254853215068579,"z":0.08188952505588531},"j1":{"w":0.0,"x":-0.10381996631622314,"y":0.000815314007923007,"z":-0.005924399942159653},"j2":{"w":0.0,"x":-0.0034728916361927986,"y":-0.9970735311508179,"z":-0.0763583704829216},"j3":{"w":1.0,"x":2.0099921226501465,"y":1.9823397397994995,"z":-2.1112253665924072}}}},{"id":21,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":16,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0015184117946773767,"y":-0.001873633824288845,"z":0.08222834020853043},"j1":{"w":0.0,"x":-0.10390593856573105,"y":0.0038146909791976213,"z":-0.0018317853100597858},"j2":{"w":0.0,"x":-0.036265525966882706,"y":-0.9990666508674622,"z":-0.02343420498073101},"j3":{"w":1.0,"x":3.611302614212036,"y":1.9326788187026978,"z":-2.369572162628174}}}},{"id":22,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":17,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370811462402,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0011607652995735407,"y":-0.005252636969089508,"z":0.08208763599395752},"j1":{"w":0.0,"x":-0.1039327085018158,"y":-0.003092399565503001,"z":-0.0016675429651513696},"j2":{"w":0.0,"x":0.03069702349603176,"y":-0.9975154995918274,"z":-0.06339509040117264},"j3":{"w":1.0,"x":0.911769449710846,"y":2.8139381408691406,"z":-2.3714351654052734}}}},{"id":23,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":18,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399208217859268,"z":0.9999986886978149}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.002328230533748865,"y":-0.01567736454308033,"z":0.08072245121002197},"j1":{"w":0.0,"x":-0.10387608408927917,"y":0.0032992407213896513,"z":0.0036367876455187798},"j2":{"w":0.0,"x":-0.03779618442058563,"y":-0.9811586737632751,"z":-0.189463809132576},"j3":{"w":1.0,"x":2.5983128547668457,"y":2.8227591514587402,"z":-2.0519001483917236}}}},{"id":24,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":19,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920449256897,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006420230958610773,"y":-0.0025190962478518486,"z":0.0819740742444992},"j1":{"w":0.0,"x":-0.10356941819190979,"y":0.004437707830220461,"z":0.008247951045632362},"j2":{"w":0.0,"x":-0.04495199769735336,"y":-0.9986188411712646,"z":-0.027167268097400665},"j3":{"w":1.0,"x":4.155186176300049,"y":2.7027957439422607,"z":-2.4178249835968018}}}},{"id":25,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":20,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999993443489075}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007614439819008112,"y":-0.014711390249431133,"z":0.08057859539985657},"j1":{"w":0.0,"x":-0.1032203733921051,"y":-0.006378653459250927,"z":-0.010918588377535343},"j2":{"w":0.0,"x":0.07885781675577164,"y":-0.9819651246070862,"z":-0.17182737588882446},"j3":{"w":1.0,"x":1.3723328113555908,"y":3.7512500286102295,"z":-2.243227481842041}}}},{"id":26,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":21,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.005531982518732548,"y":-0.015606719069182873,"z":0.08058004826307297},"j1":{"w":0.0,"x":-0.10365156084299088,"y":0.005922866519540548,"z":-0.005968747194856405},"j2":{"w":0.0,"x":-0.0449003241956234,"y":-0.9801850318908691,"z":-0.19292448461055756},"j3":{"w":1.0,"x":3.1063742637634277,"y":3.642221689224243,"z":-2.205120325088501}}}},{"id":27,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":22,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399164259433746,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.009233793243765831,"y":-2.8461645484867404e-08,"z":-0.08174382150173187},"j1":{"w":0.0,"x":5.111483005748596e-07,"y":-0.10399164259433746,"z":-2.153150546746474e-08},"j2":{"w":0.0,"x":-0.9936796426773071,"y":-4.907456968794577e-06,"z":0.11224624514579773},"j3":{"w":1.0,"x":5.397507667541504,"y":1.5309886932373047,"z":-0.8703097105026245}}}},{"id":28,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":23,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.004304870497435331,"y":-0.016259904950857162,"z":0.08052577078342438},"j1":{"w":0.0,"x":-0.10374186187982559,"y":0.0035653808154165745,"z":0.006265922449529171},"j2":{"w":0.0,"x":-0.04547032341361046,"y":-0.9796709418296814,"z":-0.19538608193397522},"j3":{"w":1.0,"x":3.7071003913879395,"y":4.404808521270752,"z":-2.0641326904296875}}}},{"id":29,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":24,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226374536752701,"y":0.1039920300245285,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004521988797932863,"y":-0.014796562492847443,"z":0.08079565316438675},"j1":{"w":0.0,"x":-0.10348106175661087,"y":-0.007410035468637943,"z":-0.0071486919187009335},"j2":{"w":0.0,"x":0.0823487713932991,"y":-0.9811068177223206,"z":-0.17506666481494904},"j3":{"w":1.0,"x":1.740257740020752,"y":4.569649696350098,"z":-2.0765440464019775}}}},{"id":30,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":25,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"script":{"permanentExecution":false,"resourcePath":"scripts/example.lua","scriptProperties":{"duplicateEntityName":{"type":"string","value":""}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0822434350848198,"y":-3.559059393865027e-07,"z":-0.0018298403592780232},"j1":{"w":0.0,"x":6.938781211829337e-07,"y":0.1486254185438156,"z":2.2790266029915074e-06},"j2":{"w":0.0,"x":0.021798700094223022,"y":-1.5125399841053877e-05,"z":0.97975754737854},"j3":{"w":1.0,"x":-0.42584455013275146,"y":-0.042439818382263184,"z":0.7894344925880432}}}},{"id":31,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":26,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226378262042999,"y":0.015076023526489735,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.07320480048656464,"y":4.977956632501446e-05,"z":-0.03752845898270607},"j1":{"w":0.0,"x":0.006859811022877693,"y":-0.0011024783598259091,"z":0.013379612006247044},"j2":{"w":0.0,"x":-0.032167207449674606,"y":-0.9773759245872498,"z":-0.0640433058142662},"j3":{"w":1.0,"x":2.4300098419189453,"y":0.3631786108016968,"z":1.207587718963623}}}},{"id":32,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":27,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.06837532669305801,"y":-0.0017373006558045745,"z":-0.04570697247982025},"j1":{"w":0.0,"x":0.05685741454362869,"y":0.11100539565086365,"z":0.08083657920360565},"j2":{"w":0.0,"x":0.39542150497436523,"y":-0.6513306498527527,"z":0.6162874698638916},"j3":{"w":1.0,"x":3.135746955871582,"y":0.2095150351524353,"z":-1.027677297592163}}}},{"id":33,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":28,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000786781311}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0716107115149498,"y":-4.5638077494913887e-07,"z":-0.040487490594387054},"j1":{"w":0.0,"x":0.0005247447988949716,"y":0.14862160384655,"z":0.0009264472755603492},"j2":{"w":0.0,"x":0.4823108911514282,"y":-0.007020606193691492,"z":0.8530691862106323},"j3":{"w":1.0,"x":2.5021331310272217,"y":-0.04527640342712402,"z":0.6787291169166565}}}}],"id":9,"name":{"name":"Staircase"},"root":false},{"id":34,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":29,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-3.9226383705681656e-06,"y":0.0,"z":0.08226368576288223},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-2.479363736540563e-08,"z":-4.958727458870271e-06},"j2":{"w":0.0,"x":2.384183801495965e-07,"y":-0.9999991655349731,"z":0.0},"j3":{"w":1.0,"x":3.1176745891571045,"y":5.388330459594727,"z":-4.729436874389648}}}},{"entities":[{"entities":[{"id":37,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":32,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000007152557373,"y":1.0000007152557373,"z":1.0000007152557373}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.9554479122161865,"y":0.034463346004486084,"z":0.29313671588897705},"j1":{"w":0.0,"x":-0.09065454453229904,"y":0.9794178605079651,"z":0.18033018708229065},"j2":{"w":0.0,"x":-0.28088951110839844,"y":-0.19888851046562195,"z":0.9386930465698242},"j3":{"w":0.999999463558197,"x":-1.679502010345459,"y":-0.44969987869262695,"z":6.6491780281066895}}}}],"id":36,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":31,"creationSettings":{"angularVelocity":{"x":-0.003580757649615407,"y":-0.0010163785191252828,"z":-0.001152479788288474},"linearVelocity":{"x":0.0011589848436415195,"y":-0.276141881942749,"z":-0.003600968746468425},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000016689300537,"y":1.0000016689300537,"z":1.0000016689300537}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.7511749267578125,"y":0.22571837902069092,"z":-0.6203151345252991},"j1":{"w":0.0,"x":-0.39222919940948486,"y":0.6032152771949768,"z":0.6944692730903625},"j2":{"w":0.0,"x":0.5309374332427979,"y":0.7649720907211304,"z":-0.3645859360694885},"j3":{"w":1.0,"x":-11.712557792663574,"y":4.754024505615234,"z":-4.003259658813477}}}}],"id":35,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":30,"creationSettings":{"angularVelocity":{"x":0.16539807617664337,"y":0.1814352571964264,"z":-0.11671467125415802},"linearVelocity":{"x":0.11671468615531921,"y":2.4347741600649897e-09,"z":0.16539809107780457},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.6672989130020142,"y":0.0363946259021759,"z":0.7439002990722656},"j1":{"w":0.0,"x":0.5453938245773315,"y":0.7040697336196899,"z":0.45478731393814087},"j2":{"w":0.0,"x":-0.5072058439254761,"y":0.7091977000236511,"z":-0.48967432975769043},"j3":{"w":1.0,"x":-12.277113914489746,"y":0.9699291586875916,"z":-0.5359781384468079}}}},{"id":38,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":9.527641296386719,"z":0.0}}}},{"id":39,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-5.397964000701904,"y":12.993012428283691,"z":0.0}}}}],"id":0,"name":{"name":"Root"},"root":false}],"fog":{"ambientFactor":0.009999999776482582,"density":0.0005000000237487257,"enable":true,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"height":0.0,"heightFalloff":0.0284000001847744,"rayMarchStepCount":10,"rayMarching":true,"scatteringAnisotropy":-0.6000000238418579,"scatteringFactor":2.0,"volumetricIntensity":1.0},"irradianceVolume":{"aabb":{"max":{"x":38.237998962402344,"y":18.340999603271484,"z":31.85099983215332},"min":{"x":-38.63600158691406,"y":-9.817999839782715,"z":-21.163000106811523}},"bias":0.30000001192092896,"cascadeCount":1,"enable":true,"gamma":5.0,"hysteresis":0.9800000190734863,"lowerResMoments":true,"opacityCheck":false,"optimizeProbes":true,"probeCount":{"x":20,"y":20,"z":20},"rayCount":100,"rayCountInactive":32,"sampleEmissives":false,"scroll":false,"sharpness":50.0,"splitCorrection":2.0,"strength":1.0,"useShadowMap":false},"name":"sponza","physicsWorld":null,"postProcessing":{"chromaticAberration":{"colorsReversed":false,"enable":false,"strength":1.0},"contrast":1.0,"filmGrain":{"enable":false,"strength":0.10000000149011612},"filmicTonemapping":false,"fsr2":true,"paperWhiteLuminance":150.0,"saturation":1.0,"screenMaxLuminance":1600.0,"sharpen":{"enable":true,"factor":0.15000000596046448},"taa":{"enable":true,"jitterRange":0.9900000095367432},"tint":{"x":1.0,"y":1.0,"z":1.0},"vignette":{"color":{"x":0.0,"y":0.0,"z":0.0},"enable":false,"offset":0.0,"power":0.0,"strength":0.0}},"reflection":{"bias":0.0,"currentClipFactor":2.0,"ddgi":true,"enable":true,"halfResolution":true,"historyClipMax":1.0,"opacityCheck":false,"radianceLimit":10.0,"roughnessCutoff":0.8999999761581421,"rt":true,"spatialFilterStrength":5.234000205993652,"temporalWeight":0.9520000219345093,"textureLevel":4,"useNormalMaps":true,"useShadowMap":false},"sky":{"atmosphere":{"height":100000.0,"mieHeightScale":1200.0,"mieScatteringCoeff":2.099999983329326e-05,"probeResolution":128,"rayleighHeightScale":8000.0,"rayleighScatteringCoeff":{"x":5.500000042957254e-06,"y":1.2999999853491317e-05,"z":2.2399999579647556e-05}},"clouds":{"castShadow":false,"coverageResolution":512,"coverageScale":0.25,"coverageSpeed":5.0,"darkEdgeAmbient":0.10000000149011612,"darkEdgeFocus":2.0,"densityMultiplier":0.800000011920929,"detailResolution":32,"detailScale":16.0,"detailSpeed":10.0,"detailStrength":0.15000000596046448,"distanceLimit":8000.0,"enable":true,"halfResolution":true,"heightStretch":0.5,"maxHeight":1700.0,"minHeight":1400.0,"occlusionSampleCount":5,"sampleCount":64,"scattering":{"eccentricityFirstPhase":0.0,"eccentricitySecondPhase":-0.5,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"phaseAlpha":0.5,"scatteringFactor":2.0},"shadowResolution":512,"shadowSampleFraction":4,"shapeResolution":128,"shapeScale":2.0,"shapeSpeed":5.0,"stochasticOcclusionSampling":true},"intensity":1.0,"planetCenter":{"x":0.0,"y":-650000.0,"z":0.0},"planetRadius":649000.0},"ssgi":{"aoStrength":1.0,"enable":true,"enableAo":true,"halfResolution":true,"irradianceLimit":10.0,"radius":1.0,"rayCount":2,"sampleCount":8},"sss":{"enable":true,"maxLength":0.4970000088214874,"sampleCount":8,"thickness":0.30000001192092896},"wind":{"direction":{"x":1.0,"y":1.0},"speed":10.0}} \ No newline at end of file +{"aabb":{"max":{"x":128.0,"y":128.0,"z":128.0},"min":{"x":-128.0,"y":-128.0,"z":-128.0}},"ao":{"enable":false,"halfResolution":true,"opacityCheck":false,"radius":3.0,"rt":true,"sampleCount":16,"strength":1.0},"depth":5.0,"entities":[{"entities":[{"id":1,"light":{"color":{"x":1.0,"y":0.9254902005195618,"z":0.8196078538894653},"intensity":10.0,"isMain":true,"mobility":0,"properties":{"direction":{"x":0.0,"y":-1.0,"z":0.2800000011920929}},"shadow":{"allowDynamicEntities":false,"allowTerrain":true,"bias":0.800000011920929,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":75.0,"edgeSoftness":0.05000000074505806,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":2048,"splitCorrection":0.0,"useCubemap":false,"viewCount":1,"views":[{"farDistance":75.0,"frustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"nearDistance":0.0,"orthoSize":{"w":43.0,"x":-50.0,"y":50.0,"z":-41.0},"projectionMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.26962992548942566,"z":0.9629640579223633},"j2":{"w":0.0,"x":0.0,"y":0.9629640579223633,"z":-0.26962992548942566},"j3":{"w":1.0,"x":-0.0,"y":-0.0,"z":0.0}}}]},"type":0,"volumetric":true},"name":{"name":"Directional light"}},{"id":2,"mesh":{"dontCull":false,"resourcePath":"sponza/meshes/sponza.aemesh","visible":true},"name":{"name":"Sponza"},"rigidBody":{"bodyIndex":32,"creationSettings":{"angularDampening":0.0,"linearDampening":0.0,"shape":{"meshSettings":{"resourcePath":"sponza/meshes/sponza.aemesh","scale":{"x":0.012193998321890831,"y":0.012000000104308128,"z":0.012193998321890831}}}},"layer":0},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.012193998321890831,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":0.012000000104308128,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":0.012193998321890831},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}}}},{"id":3,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":0,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.000000238418579,"y":1.000000238418579,"z":1.000000238418579}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.4756948947906494,"y":0.00011953715875279158,"z":-0.8796106576919556},"j1":{"w":0.0,"x":0.5917145013809204,"y":-0.739871621131897,"z":-0.32010072469711304},"j2":{"w":0.0,"x":-0.6508373022079468,"y":-0.6727486252784729,"z":0.3518824875354767},"j3":{"w":1.0,"x":-15.995047569274902,"y":0.9694054126739502,"z":0.2113814800977707}}}},{"id":4,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Wall"},"rigidBody":{"bodyIndex":1,"creationSettings":{"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":1.0,"scale":{"x":0.1481112539768219,"y":0.17914418876171112,"z":2.874448299407959}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.12404608726501465,"y":-7.875383403188607e-07,"z":0.08092907071113586},"j1":{"w":0.0,"x":-6.167340416141087e-07,"y":0.17914418876171112,"z":2.688605945877498e-06},"j2":{"w":0.0,"x":-1.5706194639205933,"y":-4.1537619836162776e-05,"z":2.407406806945801},"j3":{"w":1.0,"x":7.4162163734436035,"y":-0.04500603675842285,"z":-0.9572893381118774}}}},{"id":5,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":2,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.9999986290931702,"y":0.9999986290931702,"z":0.9999986290931702}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.30071619153022766,"y":0.9535101652145386,"z":0.01963132992386818},"j1":{"w":0.0,"x":-0.02151578664779663,"y":-0.013796210289001465,"z":0.9996733665466309},"j2":{"w":0.0,"x":0.9534696936607361,"y":-0.3010404407978058,"z":0.016366761177778244},"j3":{"w":1.0,"x":4.233027935028076,"y":0.966492235660553,"z":1.2846850156784058}}}},{"id":6,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":3,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0475580133497715,"y":-8.188627589333919e-07,"z":0.06712339073419571},"j1":{"w":0.0,"x":-3.60343005922914e-06,"y":-0.1039920523762703,"z":1.2844517414123402e-06},"j2":{"w":0.0,"x":0.8159534335136414,"y":-3.541418118402362e-05,"z":-0.5781162977218628},"j3":{"w":1.0,"x":-9.601022720336914,"y":1.530970811843872,"z":-0.44825008511543274}}}},{"camera":{"aspectRatio":2.0,"exposure":1.0,"farPlane":400.0,"fieldOfView":55.20000076293945,"isMain":true,"location":{"x":0.0,"y":1.2000000476837158,"z":0.0},"nearPlane":1.0,"rotation":{"x":51.511505126953125,"y":0.15597067773342133},"thirdPerson":true,"thirdPersonDistance":3.0,"useEntityRotation":true,"useEntityTranslation":true},"id":7,"mesh":{"dontCull":false,"resourcePath":"meshes/capsule.aemesh","visible":true},"name":{"name":"Player"},"player":{"allowInput":true,"creationSettings":{"shape":{"capsuleShapeSettings":{"density":1.0,"height":1.2000000476837158,"radius":0.30000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"fastVelocity":4.0,"jumpVelocity":4.0,"slowVelocity":1.600000023841858},"text":{"halfSize":{"x":0.5,"y":1.0},"outlineColor":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"outlineFactor":0.0,"position":{"x":0.0,"y":1.600000023841858,"z":0.0},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"This is the player","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.07999999821186066},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-10.923478126525879,"y":-0.030071211978793144,"z":-1.5454801321029663}}}},{"audio":{"cutoff":0.0010000000474974513,"falloffFactor":0.10000000149011612,"falloffPower":2.0,"permanentPlay":false,"stream":{"loop":false,"pitch":1.0,"resourcePath":"/music.wav","time":0.0,"volume":0.0},"volume":1.0},"id":8,"name":{"name":"WelcomeText"},"text":{"halfSize":{"x":1.899999976158142,"y":1.0},"outlineColor":{"w":1.0,"x":1.0,"y":0.0,"z":0.0},"outlineFactor":0.15000000596046448,"position":{"x":0.0,"y":0.0,"z":1.2999999523162842},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"Welcome to this demo scene!","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.1899999976158142},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.01578390598297119,"y":0.00355260306969285,"z":0.9998670816421509},"j1":{"w":0.0,"x":0.40691956877708435,"y":0.9134560227394104,"z":0.003178075887262821},"j2":{"w":0.0,"x":-0.913324773311615,"y":0.4069172441959381,"z":-0.015863558277487755},"j3":{"w":1.0,"x":2.9802322387695313e-08,"y":4.168000221252441,"z":-0.02871951460838318}}}},{"entities":[{"id":10,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":4,"creationSettings":{"angularVelocity":{"x":0.3400594890117645,"y":0.002075438853353262,"z":-0.2711464762687683},"linearVelocity":{"x":0.027797559276223183,"y":-0.06926704198122025,"z":0.03678030148148537},"motionQuality":1,"objectLayer":1,"restitution":-0.0,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226305991411209,"y":0.10399112105369568,"z":0.24259740114212036}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.06749320030212402,"y":-0.0013515298487618566,"z":0.04701119661331177},"j1":{"w":0.0,"x":-0.05943548306822777,"y":-5.547449109144509e-05,"z":-0.08533213287591934},"j2":{"w":0.0,"x":0.003344531636685133,"y":-0.2425646185874939,"z":-0.0021718384232372046},"j3":{"w":1.0,"x":-6.993166923522949,"y":0.07752954214811325,"z":-0.49586528539657593}}}},{"id":11,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":5,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226487040519714,"y":0.10399449616670609,"z":1.000009298324585}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.001214503077790141,"y":4.0089940739562735e-05,"z":0.08225589245557785},"j1":{"w":0.0,"x":-0.10398011654615402,"y":-0.000795417174231261,"z":0.0015356455696746707},"j2":{"w":0.0,"x":0.0076551553793251514,"y":-0.9999799728393555,"z":0.00037435046397149563},"j3":{"w":1.0,"x":-0.18109244108200073,"y":1.1424553394317627,"z":-2.4032680988311768}}}},{"id":12,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":6,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399213433265686,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004975396674126387,"y":-3.6774740692635532e-06,"z":0.0821131020784378},"j1":{"w":0.0,"x":-0.10380175709724426,"y":-6.8306521825434174e-06,"z":-0.006289551965892315},"j2":{"w":0.0,"x":6.824726733611897e-05,"y":-0.9999992847442627,"z":-4.065033863298595e-05},"j3":{"w":1.0,"x":0.49817052483558655,"y":0.3519432246685028,"z":-2.3503992557525635}}}},{"id":13,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":7,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.10399220138788223,"z":0.9999990463256836}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006919844541698694,"y":0.0009341590339317918,"z":0.08196679502725601},"j1":{"w":0.0,"x":-0.10362283140420914,"y":-0.00030928864725865424,"z":0.008751623332500458},"j2":{"w":0.0,"x":0.003919091075658798,"y":-0.9999301433563232,"z":0.011065145023167133},"j3":{"w":1.0,"x":2.0737833976745605,"y":0.3635621964931488,"z":-1.7112125158309937}}}},{"id":14,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":8,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.10399205982685089,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.00037123600486665964,"y":-0.00020935118664056063,"z":0.08226258307695389},"j1":{"w":0.0,"x":-0.10399100184440613,"y":-7.686027743147861e-07,"z":0.000469290855107829},"j2":{"w":0.0,"x":-4.082914983882802e-06,"y":-0.9999959468841553,"z":-0.0025448778178542852},"j3":{"w":1.0,"x":3.7019379138946533,"y":0.35346531867980957,"z":-2.4043333530426025}}}},{"id":15,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":9,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.0822637677192688,"y":0.10399221628904343,"z":1.0000003576278687}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0014320656191557646,"y":-0.005514409858733416,"z":0.08206624537706375},"j1":{"w":0.0,"x":-0.1039608046412468,"y":-0.0019218007801100612,"z":0.0016850243555381894},"j2":{"w":0.0,"x":0.01734951324760914,"y":-0.9975799322128296,"z":-0.06733495742082596},"j3":{"w":1.0,"x":1.3664464950561523,"y":1.2094060182571411,"z":-2.3293323516845703}}}},{"id":16,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":10,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007250844966620207,"y":-0.00029188839835114777,"z":0.08194299042224884},"j1":{"w":0.0,"x":-0.10357026010751724,"y":0.0019194179913029075,"z":-0.009157725609838963},"j2":{"w":0.0,"x":-0.01807291805744171,"y":-0.9998225569725037,"z":-0.005160685162991285},"j3":{"w":1.0,"x":3.177853584289551,"y":1.137428641319275,"z":-2.286043643951416}}}},{"id":17,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":11,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999994039535522}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007074753753840923,"y":-0.0009124425705522299,"z":0.08195383846759796},"j1":{"w":0.0,"x":-0.10360674560070038,"y":2.178741397074191e-06,"z":-0.008943937718868256},"j2":{"w":0.0,"x":0.0009330803295597434,"y":-0.999937891960144,"z":-0.01105236355215311},"j3":{"w":1.0,"x":4.739034652709961,"y":1.1431937217712402,"z":-2.344177484512329}}}},{"id":18,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":12,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-2.9814507797709666e-05,"y":-0.00011468570301076397,"z":0.08226361125707626},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-5.103151488583535e-05,"z":-3.7763817090308294e-05},"j2":{"w":0.0,"x":0.0004912313306704164,"y":-0.9999982118606567,"z":-0.0013939131749793887},"j3":{"w":1.0,"x":5.269709587097168,"y":0.3537576496601105,"z":-2.396353006362915}}}},{"id":19,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":13,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226397633552551,"y":0.10399535298347473,"z":1.0000017881393433}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0029943662229925394,"y":-0.004902660381048918,"z":0.08206314593553543},"j1":{"w":0.0,"x":-0.1038932278752327,"y":-0.00239846995100379,"z":-0.0039341989904642105},"j2":{"w":0.0,"x":0.025261566042900085,"y":-0.9979578852653503,"z":-0.05869881808757782},"j3":{"w":1.0,"x":0.4539576470851898,"y":1.9912066459655762,"z":-2.3605332374572754}}}},{"id":20,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":14,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999991059303284}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0047220797277987,"y":-0.006254853215068579,"z":0.08188952505588531},"j1":{"w":0.0,"x":-0.10381996631622314,"y":0.000815314007923007,"z":-0.005924399942159653},"j2":{"w":0.0,"x":-0.0034728916361927986,"y":-0.9970735311508179,"z":-0.0763583704829216},"j3":{"w":1.0,"x":2.0099921226501465,"y":1.9823397397994995,"z":-2.1112253665924072}}}},{"id":21,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":15,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0015184117946773767,"y":-0.001873633824288845,"z":0.08222834020853043},"j1":{"w":0.0,"x":-0.10390593856573105,"y":0.0038146909791976213,"z":-0.0018317853100597858},"j2":{"w":0.0,"x":-0.036265525966882706,"y":-0.9990666508674622,"z":-0.02343420498073101},"j3":{"w":1.0,"x":3.611302614212036,"y":1.9326788187026978,"z":-2.369572162628174}}}},{"id":22,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":16,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370811462402,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0011607652995735407,"y":-0.005252636969089508,"z":0.08208763599395752},"j1":{"w":0.0,"x":-0.1039327085018158,"y":-0.003092399565503001,"z":-0.0016675429651513696},"j2":{"w":0.0,"x":0.03069702349603176,"y":-0.9975154995918274,"z":-0.06339509040117264},"j3":{"w":1.0,"x":0.911769449710846,"y":2.8139381408691406,"z":-2.3714351654052734}}}},{"id":23,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":17,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399208217859268,"z":0.9999986886978149}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.002328230533748865,"y":-0.01567736454308033,"z":0.08072245121002197},"j1":{"w":0.0,"x":-0.10387608408927917,"y":0.0032992407213896513,"z":0.0036367876455187798},"j2":{"w":0.0,"x":-0.03779618442058563,"y":-0.9811586737632751,"z":-0.189463809132576},"j3":{"w":1.0,"x":2.5983128547668457,"y":2.8227591514587402,"z":-2.0519001483917236}}}},{"id":24,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":18,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920449256897,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006420230958610773,"y":-0.0025190962478518486,"z":0.0819740742444992},"j1":{"w":0.0,"x":-0.10356941819190979,"y":0.004437707830220461,"z":0.008247951045632362},"j2":{"w":0.0,"x":-0.04495199769735336,"y":-0.9986188411712646,"z":-0.027167268097400665},"j3":{"w":1.0,"x":4.155186176300049,"y":2.7027957439422607,"z":-2.4178249835968018}}}},{"id":25,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":19,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999993443489075}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007614439819008112,"y":-0.014711390249431133,"z":0.08057859539985657},"j1":{"w":0.0,"x":-0.1032203733921051,"y":-0.006378653459250927,"z":-0.010918588377535343},"j2":{"w":0.0,"x":0.07885781675577164,"y":-0.9819651246070862,"z":-0.17182737588882446},"j3":{"w":1.0,"x":1.3723328113555908,"y":3.7512500286102295,"z":-2.243227481842041}}}},{"id":26,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":20,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.005531982518732548,"y":-0.015606719069182873,"z":0.08058004826307297},"j1":{"w":0.0,"x":-0.10365156084299088,"y":0.005922866519540548,"z":-0.005968747194856405},"j2":{"w":0.0,"x":-0.0449003241956234,"y":-0.9801850318908691,"z":-0.19292448461055756},"j3":{"w":1.0,"x":3.1063742637634277,"y":3.642221689224243,"z":-2.205120325088501}}}},{"id":27,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":21,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399164259433746,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.009233793243765831,"y":-2.8461645484867404e-08,"z":-0.08174382150173187},"j1":{"w":0.0,"x":5.111483005748596e-07,"y":-0.10399164259433746,"z":-2.153150546746474e-08},"j2":{"w":0.0,"x":-0.9936796426773071,"y":-4.907456968794577e-06,"z":0.11224624514579773},"j3":{"w":1.0,"x":5.397507667541504,"y":1.5309886932373047,"z":-0.8703097105026245}}}},{"id":28,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":22,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.004304870497435331,"y":-0.016259904950857162,"z":0.08052577078342438},"j1":{"w":0.0,"x":-0.10374186187982559,"y":0.0035653808154165745,"z":0.006265922449529171},"j2":{"w":0.0,"x":-0.04547032341361046,"y":-0.9796709418296814,"z":-0.19538608193397522},"j3":{"w":1.0,"x":3.7071003913879395,"y":4.404808521270752,"z":-2.0641326904296875}}}},{"id":29,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":23,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226374536752701,"y":0.1039920300245285,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004521988797932863,"y":-0.014796562492847443,"z":0.08079565316438675},"j1":{"w":0.0,"x":-0.10348106175661087,"y":-0.007410035468637943,"z":-0.0071486919187009335},"j2":{"w":0.0,"x":0.0823487713932991,"y":-0.9811068177223206,"z":-0.17506666481494904},"j3":{"w":1.0,"x":1.740257740020752,"y":4.569649696350098,"z":-2.0765440464019775}}}},{"id":30,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":24,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"script":{"permanentExecution":false,"resourcePath":"scripts/example.lua","scriptProperties":{"duplicateEntityName":{"type":"string","value":""}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0822434350848198,"y":-3.559059393865027e-07,"z":-0.0018298403592780232},"j1":{"w":0.0,"x":6.938781211829337e-07,"y":0.1486254185438156,"z":2.2790266029915074e-06},"j2":{"w":0.0,"x":0.021798700094223022,"y":-1.5125399841053877e-05,"z":0.97975754737854},"j3":{"w":1.0,"x":-0.42584455013275146,"y":-0.042439818382263184,"z":0.7894344925880432}}}},{"id":31,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":25,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226378262042999,"y":0.015076023526489735,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.07320480048656464,"y":4.977956632501446e-05,"z":-0.03752845898270607},"j1":{"w":0.0,"x":0.006859811022877693,"y":-0.0011024783598259091,"z":0.013379612006247044},"j2":{"w":0.0,"x":-0.032167207449674606,"y":-0.9773759245872498,"z":-0.0640433058142662},"j3":{"w":1.0,"x":2.4300098419189453,"y":0.3631786108016968,"z":1.207587718963623}}}},{"id":32,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":26,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.06837532669305801,"y":-0.0017373006558045745,"z":-0.04570697247982025},"j1":{"w":0.0,"x":0.05685741454362869,"y":0.11100539565086365,"z":0.08083657920360565},"j2":{"w":0.0,"x":0.39542150497436523,"y":-0.6513306498527527,"z":0.6162874698638916},"j3":{"w":1.0,"x":3.135746955871582,"y":0.2095150351524353,"z":-1.027677297592163}}}},{"id":33,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":27,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000786781311}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0716107115149498,"y":-4.5638077494913887e-07,"z":-0.040487490594387054},"j1":{"w":0.0,"x":0.0005247447988949716,"y":0.14862160384655,"z":0.0009264472755603492},"j2":{"w":0.0,"x":0.4823108911514282,"y":-0.007020606193691492,"z":0.8530691862106323},"j3":{"w":1.0,"x":2.5021331310272217,"y":-0.04527640342712402,"z":0.6787291169166565}}}}],"id":9,"name":{"name":"Staircase"},"root":false},{"id":34,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":28,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-3.9226383705681656e-06,"y":0.0,"z":0.08226368576288223},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-2.479363736540563e-08,"z":-4.958727458870271e-06},"j2":{"w":0.0,"x":2.384183801495965e-07,"y":-0.9999991655349731,"z":0.0},"j3":{"w":1.0,"x":3.1176745891571045,"y":5.388330459594727,"z":-4.729436874389648}}}},{"entities":[{"entities":[{"id":37,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":31,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000007152557373,"y":1.0000007152557373,"z":1.0000007152557373}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.9554479122161865,"y":0.034463346004486084,"z":0.29313671588897705},"j1":{"w":0.0,"x":-0.09065454453229904,"y":0.9794178605079651,"z":0.18033018708229065},"j2":{"w":0.0,"x":-0.28088951110839844,"y":-0.19888851046562195,"z":0.9386930465698242},"j3":{"w":0.999999463558197,"x":-1.679502010345459,"y":-0.44969987869262695,"z":6.6491780281066895}}}}],"id":36,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":30,"creationSettings":{"angularVelocity":{"x":-0.003580757649615407,"y":-0.0010163785191252828,"z":-0.001152479788288474},"linearVelocity":{"x":0.0011589848436415195,"y":-0.276141881942749,"z":-0.003600968746468425},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000016689300537,"y":1.0000016689300537,"z":1.0000016689300537}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.7511749267578125,"y":0.22571837902069092,"z":-0.6203151345252991},"j1":{"w":0.0,"x":-0.39222919940948486,"y":0.6032152771949768,"z":0.6944692730903625},"j2":{"w":0.0,"x":0.5309374332427979,"y":0.7649720907211304,"z":-0.3645859360694885},"j3":{"w":1.0,"x":-11.712557792663574,"y":4.754024505615234,"z":-4.003259658813477}}}}],"id":35,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":29,"creationSettings":{"angularVelocity":{"x":0.16539807617664337,"y":0.1814352571964264,"z":-0.11671467125415802},"linearVelocity":{"x":0.11671468615531921,"y":2.4347741600649897e-09,"z":0.16539809107780457},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.6672989130020142,"y":0.0363946259021759,"z":0.7439002990722656},"j1":{"w":0.0,"x":0.5453938245773315,"y":0.7040697336196899,"z":0.45478731393814087},"j2":{"w":0.0,"x":-0.5072058439254761,"y":0.7091977000236511,"z":-0.48967432975769043},"j3":{"w":1.0,"x":-12.277113914489746,"y":0.9699291586875916,"z":-0.5359781384468079}}}},{"id":38,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":9.527641296386719,"z":0.0}}}},{"id":39,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-5.397964000701904,"y":12.993012428283691,"z":0.0}}}},{"id":40,"light":{"color":{"x":1.0,"y":1.0,"z":1.0},"intensity":1.0,"isMain":false,"mobility":1,"properties":{"attenuation":1.0,"position":{"x":0.0,"y":0.0,"z":0.0},"radius":10.0},"shadow":{"allowDynamicEntities":false,"allowTerrain":false,"bias":0.10000000149011612,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":0.0,"edgeSoftness":0.0,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":1024,"splitCorrection":0.8999999761581421,"useCubemap":true,"viewCount":6,"views":[{"farDistance":0.0,"frustumMatrix":{"j0":{"w":1.0,"x":0.0,"y":0.0,"z":1.0020020008087158},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":0.0,"x":-1.0,"y":0.0,"z":0.0},"j3":{"w":0.4823928773403168,"x":-0.8340781927108765,"y":0.8387702107429504,"z":0.46333861351013184}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":0.0,"y":0.0,"z":-1.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j3":{"w":1.0,"x":-0.8340781927108765,"y":0.8387702107429504,"z":-0.4823928773403168}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j3":{"w":-0.4823928773403168,"x":0.8340781927108765,"y":0.8387702107429504,"z":-0.5033786296844482}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j3":{"w":1.0,"x":0.8340781927108765,"y":0.8387702107429504,"z":0.4823928773403168}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":1.0,"x":0.0,"y":0.0,"z":1.0020020008087158},"j2":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j3":{"w":-0.8387702107429504,"x":0.4823928773403168,"y":0.8340781927108765,"z":-0.8604694604873657}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.0,"z":-1.0},"j2":{"w":0.0,"x":0.0,"y":1.0,"z":-0.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":0.8340781927108765,"z":0.8387702107429504}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j2":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j3":{"w":0.8387702107429504,"x":0.4823928773403168,"y":-0.8340781927108765,"z":0.8204294443130493}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j2":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":-0.8340781927108765,"z":-0.8387702107429504}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":1.0,"x":0.0,"y":0.0,"z":1.0020020008087158},"j3":{"w":0.8340781927108765,"x":0.4823928773403168,"y":0.8387702107429504,"z":0.8157280087471008}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-0.0,"y":0.0,"z":-1.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":0.8387702107429504,"z":-0.8340781927108765}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":-0.8340781927108765,"x":-0.4823928773403168,"y":0.8387702107429504,"z":-0.8557680249214172}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":-0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-0.4823928773403168,"y":0.8387702107429504,"z":0.8340781927108765}}}]},"type":1,"volumetric":true},"name":{"name":"Point light"},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-0.4823928773403168,"y":0.8387702107429504,"z":-0.8340781927108765}}}}],"id":0,"name":{"name":"Root"},"root":false}],"fog":{"ambientFactor":0.009999999776482582,"density":0.0005000000237487257,"enable":true,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"height":0.0,"heightFalloff":0.0284000001847744,"rayMarchStepCount":10,"rayMarching":true,"scatteringAnisotropy":-0.6000000238418579,"scatteringFactor":2.0,"volumetricIntensity":1.0},"irradianceVolume":{"aabb":{"max":{"x":38.237998962402344,"y":18.340999603271484,"z":31.85099983215332},"min":{"x":-38.63600158691406,"y":-9.817999839782715,"z":-21.163000106811523}},"bias":0.30000001192092896,"cascadeCount":1,"enable":true,"gamma":5.0,"hysteresis":0.9800000190734863,"lowerResMoments":true,"opacityCheck":false,"optimizeProbes":true,"probeCount":{"x":20,"y":20,"z":20},"rayCount":100,"rayCountInactive":32,"sampleEmissives":false,"scroll":false,"sharpness":50.0,"splitCorrection":2.0,"strength":1.0,"useShadowMap":false},"name":"sponza","physicsWorld":null,"postProcessing":{"chromaticAberration":{"colorsReversed":false,"enable":false,"strength":1.0},"contrast":1.0,"filmGrain":{"enable":false,"strength":0.10000000149011612},"filmicTonemapping":false,"fsr2":true,"paperWhiteLuminance":150.0,"saturation":1.0,"screenMaxLuminance":1600.0,"sharpen":{"enable":true,"factor":0.15000000596046448},"taa":{"enable":true,"jitterRange":0.9900000095367432},"tint":{"x":1.0,"y":1.0,"z":1.0},"vignette":{"color":{"x":0.0,"y":0.0,"z":0.0},"enable":false,"offset":0.0,"power":0.0,"strength":0.0}},"reflection":{"bias":0.0,"currentClipFactor":2.0,"ddgi":true,"enable":true,"halfResolution":true,"historyClipMax":1.0,"opacityCheck":false,"radianceLimit":10.0,"roughnessCutoff":0.8999999761581421,"rt":true,"spatialFilterStrength":5.234000205993652,"temporalWeight":0.9520000219345093,"textureLevel":4,"useNormalMaps":true,"useShadowMap":false},"sky":{"atmosphere":{"height":100000.0,"mieHeightScale":1200.0,"mieScatteringCoeff":2.099999983329326e-05,"probeResolution":128,"rayleighHeightScale":8000.0,"rayleighScatteringCoeff":{"x":5.500000042957254e-06,"y":1.2999999853491317e-05,"z":2.2399999579647556e-05}},"clouds":{"castShadow":false,"coverageResolution":512,"coverageScale":0.25,"coverageSpeed":5.0,"darkEdgeAmbient":0.10000000149011612,"darkEdgeFocus":2.0,"densityMultiplier":0.800000011920929,"detailResolution":32,"detailScale":16.0,"detailSpeed":10.0,"detailStrength":0.15000000596046448,"distanceLimit":8000.0,"enable":true,"halfResolution":true,"heightStretch":0.5,"maxHeight":1700.0,"minHeight":1400.0,"occlusionSampleCount":5,"sampleCount":64,"scattering":{"eccentricityFirstPhase":0.0,"eccentricitySecondPhase":-0.5,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"phaseAlpha":0.5,"scatteringFactor":2.0},"shadowResolution":512,"shadowSampleFraction":4,"shapeResolution":128,"shapeScale":2.0,"shapeSpeed":5.0,"stochasticOcclusionSampling":true},"intensity":1.0,"planetCenter":{"x":0.0,"y":-650000.0,"z":0.0},"planetRadius":649000.0},"ssgi":{"aoStrength":1.0,"enable":true,"enableAo":true,"halfResolution":true,"irradianceLimit":10.0,"radius":1.0,"rayCount":2,"sampleCount":8},"sss":{"enable":true,"maxLength":0.4970000088214874,"sampleCount":8,"thickness":0.30000001192092896},"wind":{"direction":{"x":1.0,"y":1.0},"speed":10.0}} \ No newline at end of file diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 91c2f93be..76e6c3fa3 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -26,11 +26,6 @@ layout(set = 3, binding = 1) uniform sampler2D sssTexture; layout(set = 3, binding = 2) uniform sampler2D cloudMap; #endif -layout(std140, set = 3, binding = 3) uniform UniformBuffer { - int mapIndices[16]; - int lightCount; -} uniforms; - layout(std140, set = 3, binding = 4) uniform CloudShadowUniformBuffer { CloudShadow cloudShadow; } cloudShadowUniforms; @@ -40,6 +35,14 @@ layout(set = 3, binding = 5) uniform sampler shadowSampler; layout(set = 3, binding = 6) uniform texture2DArray cascadeMaps[8]; layout(set = 3, binding = 14) uniform textureCube cubeMaps[8]; +layout(push_constant) uniform constants { + int lightCount; + int padding0; + int padding1; + int padding2; + int mapIndices[16]; +} pushConstants; + vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMain); float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain); @@ -58,10 +61,12 @@ void main() { // We don't have any light direction, that's why we use vec3(0.0, -1.0, 0.0) as a placeholder Surface surface = GetSurface(texCoord, depth, vec3(0.0, -1.0, 0.0), geometryNormal); - for (int i = 0; i < uniforms.lightCount && i < 8; i++) { + direct = vec3(.0); + + for (int i = 0; i < pushConstants.lightCount && i < 8; i++) { Light light = lights[i]; - light.shadow.mapIdx = uniforms.mapIndices[i]; + light.shadow.mapIdx = pushConstants.mapIndices[i]; bool isMain = i == 0 ? true : false; direct += EvaluateLight(light, surface, geometryNormal, isMain); } @@ -129,6 +134,15 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai } +vec3 sampleOffsetDirections[20] = vec3[] +( + vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) +); + float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain) { if (light.shadow.cascadeCount <= 0) @@ -144,14 +158,24 @@ float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometr -geometryNormal : geometryNormal : geometryNormal; if (lightType == DIRECTIONAL_LIGHT) { - /* shadowFactor = CalculateCascadedShadow(light.shadow, cascadeMaps[nonuniformEXT(light.shadow.mapIdx)], shadowSampler, surface.P, vec3(vec2(pixel) + 0.5, 0.0), shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); - */ } else if (lightType == POINT_LIGHT) { - + int samples = 20; + float diskRadius = 0.0075; + shadowFactor = 0.0; + vec4 position = light.shadow.cascades[1].cascadeSpace * vec4(surface.P, 1.0); + vec4 absPosition = abs(position); + float depth = -max(absPosition.x, max(absPosition.y, absPosition.z)); + vec4 clip = light.shadow.cascades[0].cascadeSpace * vec4(0.0, 0.0, depth, 1.0); + depth = (clip.z - 0.0005) / clip.w; + for(int i = 0; i < samples; i++) { + shadowFactor += clamp(texture(samplerCubeShadow(cubeMaps[nonuniformEXT(light.shadow.mapIdx)], shadowSampler), + vec4(position.xyz + sampleOffsetDirections[i] * diskRadius, depth)), 0.0, 1.0); + } + shadowFactor /= float(samples + 1); } if (isMain) { diff --git a/data/shader/deferred/point.fsh b/data/shader/deferred/point.fsh index b0acdc56e..3586ca4f5 100644 --- a/data/shader/deferred/point.fsh +++ b/data/shader/deferred/point.fsh @@ -92,7 +92,7 @@ void main() { if (shadowEnabled) { for(int i = 0; i < samples; i++) { - shadowFactor += clamp(texture(shadowCubemap, vec4(lsPosition.xyz + sampleOffsetDirections[i] * diskRadius, depth)), 0.0, 1.0); + shadowFactor += clamp(texture(shadowCubemap, vec4(surface.P + sampleOffsetDirections[i] * diskRadius, depth)), 0.0, 1.0); } shadowFactor /= float(samples + 1); } diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index 3d0d4bc83..0dc6ea4c0 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -8,12 +8,6 @@ namespace Atlas { this->device = device; - auto bufferDesc = Graphics::BufferDesc { - .usageFlags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - .domain = Graphics::BufferDomain::Host, - .size = sizeof(Uniforms) - }; - uniformBuffer = Buffer::UniformBuffer(sizeof(Uniforms)); cloudShadowUniformBuffer = Buffer::UniformBuffer(sizeof(CloudShadow)); pipelineConfig = PipelineConfig("deferred/direct.csh"); @@ -43,24 +37,26 @@ namespace Atlas { std::vector> cascadeMaps; std::vector> cubeMaps; - Uniforms uniforms; - uniforms.lightCount = std::min(8, int32_t(lightData.lightEntities.size())); - for (int32_t i = 0; i < uniforms.lightCount; i++) { + PushConstants pushConstants; + pushConstants.lightCount = std::min(8, int32_t(lightData.lightEntities.size())); + for (int32_t i = 0; i < pushConstants.lightCount; i++) { auto& comp = lightData.lightEntities[i].comp; if (comp.shadow) { auto& shadow = comp.shadow; if (shadow->useCubemap) { - uniforms.mapIndices[i] = int32_t(cubeMaps.size()); + pushConstants.mapIndices[i] = int32_t(cubeMaps.size()); cubeMaps.push_back(shadow->cubemap->image); } else { - uniforms.mapIndices[i] = int32_t(cascadeMaps.size()); + pushConstants.mapIndices[i] = int32_t(cascadeMaps.size()); cascadeMaps.push_back(shadow->maps->image); } } } + commandList->PushConstants("constants", &pushConstants); + commandList->BindSampledImages(cascadeMaps, 3, 6); commandList->BindSampledImages(cubeMaps, 3, 14); @@ -70,7 +66,6 @@ namespace Atlas { commandList->BindPipeline(pipeline); commandList->BindImage(target->lightingTexture.image, 3, 0); - uniformBuffer.Bind(commandList, 3, 3); if (sss && sss->enable) { commandList->BindImage(target->sssTexture.image, target->sssTexture.sampler, 3, 1); diff --git a/src/engine/renderer/DirectLightRenderer.h b/src/engine/renderer/DirectLightRenderer.h index 696c7f9dd..a87529417 100644 --- a/src/engine/renderer/DirectLightRenderer.h +++ b/src/engine/renderer/DirectLightRenderer.h @@ -18,14 +18,16 @@ namespace Atlas { Helper::LightData& lightData, Graphics::CommandList* commandList); private: - struct alignas(16) Uniforms { - int32_t mapIndices[16]; + struct alignas(16) PushConstants { int32_t lightCount; + int32_t padding0; + int32_t padding1; + int32_t padding2; + int32_t mapIndices[16]; }; PipelineConfig pipelineConfig; - Buffer::UniformBuffer uniformBuffer; Buffer::UniformBuffer cloudShadowUniformBuffer; Ref shadowSampler; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index cc727a33d..c8d4facac 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -224,6 +224,7 @@ namespace Atlas { JobSystem::WaitSpin(scene->rayTracingWorldUpdateJob); + lightData.FillBuffer(scene); lightData.lightBuffer.Bind(commandList, 1, 16); ddgiRenderer.TraceAndUpdateProbes(scene, commandList); diff --git a/src/engine/renderer/helper/LightData.cpp b/src/engine/renderer/helper/LightData.cpp index 71578d61f..6e92a712e 100644 --- a/src/engine/renderer/helper/LightData.cpp +++ b/src/engine/renderer/helper/LightData.cpp @@ -93,8 +93,16 @@ namespace Atlas::Renderer::Helper { auto texelSize = glm::max(abs(corners[0].x - corners[1].x), abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; shadowUniform.cascades[i].distance = cascade->farDistance; - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix; + if (light.type == LightType::DirectionalLight) { + shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * + cascade->viewMatrix * camera.invViewMatrix; + } + else if (light.type == LightType::PointLight) { + if (i == 0) + shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix; + else + shadowUniform.cascades[i].cascadeSpace = glm::translate(mat4(1.0f), -prop.point.position) * camera.invViewMatrix; + } shadowUniform.cascades[i].texelSize = texelSize; } else { @@ -104,12 +112,12 @@ namespace Atlas::Renderer::Helper { } } - lights.emplace_back(std::move(lightUniform)); + lights.emplace_back(lightUniform); } if (lightBuffer.GetElementCount() < lightEntities.size()) { lightBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit - | Buffer::BufferUsageBits::UniformBufferBit, sizeof(Light), lightEntities.size(), lights.data()); + | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Light), lightEntities.size(), lights.data()); } else { lightBuffer.SetData(lights.data(), 0, lights.size()); diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index 886ca95bf..fdb20418e 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -118,7 +118,12 @@ namespace Atlas { else if (type == LightType::PointLight) { vec3 position = transformedProperties.point.position; - mat4 projectionMatrix = glm::perspective(glm::radians(90.0f), 1.0f, 0.01f, properties.point.radius); + const mat4 clip = mat4(1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.5f, 0.0f, + 0.0f, 0.0f, 0.5f, 1.0f); + + mat4 projectionMatrix = clip * glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, properties.point.radius); const vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; From 7f92f7d139b2ee37fe5317d679e39cb753ac175a Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Mon, 19 Aug 2024 21:40:39 +0200 Subject: [PATCH 04/66] Point lights are now working properly --- data/shader/deferred/direct.csh | 26 ++------------- data/shader/shadow.hsh | 32 +++++++++++++++++++ src/engine/Engine.cpp | 2 +- src/engine/renderer/DirectLightRenderer.cpp | 2 +- src/engine/renderer/ShadowRenderer.cpp | 2 ++ src/engine/renderer/helper/LightData.cpp | 1 - .../scene/components/LightComponent.cpp | 19 ++++------- 7 files changed, 46 insertions(+), 38 deletions(-) diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 76e6c3fa3..0cdc82be1 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -114,7 +114,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai float shadowFactor = GetShadowFactor(light, surface, lightType, geometryNormal, isMain); - vec3 radiance = light.color.rgb * light.intensity; + vec3 radiance = light.color.rgb * light.intensity * lightMultiplier; direct = direct * radiance * surface.NdotL * shadowFactor; if (surface.material.transmissive) { @@ -134,15 +134,6 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai } -vec3 sampleOffsetDirections[20] = vec3[] -( - vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), - vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), - vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), - vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), - vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) -); - float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain) { if (light.shadow.cascadeCount <= 0) @@ -163,19 +154,8 @@ float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometr shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); } else if (lightType == POINT_LIGHT) { - int samples = 20; - float diskRadius = 0.0075; - shadowFactor = 0.0; - vec4 position = light.shadow.cascades[1].cascadeSpace * vec4(surface.P, 1.0); - vec4 absPosition = abs(position); - float depth = -max(absPosition.x, max(absPosition.y, absPosition.z)); - vec4 clip = light.shadow.cascades[0].cascadeSpace * vec4(0.0, 0.0, depth, 1.0); - depth = (clip.z - 0.0005) / clip.w; - for(int i = 0; i < samples; i++) { - shadowFactor += clamp(texture(samplerCubeShadow(cubeMaps[nonuniformEXT(light.shadow.mapIdx)], shadowSampler), - vec4(position.xyz + sampleOffsetDirections[i] * diskRadius, depth)), 0.0, 1.0); - } - shadowFactor /= float(samples + 1); + shadowFactor = CalculatePointShadow(light.shadow, cubeMaps[nonuniformEXT(light.shadow.mapIdx)], + shadowSampler, surface.P); } if (isMain) { diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh index 0262a61fb..056b58174 100644 --- a/data/shader/shadow.hsh +++ b/data/shader/shadow.hsh @@ -753,4 +753,36 @@ float CalculateShadowWorldSpace(Shadow shadow, texture2DArray cascadeMaps, sampl return cascadeLookup(shadow, cascadeMaps, shadowSampler, 0.0, cascadeMatrix, position, position, 0.0, false); +} + +vec3 sampleOffsetDirections[20] = vec3[] ( + vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) +); + + +float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSampler, vec3 position) { + + int samples = 20; + float diskRadius = shadow.edgeSoftness; + + vec4 shadowCoords = shadow.cascades[1].cascadeSpace * vec4(position, 1.0); + shadowCoords.y *= -1.0; + vec4 absPosition = abs(shadowCoords); + float depth = -max(absPosition.x, max(absPosition.y, absPosition.z)); + vec4 clip = shadow.cascades[0].cascadeSpace * vec4(0.0, 0.0, depth, 1.0); + depth = clip.z / clip.w; + + float shadowFactor = 0.0; + for(int i = 0; i < samples; i++) { + shadowFactor += clamp(texture(samplerCubeShadow(cubeMap, shadowSampler), + vec4(shadowCoords.xyz + sampleOffsetDirections[i] * diskRadius, depth - shadow.bias * 0.001)), 0.0, 1.0); + } + shadowFactor /= float(samples + 1); + + return shadowFactor; + } \ No newline at end of file diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index c3559c8a9..8b22c8185 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -52,7 +52,7 @@ namespace Atlas { #ifdef AE_BUILDTYPE_DEBUG .enableValidationLayers = true, #else - .enableValidationLayers = true, + .enableValidationLayers = false, #endif .validationLayerSeverity = config.validationLayerSeverity, #ifndef AE_HEADLESS diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index 0dc6ea4c0..f0e80845f 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -55,7 +55,7 @@ namespace Atlas { } } - commandList->PushConstants("constants", &pushConstants); + commandList->PushConstants("constants", &pushConstants, sizeof(PushConstants)); commandList->BindSampledImages(cascadeMaps, 3, 6); commandList->BindSampledImages(cubeMaps, 3, 14); diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index 9e20568b1..a98d1d255 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -44,6 +44,8 @@ namespace Atlas { // Need to also keep track of non processed layer (e.g. long range layers) for (auto& [lightEntity, frameBuffer] : lightMap) { const auto& light = lightEntity.GetComponent(); + // Will be activated automatically by movable lights + light.shadow->update = false; if (light.type == LightType::DirectionalLight && light.shadow->longRange) { // Need to go through render passes to make sure images have transitioned diff --git a/src/engine/renderer/helper/LightData.cpp b/src/engine/renderer/helper/LightData.cpp index 6e92a712e..57895aeb2 100644 --- a/src/engine/renderer/helper/LightData.cpp +++ b/src/engine/renderer/helper/LightData.cpp @@ -72,7 +72,6 @@ namespace Atlas::Renderer::Helper { lightUniform.attenuation = prop.point.attenuation; } - auto& shadowUniform = lightUniform.shadow; if (light.shadow) { auto shadow = light.shadow; auto& shadowUniform = lightUniform.shadow; diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index fdb20418e..e0d422d17 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -118,18 +118,13 @@ namespace Atlas { else if (type == LightType::PointLight) { vec3 position = transformedProperties.point.position; - const mat4 clip = mat4(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.5f, 0.0f, - 0.0f, 0.0f, 0.5f, 1.0f); - - mat4 projectionMatrix = clip * glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, properties.point.radius); - const vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), - vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; - - const vec3 ups[] = { vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f), + mat4 projectionMatrix = clipMatrix * glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, properties.point.radius); + vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), + vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), + vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; + + vec3 ups[] = { vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, 0.0f, -1.0f), vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f) }; for (uint8_t i = 0; i < 6; i++) { From f41a3f6fffd0052e0b6bc826c4e51a8db48cf05e Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 20 Aug 2024 21:37:36 +0200 Subject: [PATCH 05/66] Upgrade Jolt + other things --- CMakeLists.txt | 2 +- src/demo/CMakeLists.txt | 4 ++++ src/editor/App.cpp | 17 +++++++++++++++++ src/editor/App.h | 2 ++ src/editor/CMakeLists.txt | 5 +++++ src/engine/CMakeLists.txt | 6 +++--- vcpkg.json | 6 +++--- 7 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b49ff4599..3941e2069 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,7 @@ find_package(VulkanMemoryAllocator CONFIG REQUIRED) find_package(glslang CONFIG REQUIRED) find_package(SPIRV-Tools-opt CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) -find_package(unofficial-joltphysics CONFIG REQUIRED) +find_package(Jolt CONFIG REQUIRED) find_package(Lua REQUIRED) find_package(sol2 CONFIG REQUIRED) diff --git a/src/demo/CMakeLists.txt b/src/demo/CMakeLists.txt index 32d42279b..e964df7f3 100644 --- a/src/demo/CMakeLists.txt +++ b/src/demo/CMakeLists.txt @@ -34,6 +34,10 @@ endforeach() if (UNIX AND NOT APPLE AND NOT ANDROID) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'") endif() +# Need to reference the vulkan SDK for MacOS to search at runtime +if (APPLE) +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'/usr/local/lib'") +endif() # We use the exported main file from the AtlasEngine library to able to use # the app class. Alternatively, you can write a main function yourself. diff --git a/src/editor/App.cpp b/src/editor/App.cpp index 9bc8788f4..1507da07a 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -21,6 +21,8 @@ namespace Atlas::Editor { ContentDiscovery::Update(); + SetDefaultWindowResolution(); + auto icon = Atlas::Texture::Texture2D("icon.png"); window.SetIcon(&icon); @@ -405,6 +407,21 @@ namespace Atlas::Editor { } + void App::SetDefaultWindowResolution() { + + auto resolution = GetScreenSize(); + if (resolution.y <= 1080) { + window.SetSize(1280, 720); + } + else if (resolution.y <= 1440) { + window.SetSize(1920, 1080); + } + else { + window.SetSize(2560, 1440); + } + + } + } Atlas::EngineInstance* GetEngineInstance() { diff --git a/src/editor/App.h b/src/editor/App.h index e205d5ed0..295414b9d 100644 --- a/src/editor/App.h +++ b/src/editor/App.h @@ -38,6 +38,8 @@ namespace Atlas::Editor { void SubscribeToResourceEvents(); + void SetDefaultWindowResolution(); + Input::MouseHandler mouseHandler; Input::KeyboardHandler keyboardHandler; diff --git a/src/editor/CMakeLists.txt b/src/editor/CMakeLists.txt index 032f5d24f..9b61053d4 100644 --- a/src/editor/CMakeLists.txt +++ b/src/editor/CMakeLists.txt @@ -33,6 +33,11 @@ endforeach() if (UNIX AND NOT APPLE AND NOT ANDROID) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'") endif() +# Need to reference the vulkan SDK for MacOS to search at runtime +if (APPLE) +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'/usr/local/lib'") +endif() + # We use the exported main file from the AtlasEngine library to able to use # the app class. Alternatively, you can write a main function yourself. # To export the main file the ATLAS_EXPORT_MAIN option has to be turned on. diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index 2688a2547..e603fd324 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -53,7 +53,7 @@ if(WIN32) set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SPIRV-Tools-opt volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator - unofficial::spirv-reflect glslang::SPIRV unofficial::joltphysics::Jolt + unofficial::spirv-reflect glslang::SPIRV Jolt::Jolt ${LUA_LIBRARIES} sol2 fsr2) endif() @@ -67,7 +67,7 @@ if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_MACOS_MVK -DVK_EXAMPLE_XCODE_GENERATED") set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static - volk::volk SPIRV-Tools-opt unofficial::joltphysics::Jolt fsr2 + volk::volk SPIRV-Tools-opt Jolt::Jolt fsr2 GPUOpen::VulkanMemoryAllocator Vulkan::Vulkan Vulkan::Headers unofficial::spirv-reflect glslang::SPIRV ${LUA_LIBRARIES} sol2) endif() @@ -92,7 +92,7 @@ if(UNIX AND NOT APPLE AND NOT ANDROID) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static fsr2 - volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator unofficial::joltphysics::Jolt + volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator Jolt::Jolt unofficial::spirv-reflect SPIRV-Tools-opt glslang::SPIRV ${LUA_LIBRARIES} sol2) endif() diff --git a/vcpkg.json b/vcpkg.json index e79971e89..4c8eb135d 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,9 +1,9 @@ { "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", "name": "atlas-engine", - "version-string": "0.2.0", + "version-string": "0.2.1", "port-version": 0, - "builtin-baseline": "821100d967e1737d96414a308e3f7cbe0d1abf18", + "builtin-baseline": "a993be073c6baea8674117f3eaed6e2d2486aaae", "homepage": "https://github.com/tippesi/Atlas-Engine", "description": "Cross platform toy render engine supporting physically based rendering and software ray tracing", "dependencies": [ @@ -84,7 +84,7 @@ }, { "name": "joltphysics", - "version": "5.0.0#1" + "version": "5.1.0" }, { "name": "lua", From c19db110171319e444b32d4ef37f7f6a59408f66 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 20 Aug 2024 21:38:18 +0200 Subject: [PATCH 06/66] Fix build pipelines --- .github/workflows/build.yml | 6 +++--- .github/workflows/release.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8cd079aca..65ba92def 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 # Committish: The commit sha of the vcpkg repo, same as in vcpkg.json with: - committish: 821100d967e1737d96414a308e3f7cbe0d1abf18 + committish: a993be073c6baea8674117f3eaed6e2d2486aaae cache: ${{ env.USE_CACHE }} # This doesn't work when the Visual Studio C++ CLI was set up first (maybe needs a setup with 2019 version) @@ -205,7 +205,7 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 # Committish: The commit sha of the vcpkg repo, same as in vcpkg.json with: - committish: 821100d967e1737d96414a308e3f7cbe0d1abf18 + committish: a993be073c6baea8674117f3eaed6e2d2486aaae cache: ${{ env.USE_CACHE }} - name: Setup Ninja @@ -335,7 +335,7 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 # Committish: The commit sha of the vcpkg repo, same as in vcpkg.json with: - committish: 821100d967e1737d96414a308e3f7cbe0d1abf18 + committish: a993be073c6baea8674117f3eaed6e2d2486aaae cache: ${{ env.USE_CACHE }} - name: Setup Ninja diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5bdedb294..be783ed8c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 # Committish: The commit sha of the vcpkg repo, same as in vcpkg.json with: - committish: 821100d967e1737d96414a308e3f7cbe0d1abf18 + committish: a993be073c6baea8674117f3eaed6e2d2486aaae - name: Delete MSVC tool version shell: pwsh @@ -109,7 +109,7 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 # Committish: The commit sha of the vcpkg repo, same as in vcpkg.json with: - committish: 821100d967e1737d96414a308e3f7cbe0d1abf18 + committish: a993be073c6baea8674117f3eaed6e2d2486aaae - name: Setup Ninja uses: ashutoshvarma/setup-ninja@master @@ -176,7 +176,7 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 # Committish: The commit sha of the vcpkg repo, same as in vcpkg.json with: - committish: 821100d967e1737d96414a308e3f7cbe0d1abf18 + committish: a993be073c6baea8674117f3eaed6e2d2486aaae cache: ${{ env.USE_CACHE }} - name: Setup Ninja From 569d1e7ccc5678924bfdd8603429b891c6381b62 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 22 Aug 2024 20:51:03 +0200 Subject: [PATCH 07/66] Some quality of life improvements --- data/scenes/sponza.aescene | 2 +- src/editor/App.cpp | 207 ++++++++++-------- src/editor/Notifications.cpp | 4 +- src/editor/Serialization.cpp | 2 + src/editor/ui/panels/ViewportPanel.cpp | 61 +++--- src/editor/ui/panels/ViewportPanel.h | 2 + src/editor/ui/windows/SceneWindow.cpp | 10 + src/editor/ui/windows/SceneWindow.h | 1 + src/engine/renderer/DirectLightRenderer.cpp | 4 +- .../scene/components/ComponentSerializer.cpp | 2 +- 10 files changed, 174 insertions(+), 121 deletions(-) diff --git a/data/scenes/sponza.aescene b/data/scenes/sponza.aescene index 9203f2724..0f5cc95e0 100644 --- a/data/scenes/sponza.aescene +++ b/data/scenes/sponza.aescene @@ -1 +1 @@ -{"aabb":{"max":{"x":128.0,"y":128.0,"z":128.0},"min":{"x":-128.0,"y":-128.0,"z":-128.0}},"ao":{"enable":false,"halfResolution":true,"opacityCheck":false,"radius":3.0,"rt":true,"sampleCount":16,"strength":1.0},"depth":5.0,"entities":[{"entities":[{"id":1,"light":{"color":{"x":1.0,"y":0.9254902005195618,"z":0.8196078538894653},"intensity":10.0,"isMain":true,"mobility":0,"properties":{"direction":{"x":0.0,"y":-1.0,"z":0.2800000011920929}},"shadow":{"allowDynamicEntities":false,"allowTerrain":true,"bias":0.800000011920929,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":75.0,"edgeSoftness":0.05000000074505806,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":2048,"splitCorrection":0.0,"useCubemap":false,"viewCount":1,"views":[{"farDistance":75.0,"frustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"nearDistance":0.0,"orthoSize":{"w":43.0,"x":-50.0,"y":50.0,"z":-41.0},"projectionMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.26962992548942566,"z":0.9629640579223633},"j2":{"w":0.0,"x":0.0,"y":0.9629640579223633,"z":-0.26962992548942566},"j3":{"w":1.0,"x":-0.0,"y":-0.0,"z":0.0}}}]},"type":0,"volumetric":true},"name":{"name":"Directional light"}},{"id":2,"mesh":{"dontCull":false,"resourcePath":"sponza/meshes/sponza.aemesh","visible":true},"name":{"name":"Sponza"},"rigidBody":{"bodyIndex":32,"creationSettings":{"angularDampening":0.0,"linearDampening":0.0,"shape":{"meshSettings":{"resourcePath":"sponza/meshes/sponza.aemesh","scale":{"x":0.012193998321890831,"y":0.012000000104308128,"z":0.012193998321890831}}}},"layer":0},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.012193998321890831,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":0.012000000104308128,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":0.012193998321890831},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}}}},{"id":3,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":0,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.000000238418579,"y":1.000000238418579,"z":1.000000238418579}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.4756948947906494,"y":0.00011953715875279158,"z":-0.8796106576919556},"j1":{"w":0.0,"x":0.5917145013809204,"y":-0.739871621131897,"z":-0.32010072469711304},"j2":{"w":0.0,"x":-0.6508373022079468,"y":-0.6727486252784729,"z":0.3518824875354767},"j3":{"w":1.0,"x":-15.995047569274902,"y":0.9694054126739502,"z":0.2113814800977707}}}},{"id":4,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Wall"},"rigidBody":{"bodyIndex":1,"creationSettings":{"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":1.0,"scale":{"x":0.1481112539768219,"y":0.17914418876171112,"z":2.874448299407959}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.12404608726501465,"y":-7.875383403188607e-07,"z":0.08092907071113586},"j1":{"w":0.0,"x":-6.167340416141087e-07,"y":0.17914418876171112,"z":2.688605945877498e-06},"j2":{"w":0.0,"x":-1.5706194639205933,"y":-4.1537619836162776e-05,"z":2.407406806945801},"j3":{"w":1.0,"x":7.4162163734436035,"y":-0.04500603675842285,"z":-0.9572893381118774}}}},{"id":5,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":2,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.9999986290931702,"y":0.9999986290931702,"z":0.9999986290931702}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.30071619153022766,"y":0.9535101652145386,"z":0.01963132992386818},"j1":{"w":0.0,"x":-0.02151578664779663,"y":-0.013796210289001465,"z":0.9996733665466309},"j2":{"w":0.0,"x":0.9534696936607361,"y":-0.3010404407978058,"z":0.016366761177778244},"j3":{"w":1.0,"x":4.233027935028076,"y":0.966492235660553,"z":1.2846850156784058}}}},{"id":6,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":3,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0475580133497715,"y":-8.188627589333919e-07,"z":0.06712339073419571},"j1":{"w":0.0,"x":-3.60343005922914e-06,"y":-0.1039920523762703,"z":1.2844517414123402e-06},"j2":{"w":0.0,"x":0.8159534335136414,"y":-3.541418118402362e-05,"z":-0.5781162977218628},"j3":{"w":1.0,"x":-9.601022720336914,"y":1.530970811843872,"z":-0.44825008511543274}}}},{"camera":{"aspectRatio":2.0,"exposure":1.0,"farPlane":400.0,"fieldOfView":55.20000076293945,"isMain":true,"location":{"x":0.0,"y":1.2000000476837158,"z":0.0},"nearPlane":1.0,"rotation":{"x":51.511505126953125,"y":0.15597067773342133},"thirdPerson":true,"thirdPersonDistance":3.0,"useEntityRotation":true,"useEntityTranslation":true},"id":7,"mesh":{"dontCull":false,"resourcePath":"meshes/capsule.aemesh","visible":true},"name":{"name":"Player"},"player":{"allowInput":true,"creationSettings":{"shape":{"capsuleShapeSettings":{"density":1.0,"height":1.2000000476837158,"radius":0.30000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"fastVelocity":4.0,"jumpVelocity":4.0,"slowVelocity":1.600000023841858},"text":{"halfSize":{"x":0.5,"y":1.0},"outlineColor":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"outlineFactor":0.0,"position":{"x":0.0,"y":1.600000023841858,"z":0.0},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"This is the player","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.07999999821186066},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-10.923478126525879,"y":-0.030071211978793144,"z":-1.5454801321029663}}}},{"audio":{"cutoff":0.0010000000474974513,"falloffFactor":0.10000000149011612,"falloffPower":2.0,"permanentPlay":false,"stream":{"loop":false,"pitch":1.0,"resourcePath":"/music.wav","time":0.0,"volume":0.0},"volume":1.0},"id":8,"name":{"name":"WelcomeText"},"text":{"halfSize":{"x":1.899999976158142,"y":1.0},"outlineColor":{"w":1.0,"x":1.0,"y":0.0,"z":0.0},"outlineFactor":0.15000000596046448,"position":{"x":0.0,"y":0.0,"z":1.2999999523162842},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"Welcome to this demo scene!","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.1899999976158142},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.01578390598297119,"y":0.00355260306969285,"z":0.9998670816421509},"j1":{"w":0.0,"x":0.40691956877708435,"y":0.9134560227394104,"z":0.003178075887262821},"j2":{"w":0.0,"x":-0.913324773311615,"y":0.4069172441959381,"z":-0.015863558277487755},"j3":{"w":1.0,"x":2.9802322387695313e-08,"y":4.168000221252441,"z":-0.02871951460838318}}}},{"entities":[{"id":10,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":4,"creationSettings":{"angularVelocity":{"x":0.3400594890117645,"y":0.002075438853353262,"z":-0.2711464762687683},"linearVelocity":{"x":0.027797559276223183,"y":-0.06926704198122025,"z":0.03678030148148537},"motionQuality":1,"objectLayer":1,"restitution":-0.0,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226305991411209,"y":0.10399112105369568,"z":0.24259740114212036}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.06749320030212402,"y":-0.0013515298487618566,"z":0.04701119661331177},"j1":{"w":0.0,"x":-0.05943548306822777,"y":-5.547449109144509e-05,"z":-0.08533213287591934},"j2":{"w":0.0,"x":0.003344531636685133,"y":-0.2425646185874939,"z":-0.0021718384232372046},"j3":{"w":1.0,"x":-6.993166923522949,"y":0.07752954214811325,"z":-0.49586528539657593}}}},{"id":11,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":5,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226487040519714,"y":0.10399449616670609,"z":1.000009298324585}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.001214503077790141,"y":4.0089940739562735e-05,"z":0.08225589245557785},"j1":{"w":0.0,"x":-0.10398011654615402,"y":-0.000795417174231261,"z":0.0015356455696746707},"j2":{"w":0.0,"x":0.0076551553793251514,"y":-0.9999799728393555,"z":0.00037435046397149563},"j3":{"w":1.0,"x":-0.18109244108200073,"y":1.1424553394317627,"z":-2.4032680988311768}}}},{"id":12,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":6,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399213433265686,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004975396674126387,"y":-3.6774740692635532e-06,"z":0.0821131020784378},"j1":{"w":0.0,"x":-0.10380175709724426,"y":-6.8306521825434174e-06,"z":-0.006289551965892315},"j2":{"w":0.0,"x":6.824726733611897e-05,"y":-0.9999992847442627,"z":-4.065033863298595e-05},"j3":{"w":1.0,"x":0.49817052483558655,"y":0.3519432246685028,"z":-2.3503992557525635}}}},{"id":13,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":7,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.10399220138788223,"z":0.9999990463256836}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006919844541698694,"y":0.0009341590339317918,"z":0.08196679502725601},"j1":{"w":0.0,"x":-0.10362283140420914,"y":-0.00030928864725865424,"z":0.008751623332500458},"j2":{"w":0.0,"x":0.003919091075658798,"y":-0.9999301433563232,"z":0.011065145023167133},"j3":{"w":1.0,"x":2.0737833976745605,"y":0.3635621964931488,"z":-1.7112125158309937}}}},{"id":14,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":8,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.10399205982685089,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.00037123600486665964,"y":-0.00020935118664056063,"z":0.08226258307695389},"j1":{"w":0.0,"x":-0.10399100184440613,"y":-7.686027743147861e-07,"z":0.000469290855107829},"j2":{"w":0.0,"x":-4.082914983882802e-06,"y":-0.9999959468841553,"z":-0.0025448778178542852},"j3":{"w":1.0,"x":3.7019379138946533,"y":0.35346531867980957,"z":-2.4043333530426025}}}},{"id":15,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":9,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.0822637677192688,"y":0.10399221628904343,"z":1.0000003576278687}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0014320656191557646,"y":-0.005514409858733416,"z":0.08206624537706375},"j1":{"w":0.0,"x":-0.1039608046412468,"y":-0.0019218007801100612,"z":0.0016850243555381894},"j2":{"w":0.0,"x":0.01734951324760914,"y":-0.9975799322128296,"z":-0.06733495742082596},"j3":{"w":1.0,"x":1.3664464950561523,"y":1.2094060182571411,"z":-2.3293323516845703}}}},{"id":16,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":10,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007250844966620207,"y":-0.00029188839835114777,"z":0.08194299042224884},"j1":{"w":0.0,"x":-0.10357026010751724,"y":0.0019194179913029075,"z":-0.009157725609838963},"j2":{"w":0.0,"x":-0.01807291805744171,"y":-0.9998225569725037,"z":-0.005160685162991285},"j3":{"w":1.0,"x":3.177853584289551,"y":1.137428641319275,"z":-2.286043643951416}}}},{"id":17,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":11,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999994039535522}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007074753753840923,"y":-0.0009124425705522299,"z":0.08195383846759796},"j1":{"w":0.0,"x":-0.10360674560070038,"y":2.178741397074191e-06,"z":-0.008943937718868256},"j2":{"w":0.0,"x":0.0009330803295597434,"y":-0.999937891960144,"z":-0.01105236355215311},"j3":{"w":1.0,"x":4.739034652709961,"y":1.1431937217712402,"z":-2.344177484512329}}}},{"id":18,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":12,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-2.9814507797709666e-05,"y":-0.00011468570301076397,"z":0.08226361125707626},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-5.103151488583535e-05,"z":-3.7763817090308294e-05},"j2":{"w":0.0,"x":0.0004912313306704164,"y":-0.9999982118606567,"z":-0.0013939131749793887},"j3":{"w":1.0,"x":5.269709587097168,"y":0.3537576496601105,"z":-2.396353006362915}}}},{"id":19,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":13,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226397633552551,"y":0.10399535298347473,"z":1.0000017881393433}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0029943662229925394,"y":-0.004902660381048918,"z":0.08206314593553543},"j1":{"w":0.0,"x":-0.1038932278752327,"y":-0.00239846995100379,"z":-0.0039341989904642105},"j2":{"w":0.0,"x":0.025261566042900085,"y":-0.9979578852653503,"z":-0.05869881808757782},"j3":{"w":1.0,"x":0.4539576470851898,"y":1.9912066459655762,"z":-2.3605332374572754}}}},{"id":20,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":14,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999991059303284}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0047220797277987,"y":-0.006254853215068579,"z":0.08188952505588531},"j1":{"w":0.0,"x":-0.10381996631622314,"y":0.000815314007923007,"z":-0.005924399942159653},"j2":{"w":0.0,"x":-0.0034728916361927986,"y":-0.9970735311508179,"z":-0.0763583704829216},"j3":{"w":1.0,"x":2.0099921226501465,"y":1.9823397397994995,"z":-2.1112253665924072}}}},{"id":21,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":15,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0015184117946773767,"y":-0.001873633824288845,"z":0.08222834020853043},"j1":{"w":0.0,"x":-0.10390593856573105,"y":0.0038146909791976213,"z":-0.0018317853100597858},"j2":{"w":0.0,"x":-0.036265525966882706,"y":-0.9990666508674622,"z":-0.02343420498073101},"j3":{"w":1.0,"x":3.611302614212036,"y":1.9326788187026978,"z":-2.369572162628174}}}},{"id":22,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":16,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370811462402,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0011607652995735407,"y":-0.005252636969089508,"z":0.08208763599395752},"j1":{"w":0.0,"x":-0.1039327085018158,"y":-0.003092399565503001,"z":-0.0016675429651513696},"j2":{"w":0.0,"x":0.03069702349603176,"y":-0.9975154995918274,"z":-0.06339509040117264},"j3":{"w":1.0,"x":0.911769449710846,"y":2.8139381408691406,"z":-2.3714351654052734}}}},{"id":23,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":17,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399208217859268,"z":0.9999986886978149}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.002328230533748865,"y":-0.01567736454308033,"z":0.08072245121002197},"j1":{"w":0.0,"x":-0.10387608408927917,"y":0.0032992407213896513,"z":0.0036367876455187798},"j2":{"w":0.0,"x":-0.03779618442058563,"y":-0.9811586737632751,"z":-0.189463809132576},"j3":{"w":1.0,"x":2.5983128547668457,"y":2.8227591514587402,"z":-2.0519001483917236}}}},{"id":24,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":18,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920449256897,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006420230958610773,"y":-0.0025190962478518486,"z":0.0819740742444992},"j1":{"w":0.0,"x":-0.10356941819190979,"y":0.004437707830220461,"z":0.008247951045632362},"j2":{"w":0.0,"x":-0.04495199769735336,"y":-0.9986188411712646,"z":-0.027167268097400665},"j3":{"w":1.0,"x":4.155186176300049,"y":2.7027957439422607,"z":-2.4178249835968018}}}},{"id":25,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":19,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999993443489075}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007614439819008112,"y":-0.014711390249431133,"z":0.08057859539985657},"j1":{"w":0.0,"x":-0.1032203733921051,"y":-0.006378653459250927,"z":-0.010918588377535343},"j2":{"w":0.0,"x":0.07885781675577164,"y":-0.9819651246070862,"z":-0.17182737588882446},"j3":{"w":1.0,"x":1.3723328113555908,"y":3.7512500286102295,"z":-2.243227481842041}}}},{"id":26,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":20,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.005531982518732548,"y":-0.015606719069182873,"z":0.08058004826307297},"j1":{"w":0.0,"x":-0.10365156084299088,"y":0.005922866519540548,"z":-0.005968747194856405},"j2":{"w":0.0,"x":-0.0449003241956234,"y":-0.9801850318908691,"z":-0.19292448461055756},"j3":{"w":1.0,"x":3.1063742637634277,"y":3.642221689224243,"z":-2.205120325088501}}}},{"id":27,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":21,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399164259433746,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.009233793243765831,"y":-2.8461645484867404e-08,"z":-0.08174382150173187},"j1":{"w":0.0,"x":5.111483005748596e-07,"y":-0.10399164259433746,"z":-2.153150546746474e-08},"j2":{"w":0.0,"x":-0.9936796426773071,"y":-4.907456968794577e-06,"z":0.11224624514579773},"j3":{"w":1.0,"x":5.397507667541504,"y":1.5309886932373047,"z":-0.8703097105026245}}}},{"id":28,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":22,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.004304870497435331,"y":-0.016259904950857162,"z":0.08052577078342438},"j1":{"w":0.0,"x":-0.10374186187982559,"y":0.0035653808154165745,"z":0.006265922449529171},"j2":{"w":0.0,"x":-0.04547032341361046,"y":-0.9796709418296814,"z":-0.19538608193397522},"j3":{"w":1.0,"x":3.7071003913879395,"y":4.404808521270752,"z":-2.0641326904296875}}}},{"id":29,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":23,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226374536752701,"y":0.1039920300245285,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004521988797932863,"y":-0.014796562492847443,"z":0.08079565316438675},"j1":{"w":0.0,"x":-0.10348106175661087,"y":-0.007410035468637943,"z":-0.0071486919187009335},"j2":{"w":0.0,"x":0.0823487713932991,"y":-0.9811068177223206,"z":-0.17506666481494904},"j3":{"w":1.0,"x":1.740257740020752,"y":4.569649696350098,"z":-2.0765440464019775}}}},{"id":30,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":24,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"script":{"permanentExecution":false,"resourcePath":"scripts/example.lua","scriptProperties":{"duplicateEntityName":{"type":"string","value":""}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0822434350848198,"y":-3.559059393865027e-07,"z":-0.0018298403592780232},"j1":{"w":0.0,"x":6.938781211829337e-07,"y":0.1486254185438156,"z":2.2790266029915074e-06},"j2":{"w":0.0,"x":0.021798700094223022,"y":-1.5125399841053877e-05,"z":0.97975754737854},"j3":{"w":1.0,"x":-0.42584455013275146,"y":-0.042439818382263184,"z":0.7894344925880432}}}},{"id":31,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":25,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226378262042999,"y":0.015076023526489735,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.07320480048656464,"y":4.977956632501446e-05,"z":-0.03752845898270607},"j1":{"w":0.0,"x":0.006859811022877693,"y":-0.0011024783598259091,"z":0.013379612006247044},"j2":{"w":0.0,"x":-0.032167207449674606,"y":-0.9773759245872498,"z":-0.0640433058142662},"j3":{"w":1.0,"x":2.4300098419189453,"y":0.3631786108016968,"z":1.207587718963623}}}},{"id":32,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":26,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.06837532669305801,"y":-0.0017373006558045745,"z":-0.04570697247982025},"j1":{"w":0.0,"x":0.05685741454362869,"y":0.11100539565086365,"z":0.08083657920360565},"j2":{"w":0.0,"x":0.39542150497436523,"y":-0.6513306498527527,"z":0.6162874698638916},"j3":{"w":1.0,"x":3.135746955871582,"y":0.2095150351524353,"z":-1.027677297592163}}}},{"id":33,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":27,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000786781311}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0716107115149498,"y":-4.5638077494913887e-07,"z":-0.040487490594387054},"j1":{"w":0.0,"x":0.0005247447988949716,"y":0.14862160384655,"z":0.0009264472755603492},"j2":{"w":0.0,"x":0.4823108911514282,"y":-0.007020606193691492,"z":0.8530691862106323},"j3":{"w":1.0,"x":2.5021331310272217,"y":-0.04527640342712402,"z":0.6787291169166565}}}}],"id":9,"name":{"name":"Staircase"},"root":false},{"id":34,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":28,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-3.9226383705681656e-06,"y":0.0,"z":0.08226368576288223},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-2.479363736540563e-08,"z":-4.958727458870271e-06},"j2":{"w":0.0,"x":2.384183801495965e-07,"y":-0.9999991655349731,"z":0.0},"j3":{"w":1.0,"x":3.1176745891571045,"y":5.388330459594727,"z":-4.729436874389648}}}},{"entities":[{"entities":[{"id":37,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":31,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000007152557373,"y":1.0000007152557373,"z":1.0000007152557373}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.9554479122161865,"y":0.034463346004486084,"z":0.29313671588897705},"j1":{"w":0.0,"x":-0.09065454453229904,"y":0.9794178605079651,"z":0.18033018708229065},"j2":{"w":0.0,"x":-0.28088951110839844,"y":-0.19888851046562195,"z":0.9386930465698242},"j3":{"w":0.999999463558197,"x":-1.679502010345459,"y":-0.44969987869262695,"z":6.6491780281066895}}}}],"id":36,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":30,"creationSettings":{"angularVelocity":{"x":-0.003580757649615407,"y":-0.0010163785191252828,"z":-0.001152479788288474},"linearVelocity":{"x":0.0011589848436415195,"y":-0.276141881942749,"z":-0.003600968746468425},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000016689300537,"y":1.0000016689300537,"z":1.0000016689300537}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.7511749267578125,"y":0.22571837902069092,"z":-0.6203151345252991},"j1":{"w":0.0,"x":-0.39222919940948486,"y":0.6032152771949768,"z":0.6944692730903625},"j2":{"w":0.0,"x":0.5309374332427979,"y":0.7649720907211304,"z":-0.3645859360694885},"j3":{"w":1.0,"x":-11.712557792663574,"y":4.754024505615234,"z":-4.003259658813477}}}}],"id":35,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":29,"creationSettings":{"angularVelocity":{"x":0.16539807617664337,"y":0.1814352571964264,"z":-0.11671467125415802},"linearVelocity":{"x":0.11671468615531921,"y":2.4347741600649897e-09,"z":0.16539809107780457},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.6672989130020142,"y":0.0363946259021759,"z":0.7439002990722656},"j1":{"w":0.0,"x":0.5453938245773315,"y":0.7040697336196899,"z":0.45478731393814087},"j2":{"w":0.0,"x":-0.5072058439254761,"y":0.7091977000236511,"z":-0.48967432975769043},"j3":{"w":1.0,"x":-12.277113914489746,"y":0.9699291586875916,"z":-0.5359781384468079}}}},{"id":38,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":9.527641296386719,"z":0.0}}}},{"id":39,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-5.397964000701904,"y":12.993012428283691,"z":0.0}}}},{"id":40,"light":{"color":{"x":1.0,"y":1.0,"z":1.0},"intensity":1.0,"isMain":false,"mobility":1,"properties":{"attenuation":1.0,"position":{"x":0.0,"y":0.0,"z":0.0},"radius":10.0},"shadow":{"allowDynamicEntities":false,"allowTerrain":false,"bias":0.10000000149011612,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":0.0,"edgeSoftness":0.0,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":1024,"splitCorrection":0.8999999761581421,"useCubemap":true,"viewCount":6,"views":[{"farDistance":0.0,"frustumMatrix":{"j0":{"w":1.0,"x":0.0,"y":0.0,"z":1.0020020008087158},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":0.0,"x":-1.0,"y":0.0,"z":0.0},"j3":{"w":0.4823928773403168,"x":-0.8340781927108765,"y":0.8387702107429504,"z":0.46333861351013184}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":0.0,"y":0.0,"z":-1.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j3":{"w":1.0,"x":-0.8340781927108765,"y":0.8387702107429504,"z":-0.4823928773403168}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j3":{"w":-0.4823928773403168,"x":0.8340781927108765,"y":0.8387702107429504,"z":-0.5033786296844482}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j3":{"w":1.0,"x":0.8340781927108765,"y":0.8387702107429504,"z":0.4823928773403168}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":1.0,"x":0.0,"y":0.0,"z":1.0020020008087158},"j2":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j3":{"w":-0.8387702107429504,"x":0.4823928773403168,"y":0.8340781927108765,"z":-0.8604694604873657}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.0,"z":-1.0},"j2":{"w":0.0,"x":0.0,"y":1.0,"z":-0.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":0.8340781927108765,"z":0.8387702107429504}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j2":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j3":{"w":0.8387702107429504,"x":0.4823928773403168,"y":-0.8340781927108765,"z":0.8204294443130493}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j2":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":-0.8340781927108765,"z":-0.8387702107429504}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":1.0,"x":0.0,"y":0.0,"z":1.0020020008087158},"j3":{"w":0.8340781927108765,"x":0.4823928773403168,"y":0.8387702107429504,"z":0.8157280087471008}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-0.0,"y":0.0,"z":-1.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":0.8387702107429504,"z":-0.8340781927108765}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":-0.8340781927108765,"x":-0.4823928773403168,"y":0.8387702107429504,"z":-0.8557680249214172}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.0020020008087158},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0200200192630291}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":-0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-0.4823928773403168,"y":0.8387702107429504,"z":0.8340781927108765}}}]},"type":1,"volumetric":true},"name":{"name":"Point light"},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-0.4823928773403168,"y":0.8387702107429504,"z":-0.8340781927108765}}}}],"id":0,"name":{"name":"Root"},"root":false}],"fog":{"ambientFactor":0.009999999776482582,"density":0.0005000000237487257,"enable":true,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"height":0.0,"heightFalloff":0.0284000001847744,"rayMarchStepCount":10,"rayMarching":true,"scatteringAnisotropy":-0.6000000238418579,"scatteringFactor":2.0,"volumetricIntensity":1.0},"irradianceVolume":{"aabb":{"max":{"x":38.237998962402344,"y":18.340999603271484,"z":31.85099983215332},"min":{"x":-38.63600158691406,"y":-9.817999839782715,"z":-21.163000106811523}},"bias":0.30000001192092896,"cascadeCount":1,"enable":true,"gamma":5.0,"hysteresis":0.9800000190734863,"lowerResMoments":true,"opacityCheck":false,"optimizeProbes":true,"probeCount":{"x":20,"y":20,"z":20},"rayCount":100,"rayCountInactive":32,"sampleEmissives":false,"scroll":false,"sharpness":50.0,"splitCorrection":2.0,"strength":1.0,"useShadowMap":false},"name":"sponza","physicsWorld":null,"postProcessing":{"chromaticAberration":{"colorsReversed":false,"enable":false,"strength":1.0},"contrast":1.0,"filmGrain":{"enable":false,"strength":0.10000000149011612},"filmicTonemapping":false,"fsr2":true,"paperWhiteLuminance":150.0,"saturation":1.0,"screenMaxLuminance":1600.0,"sharpen":{"enable":true,"factor":0.15000000596046448},"taa":{"enable":true,"jitterRange":0.9900000095367432},"tint":{"x":1.0,"y":1.0,"z":1.0},"vignette":{"color":{"x":0.0,"y":0.0,"z":0.0},"enable":false,"offset":0.0,"power":0.0,"strength":0.0}},"reflection":{"bias":0.0,"currentClipFactor":2.0,"ddgi":true,"enable":true,"halfResolution":true,"historyClipMax":1.0,"opacityCheck":false,"radianceLimit":10.0,"roughnessCutoff":0.8999999761581421,"rt":true,"spatialFilterStrength":5.234000205993652,"temporalWeight":0.9520000219345093,"textureLevel":4,"useNormalMaps":true,"useShadowMap":false},"sky":{"atmosphere":{"height":100000.0,"mieHeightScale":1200.0,"mieScatteringCoeff":2.099999983329326e-05,"probeResolution":128,"rayleighHeightScale":8000.0,"rayleighScatteringCoeff":{"x":5.500000042957254e-06,"y":1.2999999853491317e-05,"z":2.2399999579647556e-05}},"clouds":{"castShadow":false,"coverageResolution":512,"coverageScale":0.25,"coverageSpeed":5.0,"darkEdgeAmbient":0.10000000149011612,"darkEdgeFocus":2.0,"densityMultiplier":0.800000011920929,"detailResolution":32,"detailScale":16.0,"detailSpeed":10.0,"detailStrength":0.15000000596046448,"distanceLimit":8000.0,"enable":true,"halfResolution":true,"heightStretch":0.5,"maxHeight":1700.0,"minHeight":1400.0,"occlusionSampleCount":5,"sampleCount":64,"scattering":{"eccentricityFirstPhase":0.0,"eccentricitySecondPhase":-0.5,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"phaseAlpha":0.5,"scatteringFactor":2.0},"shadowResolution":512,"shadowSampleFraction":4,"shapeResolution":128,"shapeScale":2.0,"shapeSpeed":5.0,"stochasticOcclusionSampling":true},"intensity":1.0,"planetCenter":{"x":0.0,"y":-650000.0,"z":0.0},"planetRadius":649000.0},"ssgi":{"aoStrength":1.0,"enable":true,"enableAo":true,"halfResolution":true,"irradianceLimit":10.0,"radius":1.0,"rayCount":2,"sampleCount":8},"sss":{"enable":true,"maxLength":0.4970000088214874,"sampleCount":8,"thickness":0.30000001192092896},"wind":{"direction":{"x":1.0,"y":1.0},"speed":10.0}} \ No newline at end of file +{"aabb":{"max":{"x":128.0,"y":128.0,"z":128.0},"min":{"x":-128.0,"y":-128.0,"z":-128.0}},"ao":{"enable":false,"halfResolution":true,"opacityCheck":false,"radius":3.0,"rt":true,"sampleCount":16,"strength":1.0},"depth":5.0,"entities":[{"entities":[{"id":1,"light":{"color":{"x":1.0,"y":0.9254902005195618,"z":0.8196078538894653},"intensity":10.0,"isMain":true,"mobility":1,"properties":{"direction":{"x":0.0,"y":-1.0,"z":0.2800000011920929}},"shadow":{"allowDynamicEntities":false,"allowTerrain":true,"bias":0.800000011920929,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":75.0,"edgeSoftness":0.05000000074505806,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":2048,"splitCorrection":0.8999999761581421,"useCubemap":false,"viewCount":1,"views":[{"farDistance":75.0,"frustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"nearDistance":0.0,"orthoSize":{"w":43.0,"x":-50.0,"y":50.0,"z":-41.0},"projectionMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.26962992548942566,"z":0.9629640579223633},"j2":{"w":0.0,"x":0.0,"y":0.9629640579223633,"z":-0.26962992548942566},"j3":{"w":1.0,"x":-0.0,"y":-0.0,"z":0.0}}}]},"type":0,"volumetric":true},"name":{"name":"Directional light"}},{"id":2,"mesh":{"dontCull":false,"resourcePath":"sponza/meshes/sponza.aemesh","visible":true},"name":{"name":"Sponza"},"rigidBody":{"bodyIndex":0,"creationSettings":{"angularDampening":0.0,"linearDampening":0.0,"shape":{"meshSettings":{"resourcePath":"sponza/meshes/sponza.aemesh","scale":{"x":0.012193998321890831,"y":0.012000000104308128,"z":0.012193998321890831}}}},"layer":0},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.012193998321890831,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":0.012000000104308128,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":0.012193998321890831},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}}}},{"id":3,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":1,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.09999998658895493,"y":0.09999998658895493,"z":0.09999998658895493}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.047569502145051956,"y":1.195073127746582e-05,"z":-0.08796101808547974},"j1":{"w":0.0,"x":0.05917143449187279,"y":-0.07398712635040283,"z":-0.03201008588075638},"j2":{"w":0.0,"x":-0.06508366018533707,"y":-0.06727483868598938,"z":0.03518824651837349},"j3":{"w":1.0,"x":-15.995047569274902,"y":0.9694054126739502,"z":0.2113814800977707}}}},{"id":4,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Wall"},"rigidBody":{"bodyIndex":2,"creationSettings":{"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":1.0,"scale":{"x":0.1481112539768219,"y":0.17914418876171112,"z":2.874448299407959}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.12404608726501465,"y":-7.875383403188607e-07,"z":0.08092907071113586},"j1":{"w":0.0,"x":-6.167340416141087e-07,"y":0.17914418876171112,"z":2.688605945877498e-06},"j2":{"w":0.0,"x":-1.5706194639205933,"y":-4.1537619836162776e-05,"z":2.407406806945801},"j3":{"w":1.0,"x":7.4162163734436035,"y":-0.04500603675842285,"z":-0.9572893381118774}}}},{"id":5,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":3,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.9999986290931702,"y":0.9999986290931702,"z":0.9999986290931702}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.30071619153022766,"y":0.9535101652145386,"z":0.01963132992386818},"j1":{"w":0.0,"x":-0.02151578664779663,"y":-0.013796210289001465,"z":0.9996733665466309},"j2":{"w":0.0,"x":0.9534696936607361,"y":-0.3010404407978058,"z":0.016366761177778244},"j3":{"w":1.0,"x":4.233027935028076,"y":0.966492235660553,"z":1.2846850156784058}}}},{"camera":{"aspectRatio":2.0,"exposure":1.0,"farPlane":400.0,"fieldOfView":55.20000076293945,"isMain":true,"location":{"x":0.0,"y":1.2000000476837158,"z":0.0},"nearPlane":1.0,"rotation":{"x":51.511505126953125,"y":0.15597067773342133},"thirdPerson":true,"thirdPersonDistance":3.0,"useEntityRotation":true,"useEntityTranslation":true},"id":6,"mesh":{"dontCull":false,"resourcePath":"meshes/capsule.aemesh","visible":true},"name":{"name":"Player"},"player":{"allowInput":true,"creationSettings":{"shape":{"capsuleShapeSettings":{"density":1.0,"height":1.2000000476837158,"radius":0.30000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"fastVelocity":4.0,"jumpVelocity":4.0,"slowVelocity":1.600000023841858},"text":{"halfSize":{"x":0.5,"y":1.0},"outlineColor":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"outlineFactor":0.0,"position":{"x":0.0,"y":1.600000023841858,"z":0.0},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"This is the player","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.07999999821186066},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-10.923478126525879,"y":-0.030071211978793144,"z":-1.5454801321029663}}}},{"audio":{"cutoff":0.0010000000474974513,"falloffFactor":0.10000000149011612,"falloffPower":2.0,"permanentPlay":false,"stream":{"loop":false,"pitch":1.0,"resourcePath":"/music.wav","time":0.0,"volume":0.0},"volume":1.0},"id":7,"name":{"name":"WelcomeText"},"text":{"halfSize":{"x":1.899999976158142,"y":1.0},"outlineColor":{"w":1.0,"x":1.0,"y":0.0,"z":0.0},"outlineFactor":0.15000000596046448,"position":{"x":0.0,"y":0.0,"z":1.2999999523162842},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"Welcome to this demo scene!","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.1899999976158142},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.01578390598297119,"y":0.00355260306969285,"z":0.9998670816421509},"j1":{"w":0.0,"x":0.40691956877708435,"y":0.9134560227394104,"z":0.003178075887262821},"j2":{"w":0.0,"x":-0.913324773311615,"y":0.4069172441959381,"z":-0.015863558277487755},"j3":{"w":1.0,"x":2.9802322387695313e-08,"y":4.168000221252441,"z":-0.02871951460838318}}}},{"entities":[{"id":9,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":4,"creationSettings":{"angularVelocity":{"x":0.3400594890117645,"y":0.002075438853353262,"z":-0.2711464762687683},"linearVelocity":{"x":0.027797559276223183,"y":-0.06926704198122025,"z":0.03678030148148537},"motionQuality":1,"objectLayer":1,"restitution":-0.0,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226305991411209,"y":0.10399112105369568,"z":0.24259740114212036}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.06749320030212402,"y":-0.0013515298487618566,"z":0.04701119661331177},"j1":{"w":0.0,"x":-0.05943548306822777,"y":-5.547449109144509e-05,"z":-0.08533213287591934},"j2":{"w":0.0,"x":0.003344531636685133,"y":-0.2425646185874939,"z":-0.0021718384232372046},"j3":{"w":1.0,"x":-6.993166923522949,"y":0.07752954214811325,"z":-0.49586528539657593}}}},{"id":10,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":5,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226487040519714,"y":0.10399449616670609,"z":1.000009298324585}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.001214503077790141,"y":4.0089940739562735e-05,"z":0.08225589245557785},"j1":{"w":0.0,"x":-0.10398011654615402,"y":-0.000795417174231261,"z":0.0015356455696746707},"j2":{"w":0.0,"x":0.0076551553793251514,"y":-0.9999799728393555,"z":0.00037435046397149563},"j3":{"w":1.0,"x":-0.18109244108200073,"y":1.1424553394317627,"z":-2.4032680988311768}}}},{"id":11,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":6,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399213433265686,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004975396674126387,"y":-3.6774740692635532e-06,"z":0.0821131020784378},"j1":{"w":0.0,"x":-0.10380175709724426,"y":-6.8306521825434174e-06,"z":-0.006289551965892315},"j2":{"w":0.0,"x":6.824726733611897e-05,"y":-0.9999992847442627,"z":-4.065033863298595e-05},"j3":{"w":1.0,"x":0.49817052483558655,"y":0.3519432246685028,"z":-2.3503992557525635}}}},{"id":12,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":7,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.10399220138788223,"z":0.9999990463256836}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006919844541698694,"y":0.0009341590339317918,"z":0.08196679502725601},"j1":{"w":0.0,"x":-0.10362283140420914,"y":-0.00030928864725865424,"z":0.008751623332500458},"j2":{"w":0.0,"x":0.003919091075658798,"y":-0.9999301433563232,"z":0.011065145023167133},"j3":{"w":1.0,"x":2.0737833976745605,"y":0.3635621964931488,"z":-1.7112125158309937}}}},{"id":13,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":8,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.10399205982685089,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.00037123600486665964,"y":-0.00020935118664056063,"z":0.08226258307695389},"j1":{"w":0.0,"x":-0.10399100184440613,"y":-7.686027743147861e-07,"z":0.000469290855107829},"j2":{"w":0.0,"x":-4.082914983882802e-06,"y":-0.9999959468841553,"z":-0.0025448778178542852},"j3":{"w":1.0,"x":3.7019379138946533,"y":0.35346531867980957,"z":-2.4043333530426025}}}},{"id":14,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":9,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.0822637677192688,"y":0.10399221628904343,"z":1.0000003576278687}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0014320656191557646,"y":-0.005514409858733416,"z":0.08206624537706375},"j1":{"w":0.0,"x":-0.1039608046412468,"y":-0.0019218007801100612,"z":0.0016850243555381894},"j2":{"w":0.0,"x":0.01734951324760914,"y":-0.9975799322128296,"z":-0.06733495742082596},"j3":{"w":1.0,"x":1.3664464950561523,"y":1.2094060182571411,"z":-2.3293323516845703}}}},{"id":15,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":10,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007250844966620207,"y":-0.00029188839835114777,"z":0.08194299042224884},"j1":{"w":0.0,"x":-0.10357026010751724,"y":0.0019194179913029075,"z":-0.009157725609838963},"j2":{"w":0.0,"x":-0.01807291805744171,"y":-0.9998225569725037,"z":-0.005160685162991285},"j3":{"w":1.0,"x":3.177853584289551,"y":1.137428641319275,"z":-2.286043643951416}}}},{"id":16,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":11,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999994039535522}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007074753753840923,"y":-0.0009124425705522299,"z":0.08195383846759796},"j1":{"w":0.0,"x":-0.10360674560070038,"y":2.178741397074191e-06,"z":-0.008943937718868256},"j2":{"w":0.0,"x":0.0009330803295597434,"y":-0.999937891960144,"z":-0.01105236355215311},"j3":{"w":1.0,"x":4.739034652709961,"y":1.1431937217712402,"z":-2.344177484512329}}}},{"id":17,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":12,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-2.9814507797709666e-05,"y":-0.00011468570301076397,"z":0.08226361125707626},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-5.103151488583535e-05,"z":-3.7763817090308294e-05},"j2":{"w":0.0,"x":0.0004912313306704164,"y":-0.9999982118606567,"z":-0.0013939131749793887},"j3":{"w":1.0,"x":5.269709587097168,"y":0.3537576496601105,"z":-2.396353006362915}}}},{"id":18,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":13,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226397633552551,"y":0.10399535298347473,"z":1.0000017881393433}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0029943662229925394,"y":-0.004902660381048918,"z":0.08206314593553543},"j1":{"w":0.0,"x":-0.1038932278752327,"y":-0.00239846995100379,"z":-0.0039341989904642105},"j2":{"w":0.0,"x":0.025261566042900085,"y":-0.9979578852653503,"z":-0.05869881808757782},"j3":{"w":1.0,"x":0.4539576470851898,"y":1.9912066459655762,"z":-2.3605332374572754}}}},{"id":19,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":14,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999991059303284}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0047220797277987,"y":-0.006254853215068579,"z":0.08188952505588531},"j1":{"w":0.0,"x":-0.10381996631622314,"y":0.000815314007923007,"z":-0.005924399942159653},"j2":{"w":0.0,"x":-0.0034728916361927986,"y":-0.9970735311508179,"z":-0.0763583704829216},"j3":{"w":1.0,"x":2.0099921226501465,"y":1.9823397397994995,"z":-2.1112253665924072}}}},{"id":20,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":15,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0015184117946773767,"y":-0.001873633824288845,"z":0.08222834020853043},"j1":{"w":0.0,"x":-0.10390593856573105,"y":0.0038146909791976213,"z":-0.0018317853100597858},"j2":{"w":0.0,"x":-0.036265525966882706,"y":-0.9990666508674622,"z":-0.02343420498073101},"j3":{"w":1.0,"x":3.611302614212036,"y":1.9326788187026978,"z":-2.369572162628174}}}},{"id":21,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":16,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370811462402,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0011607652995735407,"y":-0.005252636969089508,"z":0.08208763599395752},"j1":{"w":0.0,"x":-0.1039327085018158,"y":-0.003092399565503001,"z":-0.0016675429651513696},"j2":{"w":0.0,"x":0.03069702349603176,"y":-0.9975154995918274,"z":-0.06339509040117264},"j3":{"w":1.0,"x":0.911769449710846,"y":2.8139381408691406,"z":-2.3714351654052734}}}},{"id":22,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":17,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399208217859268,"z":0.9999986886978149}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.002328230533748865,"y":-0.01567736454308033,"z":0.08072245121002197},"j1":{"w":0.0,"x":-0.10387608408927917,"y":0.0032992407213896513,"z":0.0036367876455187798},"j2":{"w":0.0,"x":-0.03779618442058563,"y":-0.9811586737632751,"z":-0.189463809132576},"j3":{"w":1.0,"x":2.5983128547668457,"y":2.8227591514587402,"z":-2.0519001483917236}}}},{"id":23,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":18,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920449256897,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006420230958610773,"y":-0.0025190962478518486,"z":0.0819740742444992},"j1":{"w":0.0,"x":-0.10356941819190979,"y":0.004437707830220461,"z":0.008247951045632362},"j2":{"w":0.0,"x":-0.04495199769735336,"y":-0.9986188411712646,"z":-0.027167268097400665},"j3":{"w":1.0,"x":4.155186176300049,"y":2.7027957439422607,"z":-2.4178249835968018}}}},{"id":24,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":19,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999993443489075}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007614439819008112,"y":-0.014711390249431133,"z":0.08057859539985657},"j1":{"w":0.0,"x":-0.1032203733921051,"y":-0.006378653459250927,"z":-0.010918588377535343},"j2":{"w":0.0,"x":0.07885781675577164,"y":-0.9819651246070862,"z":-0.17182737588882446},"j3":{"w":1.0,"x":1.3723328113555908,"y":3.7512500286102295,"z":-2.243227481842041}}}},{"id":25,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":20,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.005531982518732548,"y":-0.015606719069182873,"z":0.08058004826307297},"j1":{"w":0.0,"x":-0.10365156084299088,"y":0.005922866519540548,"z":-0.005968747194856405},"j2":{"w":0.0,"x":-0.0449003241956234,"y":-0.9801850318908691,"z":-0.19292448461055756},"j3":{"w":1.0,"x":3.1063742637634277,"y":3.642221689224243,"z":-2.205120325088501}}}},{"id":26,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":21,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399164259433746,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.009233793243765831,"y":-2.8461645484867404e-08,"z":-0.08174382150173187},"j1":{"w":0.0,"x":5.111483005748596e-07,"y":-0.10399164259433746,"z":-2.153150546746474e-08},"j2":{"w":0.0,"x":-0.9936796426773071,"y":-4.907456968794577e-06,"z":0.11224624514579773},"j3":{"w":1.0,"x":5.397507667541504,"y":1.5309886932373047,"z":-0.8703097105026245}}}},{"id":27,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":22,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.004304870497435331,"y":-0.016259904950857162,"z":0.08052577078342438},"j1":{"w":0.0,"x":-0.10374186187982559,"y":0.0035653808154165745,"z":0.006265922449529171},"j2":{"w":0.0,"x":-0.04547032341361046,"y":-0.9796709418296814,"z":-0.19538608193397522},"j3":{"w":1.0,"x":3.7071003913879395,"y":4.404808521270752,"z":-2.0641326904296875}}}},{"id":28,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":23,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226374536752701,"y":0.1039920300245285,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004521988797932863,"y":-0.014796562492847443,"z":0.08079565316438675},"j1":{"w":0.0,"x":-0.10348106175661087,"y":-0.007410035468637943,"z":-0.0071486919187009335},"j2":{"w":0.0,"x":0.0823487713932991,"y":-0.9811068177223206,"z":-0.17506666481494904},"j3":{"w":1.0,"x":1.740257740020752,"y":4.569649696350098,"z":-2.0765440464019775}}}},{"id":29,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":24,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"script":{"permanentExecution":false,"resourcePath":"scripts/example.lua","scriptProperties":{"duplicateEntityName":{"type":"string","value":""}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0822434350848198,"y":-3.559059393865027e-07,"z":-0.0018298403592780232},"j1":{"w":0.0,"x":6.938781211829337e-07,"y":0.1486254185438156,"z":2.2790266029915074e-06},"j2":{"w":0.0,"x":0.021798700094223022,"y":-1.5125399841053877e-05,"z":0.97975754737854},"j3":{"w":1.0,"x":-0.42584455013275146,"y":-0.042439818382263184,"z":0.7894344925880432}}}},{"id":30,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":25,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226378262042999,"y":0.015076023526489735,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.07320480048656464,"y":4.977956632501446e-05,"z":-0.03752845898270607},"j1":{"w":0.0,"x":0.006859811022877693,"y":-0.0011024783598259091,"z":0.013379612006247044},"j2":{"w":0.0,"x":-0.032167207449674606,"y":-0.9773759245872498,"z":-0.0640433058142662},"j3":{"w":1.0,"x":2.4300098419189453,"y":0.3631786108016968,"z":1.207587718963623}}}},{"id":31,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":26,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.06837532669305801,"y":-0.0017373006558045745,"z":-0.04570697247982025},"j1":{"w":0.0,"x":0.05685741454362869,"y":0.11100539565086365,"z":0.08083657920360565},"j2":{"w":0.0,"x":0.39542150497436523,"y":-0.6513306498527527,"z":0.6162874698638916},"j3":{"w":1.0,"x":3.135746955871582,"y":0.2095150351524353,"z":-1.027677297592163}}}},{"id":32,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":27,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000786781311}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0716107115149498,"y":-4.5638077494913887e-07,"z":-0.040487490594387054},"j1":{"w":0.0,"x":0.0005247447988949716,"y":0.14862160384655,"z":0.0009264472755603492},"j2":{"w":0.0,"x":0.4823108911514282,"y":-0.007020606193691492,"z":0.8530691862106323},"j3":{"w":1.0,"x":2.5021331310272217,"y":-0.04527640342712402,"z":0.6787291169166565}}}}],"id":8,"name":{"name":"Staircase"},"root":false},{"id":33,"mesh":{"dontCull":false,"resourcePath":"meshes/metallicwall.aemesh","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":28,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-3.9226383705681656e-06,"y":0.0,"z":0.08226368576288223},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-2.479363736540563e-08,"z":-4.958727458870271e-06},"j2":{"w":0.0,"x":2.384183801495965e-07,"y":-0.9999991655349731,"z":0.0},"j3":{"w":1.0,"x":3.1176745891571045,"y":5.388330459594727,"z":-4.729436874389648}}}},{"entities":[{"entities":[{"id":36,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":31,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.10000021010637283,"y":0.10000021010637283,"z":0.10000021010637283}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.9554491639137268,"y":0.03446396440267563,"z":0.2931367754936218},"j1":{"w":0.0,"x":-0.09065470844507217,"y":0.9794172048568726,"z":0.18032999336719513},"j2":{"w":0.0,"x":-0.28088951110839844,"y":-0.19888849556446075,"z":0.9386932849884033},"j3":{"w":0.9999988675117493,"x":-1.6799697875976563,"y":-0.4502716064453125,"z":6.649372100830078}}}}],"id":35,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":30,"creationSettings":{"angularVelocity":{"x":-0.003580757649615407,"y":-0.0010163785191252828,"z":-0.001152479788288474},"linearVelocity":{"x":0.0011589848436415195,"y":-0.276141881942749,"z":-0.003600968746468425},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.10000015050172806,"y":0.10000015050172806,"z":0.10000015050172806}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.751175045967102,"y":0.22571831941604614,"z":-0.6203150749206543},"j1":{"w":0.0,"x":-0.39222919940948486,"y":0.6032153367996216,"z":0.6944690942764282},"j2":{"w":0.0,"x":0.5309373736381531,"y":0.7649720311164856,"z":-0.3645856976509094},"j3":{"w":1.0,"x":-11.712562561035156,"y":4.7540283203125,"z":-4.003265380859375}}}}],"id":34,"mesh":{"dontCull":false,"resourcePath":"meshes/chromesphere.aemesh","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":29,"creationSettings":{"angularVelocity":{"x":0.16539807617664337,"y":0.1814352571964264,"z":-0.11671467125415802},"linearVelocity":{"x":0.11671468615531921,"y":2.4347741600649897e-09,"z":0.16539809107780457},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.09999997913837433,"y":0.09999997913837433,"z":0.09999997913837433}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.06672985851764679,"y":0.0036394596099853516,"z":0.07439003139734268},"j1":{"w":0.0,"x":0.054539382457733154,"y":0.070406973361969,"z":0.045478712767362595},"j2":{"w":0.0,"x":-0.05072058364748955,"y":0.07091975212097168,"z":-0.0489673987030983},"j3":{"w":1.0,"x":-12.277113914489746,"y":0.9699291586875916,"z":-0.5359781384468079}}}},{"id":37,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":9.527641296386719,"z":0.0}}}},{"id":38,"name":{"name":"Entity 39"},"script":{"permanentExecution":false,"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-5.397964000701904,"y":12.993012428283691,"z":0.0}}}},{"id":39,"light":{"color":{"x":1.0,"y":1.0,"z":1.0},"intensity":1.0,"isMain":false,"mobility":1,"properties":{"attenuation":1.0,"position":{"x":0.0,"y":0.0,"z":0.0},"radius":10.0},"shadow":{"allowDynamicEntities":false,"allowTerrain":false,"bias":0.4000000059604645,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":0.0,"edgeSoftness":0.0,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":1024,"splitCorrection":0.8999999761581421,"useCubemap":true,"viewCount":6,"views":[{"farDistance":0.0,"frustumMatrix":{"j0":{"w":1.0,"x":0.0,"y":0.0,"z":1.010101079940796},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":-1.0,"y":0.0,"z":0.0},"j3":{"w":0.4823928773403168,"x":-0.8340781927108765,"y":-0.8387702107429504,"z":0.3862554430961609}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.10101010650396347}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":0.0,"y":0.0,"z":-1.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j3":{"w":1.0,"x":-0.8340781927108765,"y":0.8387702107429504,"z":-0.4823928773403168}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j3":{"w":-0.4823928773403168,"x":0.8340781927108765,"y":-0.8387702107429504,"z":-0.588275671005249}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.10101010650396347}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j3":{"w":1.0,"x":0.8340781927108765,"y":0.8387702107429504,"z":0.4823928773403168}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j2":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j3":{"w":0.8387702107429504,"x":0.4823928773403168,"y":0.8340781927108765,"z":0.7462326288223267}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.10101010650396347}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j2":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":-0.8340781927108765,"z":-0.8387702107429504}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":1.0,"x":0.0,"y":0.0,"z":1.010101079940796},"j2":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j3":{"w":-0.8387702107429504,"x":0.4823928773403168,"y":-0.8340781927108765,"z":-0.94825279712677}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.10101010650396347}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.0,"z":-1.0},"j2":{"w":0.0,"x":0.0,"y":1.0,"z":-0.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":0.8340781927108765,"z":0.8387702107429504}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":1.0,"x":0.0,"y":0.0,"z":1.010101079940796},"j3":{"w":0.8340781927108765,"x":0.4823928773403168,"y":-0.8387702107429504,"z":0.7414932250976563}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.10101010650396347}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-0.0,"y":0.0,"z":-1.0},"j3":{"w":1.0,"x":0.4823928773403168,"y":0.8387702107429504,"z":-0.8340781927108765}}},{"farDistance":0.0,"frustumMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j3":{"w":-0.8340781927108765,"x":-0.4823928773403168,"y":-0.8387702107429504,"z":-0.9435133934020996}},"nearDistance":0.0,"orthoSize":{"w":0.0,"x":0.0,"y":0.0,"z":0.0},"projectionMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-1.0,"z":0.0},"j2":{"w":-1.0,"x":0.0,"y":0.0,"z":-1.010101079940796},"j3":{"w":0.0,"x":0.0,"y":0.0,"z":-0.10101010650396347}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":-0.0,"y":-1.0,"z":-0.0},"j2":{"w":0.0,"x":-0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-0.4823928773403168,"y":0.8387702107429504,"z":0.8340781927108765}}}]},"type":1,"volumetric":true},"name":{"name":"Point light"},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-0.4823928773403168,"y":0.8387702107429504,"z":-0.8340781927108765}}}}],"id":0,"name":{"name":"Root"},"root":false}],"fog":{"ambientFactor":0.009999999776482582,"density":0.0005000000237487257,"enable":false,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"height":0.0,"heightFalloff":0.0284000001847744,"rayMarchStepCount":10,"rayMarching":true,"scatteringAnisotropy":-0.6000000238418579,"scatteringFactor":2.0,"volumetricIntensity":1.0},"irradianceVolume":{"aabb":{"max":{"x":38.237998962402344,"y":18.340999603271484,"z":31.85099983215332},"min":{"x":-38.63600158691406,"y":-9.817999839782715,"z":-21.163000106811523}},"bias":0.30000001192092896,"cascadeCount":1,"enable":true,"gamma":5.0,"hysteresis":0.9800000190734863,"lowerResMoments":true,"opacityCheck":false,"optimizeProbes":true,"probeCount":{"x":20,"y":20,"z":20},"rayCount":100,"rayCountInactive":32,"sampleEmissives":false,"scroll":false,"sharpness":50.0,"splitCorrection":2.0,"strength":1.0,"useShadowMap":false},"name":"sponza","physicsWorld":null,"postProcessing":{"chromaticAberration":{"colorsReversed":false,"enable":false,"strength":1.0},"contrast":1.0,"filmGrain":{"enable":false,"strength":0.10000000149011612},"filmicTonemapping":false,"fsr2":true,"paperWhiteLuminance":150.0,"saturation":1.0,"screenMaxLuminance":1600.0,"sharpen":{"enable":true,"factor":0.15000000596046448},"taa":{"enable":true,"jitterRange":0.9900000095367432},"tint":{"x":1.0,"y":1.0,"z":1.0},"vignette":{"color":{"x":0.0,"y":0.0,"z":0.0},"enable":false,"offset":0.0,"power":0.0,"strength":0.0}},"reflection":{"bias":0.0,"currentClipFactor":2.0,"ddgi":true,"enable":true,"halfResolution":true,"historyClipMax":1.0,"opacityCheck":false,"radianceLimit":10.0,"roughnessCutoff":0.8999999761581421,"rt":true,"spatialFilterStrength":5.234000205993652,"temporalWeight":0.9520000219345093,"textureLevel":4,"useNormalMaps":true,"useShadowMap":false},"sky":{"atmosphere":{"height":100000.0,"mieHeightScale":1200.0,"mieScatteringCoeff":2.099999983329326e-05,"probeResolution":128,"rayleighHeightScale":8000.0,"rayleighScatteringCoeff":{"x":5.500000042957254e-06,"y":1.2999999853491317e-05,"z":2.2399999579647556e-05}},"clouds":{"castShadow":false,"coverageResolution":512,"coverageScale":0.25,"coverageSpeed":5.0,"darkEdgeAmbient":0.10000000149011612,"darkEdgeFocus":2.0,"densityMultiplier":0.800000011920929,"detailResolution":32,"detailScale":16.0,"detailSpeed":10.0,"detailStrength":0.15000000596046448,"distanceLimit":8000.0,"enable":false,"halfResolution":true,"heightStretch":0.5,"maxHeight":1700.0,"minHeight":1400.0,"occlusionSampleCount":5,"sampleCount":64,"scattering":{"eccentricityFirstPhase":0.0,"eccentricitySecondPhase":-0.5,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"phaseAlpha":0.5,"scatteringFactor":2.0},"shadowResolution":512,"shadowSampleFraction":4,"shapeResolution":128,"shapeScale":2.0,"shapeSpeed":5.0,"stochasticOcclusionSampling":true},"intensity":1.0,"planetCenter":{"x":0.0,"y":-650000.0,"z":0.0},"planetRadius":649000.0},"ssgi":{"aoStrength":1.0,"enable":true,"enableAo":true,"halfResolution":true,"irradianceLimit":10.0,"radius":1.0,"rayCount":2,"sampleCount":8},"sss":{"enable":true,"maxLength":0.4970000088214874,"sampleCount":8,"thickness":0.30000001192092896},"wind":{"direction":{"x":1.0,"y":1.0},"speed":10.0}} \ No newline at end of file diff --git a/src/editor/App.cpp b/src/editor/App.cpp index 1507da07a..94d8f6796 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -21,16 +21,16 @@ namespace Atlas::Editor { ContentDiscovery::Update(); - SetDefaultWindowResolution(); - - auto icon = Atlas::Texture::Texture2D("icon.png"); - window.SetIcon(&icon); - ImGui::CreateContext(); ImGuiIO &io = ImGui::GetIO(); (void) io; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + SetDefaultWindowResolution(); + + auto icon = Atlas::Texture::Texture2D("icon.png"); + window.SetIcon(&icon); + // Add font with enlarged size and scale it down again // This means we can use scaled text up to 2x the size io.Fonts->AddFontFromFileTTF( @@ -251,98 +251,135 @@ namespace Atlas::Editor { // ImGui::ShowDemoWindow(); ImGuiViewport *viewport = ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(viewport->Pos); - ImGui::SetNextWindowSize(viewport->Size); - ImGui::SetNextWindowViewport(viewport->ID); - ImGui::SetNextWindowBgAlpha(0.0f); - - ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; - - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - ImGui::Begin("MainDockspace Window", nullptr, window_flags); - ImGui::PopStyleVar(3); - - ImGuiID mainDsId = ImGui::GetID("MainDS"); - if (!ImGui::DockBuilderGetNode(mainDsId) || resetDockspaceLayout) { - SetupMainDockspace(mainDsId); - } - ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode; - ImGui::DockSpace(mainDsId, ImVec2(0.0f, 0.0f), dockspace_flags); - - if (ImGui::BeginMainMenuBar()) { - static bool openProject = false, saveProject = false, newScene = false, importFiles = false; - bool saveScene = false; - if (ImGui::BeginMenu("File")) { - /* - ImGui::MenuItem("Open project", nullptr, &openProject); - ImGui::MenuItem("Save project", nullptr, &saveProject); - ImGui::Separator(); - */ - ImGui::MenuItem("New scene", nullptr, &newScene); - ImGui::MenuItem("Save scene", nullptr, &saveScene); - /* - ImGui::Separator(); - ImGui::MenuItem("Import files", nullptr, &importFiles); - */ - ImGui::EndMenu(); + bool playingMaximized = false; + auto activeSceneWindow = sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]; + if (activeSceneWindow) { + playingMaximized = activeSceneWindow->isPlaying && activeSceneWindow->playMaximized; + } + if (!playingMaximized) { + ImGui::SetNextWindowPos(viewport->Pos); + ImGui::SetNextWindowSize(viewport->Size); + ImGui::SetNextWindowViewport(viewport->ID); + ImGui::SetNextWindowBgAlpha(0.0f); + + ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + ImGui::Begin("MainDockspace Window", nullptr, window_flags); + ImGui::PopStyleVar(3); + + ImGuiID mainDsId = ImGui::GetID("MainDS"); + if (!ImGui::DockBuilderGetNode(mainDsId) || resetDockspaceLayout) { + SetupMainDockspace(mainDsId); } - if (ImGui::BeginMenu("View")) { - if (ImGui::MenuItem("Dark mode", nullptr, &config->darkMode)) { - if (config->darkMode) - ImGui::StyleColorsDark(); - else - ImGui::StyleColorsLight(); + ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode; + ImGui::DockSpace(mainDsId, ImVec2(0.0f, 0.0f), dockspace_flags); + + if (ImGui::BeginMainMenuBar()) { + static bool openProject = false, saveProject = false, newScene = false, importFiles = false; + bool saveScene = false, exitEditor = false; + if (ImGui::BeginMenu("File")) { + /* + ImGui::MenuItem("Open project", nullptr, &openProject); + ImGui::MenuItem("Save project", nullptr, &saveProject); + ImGui::Separator(); + */ + ImGui::MenuItem("New scene", nullptr, &newScene); + ImGui::MenuItem("Save scene", nullptr, &saveScene); + ImGui::MenuItem("Exit", nullptr, &exitEditor); + /* + ImGui::Separator(); + ImGui::MenuItem("Import files", nullptr, &importFiles); + */ + ImGui::EndMenu(); } - ImGui::MenuItem("Reset layout", nullptr, &resetDockspaceLayout); - ImGui::MenuItem("Show logs", nullptr, &logWindow.show); - ImGui::MenuItem("Show content browser", nullptr, &contentBrowserWindow.show); - ImGui::MenuItem("Show profiler", nullptr, &profilerWindow.show); - ImGui::MenuItem("Show geometry brush", nullptr, &geometryBrushWindow.show); - ImGui::EndMenu(); - } + if (ImGui::BeginMenu("View")) { + if (ImGui::MenuItem("Dark mode", nullptr, &config->darkMode)) { + if (config->darkMode) + ImGui::StyleColorsDark(); + else + ImGui::StyleColorsLight(); + } + + ImGui::MenuItem("Reset layout", nullptr, &resetDockspaceLayout); + ImGui::MenuItem("Show logs", nullptr, &logWindow.show); + ImGui::MenuItem("Show content browser", nullptr, &contentBrowserWindow.show); + ImGui::MenuItem("Show profiler", nullptr, &profilerWindow.show); + ImGui::MenuItem("Show geometry brush", nullptr, &geometryBrushWindow.show); + ImGui::EndMenu(); + } - if (ImGui::BeginMenu("Renderer")) { - ImGui::MenuItem("VSync", nullptr, &config->vsync); - ImGui::MenuItem("Pathtracer", nullptr, &config->pathTrace); - ImGui::EndMenu(); - } + if (ImGui::BeginMenu("Renderer")) { + ImGui::MenuItem("VSync", nullptr, &config->vsync); + ImGui::MenuItem("Pathtracer", nullptr, &config->pathTrace); + ImGui::EndMenu(); + } + + if (newScene) { + UI::PopupPanels::isNewScenePopupVisible = true; + newScene = false; + } - if (newScene) { - UI::PopupPanels::isNewScenePopupVisible = true; - newScene = false; + if (saveScene) { + auto activeSceneWindow = sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]; + if (activeSceneWindow != nullptr) + activeSceneWindow->SaveScene(); + } + + if (exitEditor) + Exit(); + + ImGui::EndMainMenuBar(); } - if (saveScene) { - auto activeSceneWindow = sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]; - if (activeSceneWindow != nullptr) - activeSceneWindow->SaveScene(); + UI::PopupPanels::Render(); + + geometryBrushWindow.Render(activeSceneWindow); + + for (auto& sceneWindow : sceneWindows) { + sceneWindow->Render(); } - ImGui::EndMainMenuBar(); + contentBrowserWindow.Render(); + logWindow.Render(); + profilerWindow.Render(); + + ImGui::End(); } + else { + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus | + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove; - UI::PopupPanels::Render(); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - geometryBrushWindow.Render(sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]); + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); + ImGui::Begin("RenderWindow", nullptr, window_flags); - for (auto& sceneWindow : sceneWindows) { - sceneWindow->Render(); - } + auto renderArea = ImGui::GetContentRegionAvail(); + activeSceneWindow->viewportPanel.RenderScene(activeSceneWindow->scene.Get(), + ivec2(0), ivec2(int32_t(renderArea.x), int32_t(renderArea.y)), true); + auto set = Singletons::imguiWrapper->GetTextureDescriptorSet(&activeSceneWindow->viewportPanel.viewportTexture); + ImGui::Image(set, renderArea); - contentBrowserWindow.Render(); - logWindow.Render(); - profilerWindow.Render(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); - Notifications::Display(); + ImGui::End(); + } - ImGui::End(); + Notifications::Display(); ImGui::Render(); Singletons::imguiWrapper->Render(true); @@ -410,15 +447,9 @@ namespace Atlas::Editor { void App::SetDefaultWindowResolution() { auto resolution = GetScreenSize(); - if (resolution.y <= 1080) { - window.SetSize(1280, 720); - } - else if (resolution.y <= 1440) { - window.SetSize(1920, 1080); - } - else { - window.SetSize(2560, 1440); - } + + window.SetSize(resolution.x - 200, resolution.y - 200); + window.SetPosition(100, 100); } diff --git a/src/editor/Notifications.cpp b/src/editor/Notifications.cpp index 4abd0231a..31e3d83b8 100644 --- a/src/editor/Notifications.cpp +++ b/src/editor/Notifications.cpp @@ -22,8 +22,8 @@ namespace Atlas::Editor { void Notifications::Display() { - const auto notificationWindowFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoFocusOnAppearing | - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDecoration; + const auto notificationWindowFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking | + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing; auto viewport = ImGui::GetMainViewport(); auto viewportSize = viewport->Size; diff --git a/src/editor/Serialization.cpp b/src/editor/Serialization.cpp index 3ffc8c15d..c357f42e7 100644 --- a/src/editor/Serialization.cpp +++ b/src/editor/Serialization.cpp @@ -89,6 +89,7 @@ namespace Atlas::Editor { { "cameraMovementSpeed", sceneWindow->cameraMovementSpeed }, { "cameraRotationSpeed", sceneWindow->cameraRotationSpeed }, { "depthTestBoundingVolumes", sceneWindow->depthTestBoundingVolumes }, + { "playMaximized", sceneWindow->playMaximized }, { "camera", camera } }; @@ -124,6 +125,7 @@ namespace Atlas::Editor { try_get_json(j, "cameraMovementSpeed", sceneWindow->cameraMovementSpeed); try_get_json(j, "cameraRotationSpeed", sceneWindow->cameraRotationSpeed); try_get_json(j, "depthTestBoundingVolumes", sceneWindow->depthTestBoundingVolumes); + try_get_json(j, "playMaximized", sceneWindow->playMaximized); try_get_json(j, "camera", camera); sceneWindow->cameraEntity = sceneWindow->scene->CreateEntity(); diff --git a/src/editor/ui/panels/ViewportPanel.cpp b/src/editor/ui/panels/ViewportPanel.cpp index c871eb304..fb02307d2 100644 --- a/src/editor/ui/panels/ViewportPanel.cpp +++ b/src/editor/ui/panels/ViewportPanel.cpp @@ -52,16 +52,44 @@ namespace Atlas::Editor::UI { auto region = ImGui::GetContentRegionAvail(); auto windowPos = ImGui::GetWindowPos(); - bool validRegion = region.x > 0.0f && region.y > 0.0f; + auto pos = ivec2(int32_t(windowPos.x), int32_t(windowPos.y)); + auto size = ivec2(int32_t(region.x), int32_t(region.y)); + RenderScene(scene, pos, size, isActiveWindow); - if ((viewportTexture.width != int32_t(region.x) || - viewportTexture.height != int32_t(region.y)) && validRegion) { - viewport->Set(int32_t(windowPos.x), int32_t(windowPos.y), int32_t(region.x), int32_t(region.y)); - viewportTexture.Resize(int32_t(region.x), int32_t(region.y)); + if (viewportTexture.IsValid() && viewportTexture.image->layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + auto set = Singletons::imguiWrapper->GetTextureDescriptorSet(&viewportTexture); + ImGui::Image(set, region); + } + + if (drawOverlayFunc && !isBlocked) + drawOverlayFunc(); + + ImGui::SetCursorPos(ImVec2(0.0f, 0.0f)); + + if (drawMenuBarFunc && !isBlocked) { + isFocused |= ImGui::IsWindowFocused(); + + drawMenuBarFunc(); + } + + ImGui::EndChild(); + + ImGui::End(); + + } + + void ViewportPanel::RenderScene(Ref& scene, ivec2 pos, ivec2 size, bool isActive) { + + bool validSize = size.x > 0 && size.y > 0; + + if ((viewportTexture.width != size.x || + viewportTexture.height != size.y) && validSize) { + viewport->Set(pos.x, pos.y, size.x, size.y); + viewportTexture.Resize(size.x, size.y); CreateRenderPass(); } - if (scene != nullptr && validRegion && isActiveWindow && !isBlocked) { + if (scene != nullptr && validSize && isActive && !Singletons::blockingOperation->block) { auto& config = Singletons::config; if (config->pathTrace) { @@ -91,29 +119,8 @@ namespace Atlas::Editor::UI { } primitiveBatchWrapper.primitiveBatch->Clear(); - - } - - if (viewportTexture.IsValid() && viewportTexture.image->layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - auto set = Singletons::imguiWrapper->GetTextureDescriptorSet(&viewportTexture); - ImGui::Image(set, region); - } - - if (drawOverlayFunc && !isBlocked) - drawOverlayFunc(); - - ImGui::SetCursorPos(ImVec2(0.0f, 0.0f)); - - if (drawMenuBarFunc && !isBlocked) { - isFocused |= ImGui::IsWindowFocused(); - - drawMenuBarFunc(); } - ImGui::EndChild(); - - ImGui::End(); - } void ViewportPanel::RenderVisualization() { diff --git a/src/editor/ui/panels/ViewportPanel.h b/src/editor/ui/panels/ViewportPanel.h index b08b28838..cf1d7fdea 100644 --- a/src/editor/ui/panels/ViewportPanel.h +++ b/src/editor/ui/panels/ViewportPanel.h @@ -32,6 +32,8 @@ namespace Atlas::Editor::UI { void Render(Ref& scene, bool isActiveWindow); + void RenderScene(Ref& scene, ivec2 pos, ivec2 size, bool isActive); + Ref viewport; Texture::Texture2D viewportTexture; diff --git a/src/editor/ui/windows/SceneWindow.cpp b/src/editor/ui/windows/SceneWindow.cpp index ebee824c9..1e341e816 100644 --- a/src/editor/ui/windows/SceneWindow.cpp +++ b/src/editor/ui/windows/SceneWindow.cpp @@ -61,6 +61,10 @@ namespace Atlas::Editor::UI { SaveScene(); } + if (controlDown && playMaximized && isPlaying && ImGui::IsKeyPressed(ImGuiKey_Escape, false)) { + StopPlaying(); + } + } void SceneWindow::Render() { @@ -356,6 +360,8 @@ namespace Atlas::Editor::UI { ImGui::Text("Path traces samples"); ImGui::DragInt("Sample count", &Singletons::mainRenderer->pathTracingRenderer.realTimeSamplesPerFrame, 1, 1, 16); + ImGui::Checkbox("Play maximized", &playMaximized); + ImGui::EndPopup(); } @@ -604,6 +610,10 @@ namespace Atlas::Editor::UI { isPlaying = true; + if (playMaximized) { + Notifications::Push({ "To stop playing, press Ctrl + Esc" }); + } + } void SceneWindow::StopPlaying() { diff --git a/src/editor/ui/windows/SceneWindow.h b/src/editor/ui/windows/SceneWindow.h index 10c3b9686..907158189 100644 --- a/src/editor/ui/windows/SceneWindow.h +++ b/src/editor/ui/windows/SceneWindow.h @@ -65,6 +65,7 @@ namespace Atlas::Editor::UI { bool hasMainCamera = false; bool hasPlayer = false; bool isPlaying = false; + bool playMaximized = false; bool isActiveWindow = false; bool lockSelection = false; diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index f0e80845f..b490d5dd2 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -55,8 +55,6 @@ namespace Atlas { } } - commandList->PushConstants("constants", &pushConstants, sizeof(PushConstants)); - commandList->BindSampledImages(cascadeMaps, 3, 6); commandList->BindSampledImages(cubeMaps, 3, 14); @@ -89,6 +87,8 @@ namespace Atlas { commandList->BindSampler(shadowSampler, 3, 5); + commandList->PushConstants("constants", &pushConstants); + ivec2 res = ivec2(target->GetScaledWidth(), target->GetScaledHeight()); int32_t groupSize = 8; ivec2 groupCount = res / groupSize; diff --git a/src/engine/scene/components/ComponentSerializer.cpp b/src/engine/scene/components/ComponentSerializer.cpp index 3ee1b9b09..19bf51467 100644 --- a/src/engine/scene/components/ComponentSerializer.cpp +++ b/src/engine/scene/components/ComponentSerializer.cpp @@ -145,7 +145,7 @@ namespace Atlas::Scene::Components { j.at("volumetric").get_to(p.volumetric); p.type = static_cast(type); - p.mobility = static_cast(type); + p.mobility = static_cast(mobility); if (p.type == LightType::DirectionalLight) { typeProperties.at("direction").get_to(p.properties.directional.direction); From d38fed782a1e6e0c9c01e329b7b245d5ba1a10fe Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 25 Aug 2024 12:14:31 +0200 Subject: [PATCH 08/66] Restructuring scene rendering data --- data/shader/rtgi/temporal.csh | 2 +- src/engine/lighting/IrradianceVolume.cpp | 9 + src/engine/lighting/IrradianceVolume.h | 6 + src/engine/physics/Player.cpp | 21 +- src/engine/physics/Player.h | 7 +- src/engine/raytracing/RayTracingWorld.cpp | 26 +- src/engine/renderer/DDGIRenderer.cpp | 17 +- src/engine/renderer/DDGIRenderer.h | 6 - src/engine/renderer/MainRenderer.cpp | 261 +++------------- src/engine/renderer/MainRenderer.h | 7 - src/engine/renderer/OpaqueRenderer.cpp | 16 +- src/engine/renderer/ShadowRenderer.cpp | 4 +- src/engine/renderer/helper/CommonStructures.h | 13 + src/engine/scene/Scene.cpp | 116 ++----- src/engine/scene/Scene.h | 18 +- src/engine/scene/SceneRenderState.cpp | 284 ++++++++++++++++++ src/engine/scene/SceneRenderState.h | 57 ++++ src/engine/volume/BVH.cpp | 2 +- 18 files changed, 496 insertions(+), 376 deletions(-) create mode 100644 src/engine/scene/SceneRenderState.cpp create mode 100644 src/engine/scene/SceneRenderState.h diff --git a/data/shader/rtgi/temporal.csh b/data/shader/rtgi/temporal.csh index 7448e2d81..8c9864bb5 100644 --- a/data/shader/rtgi/temporal.csh +++ b/data/shader/rtgi/temporal.csh @@ -468,7 +468,7 @@ void main() { imageStore(resolveImage, pixel, vec4(vec3(historyLength / 32.0), variance)); //imageStore(resolveImage, pixel, vec4(vec3(adjClipBlend), variance)); //imageStore(resolveImage, pixel, vec4(vec3(abs(velocity.x) + abs(velocity.y)), variance)); - imageStore(resolveImage, pixel, vec4(vec3(success ? 1.0 : 0.0), variance)); + //imageStore(resolveImage, pixel, vec4(vec3(success ? 1.0 : 0.0), variance)); //imageStore(resolveImage, pixel, vec4(vec3(materialIdx) / 3000.0, variance)); imageStore(resolveImage, pixel, vec4(resolve, variance)); diff --git a/src/engine/lighting/IrradianceVolume.cpp b/src/engine/lighting/IrradianceVolume.cpp index 781141255..3ca0bf70e 100644 --- a/src/engine/lighting/IrradianceVolume.cpp +++ b/src/engine/lighting/IrradianceVolume.cpp @@ -152,6 +152,15 @@ namespace Atlas { momentsArray1 = Texture::Texture2DArray(momRes.x, momRes.y, probeCount.y * cascadeCount, VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + probeDebugMaterial = CreateRef(); + probeDebugActiveMaterial = CreateRef(); + probeDebugInactiveMaterial = CreateRef(); + probeDebugOffsetMaterial = CreateRef(); + + probeDebugActiveMaterial->emissiveColor = vec3(0.0f, 1.0f, 0.0f); + probeDebugInactiveMaterial->emissiveColor = vec3(1.0f, 0.0f, 0.0f); + probeDebugOffsetMaterial->emissiveColor = vec3(0.0f, 0.0f, 1.0f); + SwapTextures(); ClearProbes(irrRes, momRes, probeCount, cascadeCount); diff --git a/src/engine/lighting/IrradianceVolume.h b/src/engine/lighting/IrradianceVolume.h index bef1f6441..4b8a7f4e3 100644 --- a/src/engine/lighting/IrradianceVolume.h +++ b/src/engine/lighting/IrradianceVolume.h @@ -55,6 +55,12 @@ namespace Atlas { Buffer::Buffer probeStateBuffer; Buffer::Buffer historyProbeStateBuffer; + // Used for debugging + Ref probeDebugMaterial; + Ref probeDebugActiveMaterial; + Ref probeDebugInactiveMaterial; + Ref probeDebugOffsetMaterial; + private: void FillRayBuffers(); diff --git a/src/engine/physics/Player.cpp b/src/engine/physics/Player.cpp index d3c7d763c..f411a7ec9 100644 --- a/src/engine/physics/Player.cpp +++ b/src/engine/physics/Player.cpp @@ -17,9 +17,17 @@ namespace Atlas::Physics { settings.mPredictiveContactDistance = predictiveContactDistance; - settings.mCharacterPadding = shapePadding; + settings.mMaxCollisionIterations = 10; + settings.mMaxConstraintIterations = 10; settings.mShapeOffset = VecToJPHVec(shapeOffset); settings.mShape = shape->ref; + settings.mInnerBodyShape = shape->ref; + settings.mInnerBodyLayer = Layers::Movable; + + if (shape->type == ShapeType::Capsule) { + auto shapeSettings = static_cast(shape->settings.get()); + settings.mSupportingVolume = { JPH::Vec3::sAxisY(), -shapeSettings->radius }; + } return settings; @@ -140,6 +148,8 @@ namespace Atlas::Physics { auto gravityVector = -GetUp() * glm::length(world->GetGravity()); + character->SetEnhancedInternalEdgeRemoval(true); + JPH::CharacterVirtual::ExtendedUpdateSettings settings; settings.mStickToFloorStepDown = VecToJPHVec(stickToGroundDist); @@ -160,6 +170,15 @@ namespace Atlas::Physics { character = CreateRef(settings, VecToJPHVec(initialPosition), QuatToJPHQuat(initialRotation), world->system.get()); + character->SetListener(this); + + } + + void Player::OnContactAdded(const JPH::CharacterVirtual *inCharacter, const JPH::BodyID &inBodyID2, const JPH::SubShapeID &inSubShapeID2, + JPH::RVec3Arg inContactPosition, JPH::Vec3Arg inContactNormal, JPH::CharacterContactSettings &ioSettings) { + + ioSettings.mCanPushCharacter = false; + } } \ No newline at end of file diff --git a/src/engine/physics/Player.h b/src/engine/physics/Player.h index b36346a4e..b46843fe4 100644 --- a/src/engine/physics/Player.h +++ b/src/engine/physics/Player.h @@ -21,12 +21,12 @@ namespace Atlas::Physics { float predictiveContactDistance = 0.1f; float shapePadding = 0.02f; - vec3 shapeOffset; + vec3 shapeOffset = vec3(0.0f); Ref shape; }; - class Player { + class Player : JPH::CharacterContactListener { public: Player() = default; @@ -70,6 +70,9 @@ namespace Atlas::Physics { protected: void Init(PhysicsWorld* world, vec3 initialPosition, quat initialRotation); + virtual void OnContactAdded(const JPH::CharacterVirtual *inCharacter, const JPH::BodyID &inBodyID2, const JPH::SubShapeID &inSubShapeID2, + JPH::RVec3Arg inContactPosition, JPH::Vec3Arg inContactNormal, JPH::CharacterContactSettings &ioSettings) override; + Ref character = nullptr; PhysicsWorld* world = nullptr; diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index 0714843b3..1949c0126 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -36,16 +36,18 @@ namespace Atlas { if (!device->swapChain->isComplete) return; if (!subset.Any()) return; + auto sceneState = &scene->renderState; + blases.clear(); auto meshes = scene->GetMeshes(); int32_t meshCount = 0; - JobSystem::Wait(scene->bindlessMeshMapUpdateJob); + JobSystem::Wait(sceneState->bindlessMeshMapUpdateJob); for (auto& mesh : meshes) { // Only need to check for this, since that means that the BVH was built and the mesh is loaded - if (!scene->meshIdToBindlessIdx.contains(mesh.GetID())) + if (!sceneState->meshIdToBindlessIdx.contains(mesh.GetID())) continue; if (!meshInfos.contains(mesh.GetID())) { @@ -54,7 +56,7 @@ namespace Atlas { } auto &meshInfo = meshInfos[mesh.GetID()]; - meshInfo.offset = int32_t(scene->meshIdToBindlessIdx[mesh.GetID()]); + meshInfo.offset = int32_t(sceneState->meshIdToBindlessIdx[mesh.GetID()]); // Some extra path for hardware raytracing, don't want to do work twice if (hardwareRayTracing) { @@ -84,14 +86,14 @@ namespace Atlas { actorAABBs.clear(); lastMatrices.clear(); - JobSystem::Wait(scene->bindlessTextureMapUpdateJob); + JobSystem::Wait(sceneState->bindlessTextureMapUpdateJob); UpdateMaterials(); for (auto entity : subset) { const auto& [meshComponent, transformComponent] = subset.Get(entity); - if (!scene->meshIdToBindlessIdx.contains(meshComponent.mesh.GetID())) + if (!sceneState->meshIdToBindlessIdx.contains(meshComponent.mesh.GetID())) continue; actorAABBs.push_back(meshComponent.aabb); @@ -172,6 +174,8 @@ namespace Atlas { std::lock_guard lock(mutex); + auto sceneState = &scene->renderState; + auto meshes = scene->GetMeshes(); materials.clear(); @@ -214,27 +218,27 @@ namespace Atlas { gpuMaterial.useVertexColors = material->vertexColors ? 1 : 0; if (material->HasBaseColorMap()) { - gpuMaterial.baseColorTexture = scene->textureToBindlessIdx[material->baseColorMap.Get()]; + gpuMaterial.baseColorTexture = sceneState->textureToBindlessIdx[material->baseColorMap.Get()]; } if (material->HasOpacityMap()) { - gpuMaterial.opacityTexture = scene->textureToBindlessIdx[material->opacityMap.Get()]; + gpuMaterial.opacityTexture = sceneState->textureToBindlessIdx[material->opacityMap.Get()]; } if (material->HasNormalMap()) { - gpuMaterial.normalTexture = scene->textureToBindlessIdx[material->normalMap.Get()]; + gpuMaterial.normalTexture = sceneState->textureToBindlessIdx[material->normalMap.Get()]; } if (material->HasRoughnessMap()) { - gpuMaterial.roughnessTexture = scene->textureToBindlessIdx[material->roughnessMap.Get()]; + gpuMaterial.roughnessTexture = sceneState->textureToBindlessIdx[material->roughnessMap.Get()]; } if (material->HasMetalnessMap()) { - gpuMaterial.metalnessTexture = scene->textureToBindlessIdx[material->metalnessMap.Get()]; + gpuMaterial.metalnessTexture = sceneState->textureToBindlessIdx[material->metalnessMap.Get()]; } if (material->HasAoMap()) { - gpuMaterial.aoTexture = scene->textureToBindlessIdx[material->aoMap.Get()]; + gpuMaterial.aoTexture = sceneState->textureToBindlessIdx[material->aoMap.Get()]; } } diff --git a/src/engine/renderer/DDGIRenderer.cpp b/src/engine/renderer/DDGIRenderer.cpp index c58765b5b..e56f6a6ee 100644 --- a/src/engine/renderer/DDGIRenderer.cpp +++ b/src/engine/renderer/DDGIRenderer.cpp @@ -27,11 +27,6 @@ namespace Atlas { irradianceCopyEdgePipelineConfig = PipelineConfig("ddgi/copyEdge.csh", {"IRRADIANCE"}); momentsCopyEdgePipelineConfig = PipelineConfig("ddgi/copyEdge.csh"); - probeDebugMaterial = CreateRef(); - probeDebugActiveMaterial = CreateRef(); - probeDebugInactiveMaterial = CreateRef(); - probeDebugOffsetMaterial = CreateRef(); - auto samplerDesc = Graphics::SamplerDesc { .filter = VK_FILTER_NEAREST, .mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, @@ -317,17 +312,13 @@ namespace Atlas { auto pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); - probeDebugActiveMaterial->emissiveColor = vec3(0.0f, 1.0f, 0.0f); - probeDebugInactiveMaterial->emissiveColor = vec3(1.0f, 0.0f, 0.0f); - probeDebugOffsetMaterial->emissiveColor = vec3(0.0f, 0.0f, 1.0f); - sphereArray.Bind(commandList); ProbeDebugConstants constants = { - .probeMaterialIdx = uint32_t(materialMap[probeDebugMaterial.get()]), - .probeActiveMaterialIdx = uint32_t(materialMap[probeDebugActiveMaterial.get()]), - .probeInactiveMaterialIdx = uint32_t(materialMap[probeDebugInactiveMaterial.get()]), - .probeOffsetMaterialIdx = uint32_t(materialMap[probeDebugOffsetMaterial.get()]) + .probeMaterialIdx = uint32_t(materialMap[internalVolume.probeDebugMaterial.get()]), + .probeActiveMaterialIdx = uint32_t(materialMap[internalVolume.probeDebugActiveMaterial.get()]), + .probeInactiveMaterialIdx = uint32_t(materialMap[internalVolume.probeDebugInactiveMaterial.get()]), + .probeOffsetMaterialIdx = uint32_t(materialMap[internalVolume.probeDebugOffsetMaterial.get()]) }; commandList->PushConstants("constants", &constants); diff --git a/src/engine/renderer/DDGIRenderer.h b/src/engine/renderer/DDGIRenderer.h index 65f9bb360..0036df0f6 100644 --- a/src/engine/renderer/DDGIRenderer.h +++ b/src/engine/renderer/DDGIRenderer.h @@ -23,12 +23,6 @@ namespace Atlas { void DebugProbes(Ref target, Ref scene, Graphics::CommandList* commandList, std::unordered_map& materialMap); - // Used for debugging - Ref probeDebugMaterial; - Ref probeDebugActiveMaterial; - Ref probeDebugInactiveMaterial; - Ref probeDebugOffsetMaterial; - private: struct alignas(16) RayGenUniforms { mat4 rotationMatrix; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index c8d4facac..6389ae493 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -6,15 +6,6 @@ #include "../tools/PerformanceCounter.h" #include "../Clock.h" -#define FEATURE_BASE_COLOR_MAP (1 << 1) -#define FEATURE_OPACITY_MAP (1 << 2) -#define FEATURE_NORMAL_MAP (1 << 3) -#define FEATURE_ROUGHNESS_MAP (1 << 4) -#define FEATURE_METALNESS_MAP (1 << 5) -#define FEATURE_AO_MAP (1 << 6) -#define FEATURE_TRANSMISSION (1 << 7) -#define FEATURE_VERTEX_COLORS (1 << 8) - namespace Atlas { namespace Renderer { @@ -106,6 +97,8 @@ namespace Atlas { camera.Jitter(vec2(0.0f)); } + auto sceneState = &scene->renderState; + Graphics::Profiler::BeginThread("Main renderer", commandList); Graphics::Profiler::BeginQuery("Render scene"); @@ -114,31 +107,6 @@ namespace Atlas { lightData.CullAndSort(scene); - Ref materialBuffer; - std::vector materials; - std::unordered_map materialMap; - - JobGroup prepareMaterialsGroup { JobPriority::High }; - JobSystem::Execute(prepareMaterialsGroup, [&](JobData&) { - PrepareMaterials(scene, materials, materialMap); - auto materialBufferDesc = Graphics::BufferDesc { - .usageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, - .domain = Graphics::BufferDomain::Host, - .hostAccess = Graphics::BufferHostAccess::Sequential, - .data = materials.data(), - .size = sizeof(PackedMaterial) * glm::max(materials.size(), size_t(1)), - }; - materialBuffer = device->CreateBuffer(materialBufferDesc); - }); - - std::vector> images; - std::vector> blasBuffers, triangleBuffers, bvhTriangleBuffers, triangleOffsetBuffers; - - JobGroup prepareBindlessGroup { JobPriority::High }; - JobSystem::Execute(prepareBindlessGroup, [&](JobData&) { - PrepareBindlessData(scene, images, blasBuffers, triangleBuffers, bvhTriangleBuffers, triangleOffsetBuffers); - }); - SetUniforms(target, scene, camera); commandList->BindBuffer(globalUniformBuffer, 1, 31); @@ -146,9 +114,6 @@ namespace Atlas { commandList->BindSampler(globalSampler, 1, 13); commandList->BindSampler(globalNearestSampler, 1, 15); - JobSystem::WaitSpin(prepareMaterialsGroup); - commandList->BindBuffer(materialBuffer, 1, 14); - if (scene->clutter) vegetationRenderer.helper.PrepareInstanceBuffer(*scene->clutter, camera, commandList); @@ -172,19 +137,29 @@ namespace Atlas { volumetricCloudRenderer.RenderShadow(target, scene, commandList); + Log::Warning("Begin wait material"); + JobSystem::WaitSpin(sceneState->materialUpdateJob); + Log::Warning("End wait material"); + sceneState->materialBuffer.Bind(commandList, 1, 14); + // Wait as long as possible for this to finish - JobSystem::WaitSpin(prepareBindlessGroup); + Log::Warning("Begin wait bindless"); + JobSystem::WaitSpin(sceneState->bindlessMeshMapUpdateJob); + JobSystem::WaitSpin(sceneState->bindlessTextureMapUpdateJob); + JobSystem::WaitSpin(sceneState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(sceneState->prepareBindlessTexturesJob); + Log::Warning("End wait bindless"); lightData.UpdateBindlessIndices(scene); - commandList->BindBuffers(triangleBuffers, 0, 1); - if (images.size()) - commandList->BindSampledImages(images, 0, 3); + commandList->BindBuffers(sceneState->triangleBuffers, 0, 1); + if (sceneState->images.size()) + commandList->BindSampledImages(sceneState->images, 0, 3); if (device->support.hardwareRayTracing) { - commandList->BindBuffers(triangleOffsetBuffers, 0, 2); + commandList->BindBuffers(sceneState->triangleOffsetBuffers, 0, 2); } else { - commandList->BindBuffers(blasBuffers, 0, 0); - commandList->BindBuffers(bvhTriangleBuffers, 0, 2); + commandList->BindBuffers(sceneState->blasBuffers, 0, 0); + commandList->BindBuffers(sceneState->bvhTriangleBuffers, 0, 2); } { @@ -222,7 +197,9 @@ namespace Atlas { commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } - JobSystem::WaitSpin(scene->rayTracingWorldUpdateJob); + Log::Warning("Begin wait ray tracing"); + JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); + Log::Warning("End wait ray tracing"); lightData.FillBuffer(scene); lightData.lightBuffer.Bind(commandList, 1, 16); @@ -237,15 +214,15 @@ namespace Atlas { commandList->BeginRenderPass(target->gBufferRenderPass, target->gBufferFrameBuffer, true); - opaqueRenderer.Render(target, scene, commandList, &renderList, materialMap); + opaqueRenderer.Render(target, scene, commandList, &renderList, sceneState->materialMap); - ddgiRenderer.DebugProbes(target, scene, commandList, materialMap); + ddgiRenderer.DebugProbes(target, scene, commandList, sceneState->materialMap); - vegetationRenderer.Render(target, scene, commandList, materialMap); + vegetationRenderer.Render(target, scene, commandList, sceneState->materialMap); - terrainRenderer.Render(target, scene, commandList, materialMap); + terrainRenderer.Render(target, scene, commandList, sceneState->materialMap); - impostorRenderer.Render(target, scene, commandList, &renderList, materialMap); + impostorRenderer.Render(target, scene, commandList, &renderList, sceneState->materialMap); commandList->EndRenderPass(); @@ -434,6 +411,8 @@ namespace Atlas { if (!scene->IsRtDataValid() || !device->swapChain->isComplete || !scene->HasMainCamera()) return; + auto sceneState = &scene->renderState; + static vec2 lastJitter = vec2(0.0f); auto& camera = scene->GetMainCamera(); @@ -475,32 +454,27 @@ namespace Atlas { pathTraceGlobalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); - std::vector> images; - std::vector> blasBuffers, triangleBuffers, bvhTriangleBuffers, triangleOffsetBuffers; - JobGroup prepareBindlessGroup { JobPriority::High }; - JobSystem::Execute(prepareBindlessGroup, [&](JobData&) { - PrepareBindlessData(scene, images, blasBuffers, triangleBuffers, bvhTriangleBuffers, triangleOffsetBuffers); - }); - - - JobSystem::WaitSpin(scene->rayTracingWorldUpdateJob); - JobSystem::WaitSpin(prepareBindlessGroup); + JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); + JobSystem::WaitSpin(sceneState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(sceneState->prepareBindlessTexturesJob); commandList->BindBuffer(pathTraceGlobalUniformBuffer, 1, 31); commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 12); commandList->BindSampler(globalSampler, 1, 13); commandList->BindSampler(globalNearestSampler, 1, 15); - commandList->BindBuffers(triangleBuffers, 0, 1); - commandList->BindSampledImages(images, 0, 3); + commandList->BindBuffers(sceneState->triangleBuffers, 0, 1); + if (sceneState->images.size()) + commandList->BindSampledImages(sceneState->images, 0, 3); if (device->support.hardwareRayTracing) { - commandList->BindBuffers(triangleOffsetBuffers, 0, 2); + commandList->BindBuffers(sceneState->triangleOffsetBuffers, 0, 2); } else { - commandList->BindBuffers(blasBuffers, 0, 0); - commandList->BindBuffers(bvhTriangleBuffers, 0, 2); + commandList->BindBuffers(sceneState->blasBuffers, 0, 0); + commandList->BindBuffers(sceneState->bvhTriangleBuffers, 0, 2); } + Graphics::Profiler::EndQuery(); // No probe filtering required @@ -1077,163 +1051,6 @@ namespace Atlas { impostor->impostorInfoBuffer.SetData(&impostorInfo, 0); } - } - - void MainRenderer::PrepareMaterials(Ref scene, std::vector& materials, - std::unordered_map& materialMap) { - - auto sceneMaterials = scene->GetMaterials(); - - // For debugging purpose - if (scene->irradianceVolume && scene->irradianceVolume->debug) { - sceneMaterials.push_back(ddgiRenderer.probeDebugMaterial); - sceneMaterials.push_back(ddgiRenderer.probeDebugActiveMaterial); - sceneMaterials.push_back(ddgiRenderer.probeDebugInactiveMaterial); - sceneMaterials.push_back(ddgiRenderer.probeDebugOffsetMaterial); - } - - uint16_t idx = 0; - - for (auto material : sceneMaterials) { - // Might happen due to the scene giving back materials on a mesh basis - if (materialMap.contains(material.get())) - continue; - - PackedMaterial packed; - - packed.baseColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(material->baseColor), 0.0f)); - packed.emissiveColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(material->emissiveColor), 0.0f)); - packed.transmissionColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(material->transmissiveColor), 0.0f)); - - packed.emissiveIntensityTiling = glm::packHalf2x16(vec2(material->emissiveIntensity, material->tiling)); - - vec4 data0, data1, data2; - - data0.x = material->opacity; - data0.y = material->roughness; - data0.z = material->metalness; - - data1.x = material->ao; - data1.y = material->HasNormalMap() ? material->normalScale : 0.0f; - data1.z = material->HasDisplacementMap() ? material->displacementScale : 0.0f; - - data2.x = material->reflectance; - // Note used - data2.y = 0.0f; - data2.z = 0.0f; - - packed.data0 = Common::Packing::PackUnsignedVector3x10_1x2(data0); - packed.data1 = Common::Packing::PackUnsignedVector3x10_1x2(data1); - packed.data2 = Common::Packing::PackUnsignedVector3x10_1x2(data2); - - packed.features = 0; - - packed.features |= material->HasBaseColorMap() ? FEATURE_BASE_COLOR_MAP : 0; - packed.features |= material->HasOpacityMap() ? FEATURE_OPACITY_MAP : 0; - packed.features |= material->HasNormalMap() ? FEATURE_NORMAL_MAP : 0; - packed.features |= material->HasRoughnessMap() ? FEATURE_ROUGHNESS_MAP : 0; - packed.features |= material->HasMetalnessMap() ? FEATURE_METALNESS_MAP : 0; - packed.features |= material->HasAoMap() ? FEATURE_AO_MAP : 0; - packed.features |= glm::length(material->transmissiveColor) > 0.0f ? FEATURE_TRANSMISSION : 0; - packed.features |= material->vertexColors ? FEATURE_VERTEX_COLORS : 0; - - materials.push_back(packed); - - materialMap[material.get()] = idx++; - } - - auto meshes = scene->GetMeshes(); - - for (auto mesh : meshes) { - if (!mesh.IsLoaded()) - continue; - - auto impostor = mesh->impostor; - - if (!impostor) - continue; - - PackedMaterial packed; - - packed.baseColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(1.0f)); - packed.emissiveColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(0.0f)); - packed.transmissionColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(impostor->transmissiveColor), 1.0f)); - - vec4 data0, data1, data2; - - data0.x = 1.0f; - data0.y = 1.0f; - data0.z = 1.0f; - - data1.x = 1.0f; - data1.y = 0.0f; - data1.z = 0.0f; - - data2.x = 0.5f; - // Note used - data2.y = 0.0f; - data2.z = 0.0f; - - packed.data0 = Common::Packing::PackUnsignedVector3x10_1x2(data0); - packed.data1 = Common::Packing::PackUnsignedVector3x10_1x2(data1); - packed.data2 = Common::Packing::PackUnsignedVector3x10_1x2(data2); - - packed.features = 0; - - packed.features |= FEATURE_BASE_COLOR_MAP | - FEATURE_ROUGHNESS_MAP | FEATURE_METALNESS_MAP | FEATURE_AO_MAP; - packed.features |= glm::length(impostor->transmissiveColor) > 0.0f ? FEATURE_TRANSMISSION : 0; - - materials.push_back(packed); - - materialMap[impostor.get()] = idx++; - } - - - } - - void MainRenderer::PrepareBindlessData(Ref scene, std::vector>& images, - std::vector>& blasBuffers, std::vector>& triangleBuffers, - std::vector>& bvhTriangleBuffers, std::vector>& triangleOffsetBuffers) { - - if (!device->support.bindless) - return; - - JobSystem::WaitSpin(scene->bindlessMeshMapUpdateJob); - - blasBuffers.resize(scene->meshIdToBindlessIdx.size()); - triangleBuffers.resize(scene->meshIdToBindlessIdx.size()); - bvhTriangleBuffers.resize(scene->meshIdToBindlessIdx.size()); - triangleOffsetBuffers.resize(scene->meshIdToBindlessIdx.size()); - - for (const auto& [meshId, idx] : scene->meshIdToBindlessIdx) { - if (!scene->registeredMeshes.contains(meshId)) continue; - - const auto& mesh = scene->registeredMeshes[meshId].resource; - - auto blasBuffer = mesh->blasNodeBuffer.Get(); - auto triangleBuffer = mesh->triangleBuffer.Get(); - auto bvhTriangleBuffer = mesh->bvhTriangleBuffer.Get(); - auto triangleOffsetBuffer = mesh->triangleOffsetBuffer.Get(); - - AE_ASSERT(triangleBuffer != nullptr); - - blasBuffers[idx] = blasBuffer; - triangleBuffers[idx] = triangleBuffer; - bvhTriangleBuffers[idx] = bvhTriangleBuffer; - triangleOffsetBuffers[idx] = triangleOffsetBuffer; - } - - JobSystem::WaitSpin(scene->bindlessTextureMapUpdateJob); - - images.resize(scene->textureToBindlessIdx.size()); - - for (const auto& [texture, idx] : scene->textureToBindlessIdx) { - - images[idx] = texture->image; - - } - } void MainRenderer::FillRenderList(Ref scene, const CameraComponent& camera) { diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index f363dbabc..d07adc197 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -74,13 +74,6 @@ namespace Atlas { void SetUniforms(const Ref& target, const Ref& scene, const CameraComponent& camera); - void PrepareMaterials(Ref scene, std::vector& materials, - std::unordered_map& materialMap); - - void PrepareBindlessData(Ref scene, std::vector>& images, - std::vector>& blasBuffers, std::vector>& triangleBuffers, - std::vector>& bvhTriangleBuffers, std::vector>& triangleOffsetBuffers); - void FillRenderList(Ref scene, const CameraComponent& camera); void PreintegrateBRDF(); diff --git a/src/engine/renderer/OpaqueRenderer.cpp b/src/engine/renderer/OpaqueRenderer.cpp index 883e1264a..a3e7a43b8 100644 --- a/src/engine/renderer/OpaqueRenderer.cpp +++ b/src/engine/renderer/OpaqueRenderer.cpp @@ -24,6 +24,8 @@ namespace Atlas { if (!mainPass) return; + auto sceneState = &scene->renderState; + commandList->BindBuffer(mainPass->currentMatricesBuffer, 1, 1); commandList->BindBuffer(mainPass->lastMatricesBuffer, 1, 2); commandList->BindBuffer(mainPass->impostorMatricesBuffer, 1, 3); @@ -116,13 +118,13 @@ namespace Atlas { .windTextureLod = mesh->windNoiseTextureLod, .windBendScale = mesh->windBendScale, .windWiggleScale = mesh->windWiggleScale, - .baseColorTextureIdx = material->HasBaseColorMap() ? scene->textureToBindlessIdx[material->baseColorMap.Get()] : 0, - .opacityTextureIdx = material->HasOpacityMap() ? scene->textureToBindlessIdx[material->opacityMap.Get()] : 0, - .normalTextureIdx = material->HasNormalMap() ? scene->textureToBindlessIdx[material->normalMap.Get()] : 0, - .roughnessTextureIdx = material->HasRoughnessMap() ? scene->textureToBindlessIdx[material->roughnessMap.Get()] : 0, - .metalnessTextureIdx = material->HasMetalnessMap() ? scene->textureToBindlessIdx[material->metalnessMap.Get()] : 0, - .aoTextureIdx = material->HasAoMap() ? scene->textureToBindlessIdx[material->aoMap.Get()] : 0, - .heightTextureIdx = material->HasDisplacementMap() ? scene->textureToBindlessIdx[material->displacementMap.Get()] : 0, + .baseColorTextureIdx = material->HasBaseColorMap() ? sceneState->textureToBindlessIdx[material->baseColorMap.Get()] : 0, + .opacityTextureIdx = material->HasOpacityMap() ? sceneState->textureToBindlessIdx[material->opacityMap.Get()] : 0, + .normalTextureIdx = material->HasNormalMap() ? sceneState->textureToBindlessIdx[material->normalMap.Get()] : 0, + .roughnessTextureIdx = material->HasRoughnessMap() ? sceneState->textureToBindlessIdx[material->roughnessMap.Get()] : 0, + .metalnessTextureIdx = material->HasMetalnessMap() ? sceneState->textureToBindlessIdx[material->metalnessMap.Get()] : 0, + .aoTextureIdx = material->HasAoMap() ? sceneState->textureToBindlessIdx[material->aoMap.Get()] : 0, + .heightTextureIdx = material->HasDisplacementMap() ? sceneState->textureToBindlessIdx[material->displacementMap.Get()] : 0, }; commandList->PushConstants("constants", &pushConstants); diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index a98d1d255..2e6f724aa 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -67,6 +67,8 @@ namespace Atlas { if (!light.shadow || !light.shadow->update) return; + auto sceneState = &scene->renderState; + Ref frameBuffer = nullptr; if (lightMap.contains(lightEntity)) frameBuffer = lightMap[lightEntity]; @@ -173,7 +175,7 @@ namespace Atlas { .windTextureLod = mesh->windNoiseTextureLod, .windBendScale = mesh->windBendScale, .windWiggleScale = mesh->windWiggleScale, - .textureID = material->HasOpacityMap() ? scene->textureToBindlessIdx[material->opacityMap.Get()] : 0 + .textureID = material->HasOpacityMap() ? sceneState->textureToBindlessIdx[material->opacityMap.Get()] : 0 }; commandList->PushConstants("constants", &pushConstants); diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index 1350235e4..ab9b18689 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -2,10 +2,23 @@ #include "../../System.h" +#include "lighting/IrradianceVolume.h" + namespace Atlas { namespace Renderer { + enum MaterialFeatures { + FEATURE_BASE_COLOR_MAP = (1 << 1), + FEATURE_OPACITY_MAP = (1 << 2), + FEATURE_NORMAL_MAP = (1 << 3), + FEATURE_ROUGHNESS_MAP = (1 << 4), + FEATURE_METALNESS_MAP = (1 << 5), + FEATURE_AO_MAP = (1 << 6), + FEATURE_TRANSMISSION = (1 << 7), + FEATURE_VERTEX_COLORS = (1 << 8) + }; + struct alignas(16) Cascade { float distance; float texelSize; diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 7ffdabcd5..6366a24db 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -98,8 +98,11 @@ namespace Atlas { CleanupUnusedResources(); #ifdef AE_BINDLESS - UpdateBindlessIndexMaps(); + renderState.UpdateMeshBindlessData(); + renderState.UpdateTextureBindlessData(); + renderState.UpdateOtherTextureBindlessData(); #endif + renderState.PrepareMaterials(); // Update scripting components (but only after the first timestep when everything else is settled) if (!firstTimestep) { @@ -193,13 +196,12 @@ namespace Atlas { // This part only needs to be executed if the simulation is running if (!physicsWorld->pauseSimulation) { - physicsWorld->Update(deltaTime); - - for (auto entity : rigidBodySubset) { - const auto& [rigidBodyComponent, transformComponent] = rigidBodySubset.Get(entity); + // Player update needs to be performed after normal rigid bodies, such that + // player can override rigid body behaviour + for (auto entity : playerSubset) { + const auto& [playerComponent, transformComponent] = playerSubset.Get(entity); - if (!rigidBodyComponent.IsValid() || transformComponent.isStatic || - rigidBodyComponent.layer == Physics::Layers::Static) + if (!playerComponent.IsValid()) continue; // This happens if no change was triggered by the user, then we still need @@ -212,16 +214,17 @@ namespace Atlas { transformComponent.updated = true; // Physics are updated in global space, so we don't need the parent transform - transformComponent.globalMatrix = rigidBodyComponent.GetMatrix(); + transformComponent.globalMatrix = playerComponent.GetMatrix(); transformComponent.inverseGlobalMatrix = glm::inverse(transformComponent.globalMatrix); } - // Player update needs to be performed after normal rigid bodies, such that - // player can override rigid body behaviour - for (auto entity : playerSubset) { - const auto& [playerComponent, transformComponent] = playerSubset.Get(entity); + physicsWorld->Update(deltaTime); - if (!playerComponent.IsValid()) + for (auto entity : rigidBodySubset) { + const auto& [rigidBodyComponent, transformComponent] = rigidBodySubset.Get(entity); + + if (!rigidBodyComponent.IsValid() || transformComponent.isStatic || + rigidBodyComponent.layer == Physics::Layers::Static) continue; // This happens if no change was triggered by the user, then we still need @@ -234,7 +237,7 @@ namespace Atlas { transformComponent.updated = true; // Physics are updated in global space, so we don't need the parent transform - transformComponent.globalMatrix = playerComponent.GetMatrix(); + transformComponent.globalMatrix = rigidBodyComponent.GetMatrix(); transformComponent.inverseGlobalMatrix = glm::inverse(transformComponent.globalMatrix); } } @@ -284,7 +287,7 @@ namespace Atlas { #ifdef AE_BINDLESS auto rayTracingSubset = GetSubset(); - JobSystem::Execute(rayTracingWorldUpdateJob, [this, rayTracingSubset](JobData&) { + JobSystem::Execute(renderState.rayTracingWorldUpdateJob, [this, rayTracingSubset](JobData&) { // Need to wait before updating graphic resources Graphics::GraphicsDevice::DefaultDevice->WaitForPreviousFrameSubmission(); if (rayTracingWorld) { @@ -568,9 +571,11 @@ namespace Atlas { void Scene::WaitForAsyncWorkCompletion() { - JobSystem::Wait(bindlessMeshMapUpdateJob); - JobSystem::Wait(bindlessTextureMapUpdateJob); - JobSystem::Wait(rayTracingWorldUpdateJob); + JobSystem::Wait(renderState.bindlessMeshMapUpdateJob); + JobSystem::Wait(renderState.bindlessTextureMapUpdateJob); + JobSystem::Wait(renderState.bindlessOtherTextureMapUpdateJob); + JobSystem::Wait(renderState.materialUpdateJob); + JobSystem::Wait(renderState.rayTracingWorldUpdateJob); } @@ -618,81 +623,6 @@ namespace Atlas { } - void Scene::UpdateBindlessIndexMaps() { - - JobSystem::Execute(bindlessMeshMapUpdateJob, [&](JobData&) { - auto meshes = GetMeshes(); - meshIdToBindlessIdx.clear(); - - uint32_t bufferIdx = 0; - for (const auto& mesh : meshes) { - if (!mesh.IsLoaded()) continue; - - // Not all meshes might have a bvh - if (!mesh->IsBVHBuilt()) - continue; - - meshIdToBindlessIdx[mesh.GetID()] = bufferIdx++; - } - }); - - JobSystem::Execute(bindlessTextureMapUpdateJob, [&](JobData&) { - auto meshes = GetMeshes(); - textureToBindlessIdx.clear(); - - std::set> materials; - std::set> textures; - - uint32_t textureIdx = 0; - for (const auto& mesh : meshes) { - if (!mesh.IsLoaded()) continue; - - for (auto& material : mesh->data.materials) - if (material.IsLoaded()) - materials.insert(material.Get()); - } - - for (const auto& material : materials) { - if (material->HasBaseColorMap()) - textures.insert(material->baseColorMap.Get()); - if (material->HasOpacityMap()) - textures.insert(material->opacityMap.Get()); - if (material->HasNormalMap()) - textures.insert(material->normalMap.Get()); - if (material->HasRoughnessMap()) - textures.insert(material->roughnessMap.Get()); - if (material->HasMetalnessMap()) - textures.insert(material->metalnessMap.Get()); - if (material->HasAoMap()) - textures.insert(material->aoMap.Get()); - if (material->HasDisplacementMap()) - textures.insert(material->displacementMap.Get()); - } - - for (const auto& texture : textures) { - - textureToBindlessIdx[texture] = textureIdx++; - - } - }); - - auto lightSubset = entityManager.GetSubset(); - for (auto entity : lightSubset) { - const auto& lightComponent = lightSubset.Get(entity); - - if (!lightComponent.shadow) - continue; - - if (lightComponent.shadow->useCubemap) { - - } - else { - - } - } - - } - void Scene::CleanupUnusedResources() { CleanupUnusedResources(registeredMeshes); diff --git a/src/engine/scene/Scene.h b/src/engine/scene/Scene.h index 579f17851..e295d06c1 100644 --- a/src/engine/scene/Scene.h +++ b/src/engine/scene/Scene.h @@ -21,6 +21,7 @@ #include "../mesh/Mesh.h" #include "SceneIterator.h" +#include "SceneRenderState.h" #include "SpacePartitioning.h" #include "Subset.h" #include "Wind.h" @@ -58,12 +59,13 @@ namespace Atlas { }; public: - Scene() : SpacePartitioning(this, vec3(-2048.0f), vec3(2048.0f), 5) { RegisterSubscribers(); } + Scene() : SpacePartitioning(this, vec3(-2048.0f), vec3(2048.0f), 5), renderState(this) + { RegisterSubscribers(); } Scene(const Scene& that) = delete; explicit Scene(const std::string& name) : SpacePartitioning(this, vec3(-2048.0f), vec3(2048.0f), 5), - name(name) { RegisterSubscribers(); } + name(name), renderState(this) { RegisterSubscribers(); } explicit Scene(const std::string& name, vec3 min, vec3 max, int32_t depth = 5) - : SpacePartitioning(this, min, max, depth), name(name) { RegisterSubscribers(); } + : SpacePartitioning(this, min, max, depth), name(name), renderState(this) { RegisterSubscribers(); } ~Scene(); @@ -143,12 +145,9 @@ namespace Atlas { Ref sss = nullptr; PostProcessing::PostProcessing postProcessing; - std::unordered_map, uint32_t> textureToBindlessIdx; - std::unordered_map meshIdToBindlessIdx; + SceneRenderState renderState; private: - void UpdateBindlessIndexMaps(); - Entity ToSceneEntity(ECS::Entity entity); void RegisterSubscribers(); @@ -182,12 +181,9 @@ namespace Atlas { Scripting::LuaScriptManager luaScriptManager = Scripting::LuaScriptManager(this); - JobGroup rayTracingWorldUpdateJob { JobPriority::High }; - JobGroup bindlessMeshMapUpdateJob { JobPriority::High }; - JobGroup bindlessTextureMapUpdateJob { JobPriority::High }; - friend Entity; friend SpacePartitioning; + friend SceneRenderState; friend RayTracing::RayTracingWorld; friend HierarchyComponent; friend MeshComponent; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp new file mode 100644 index 000000000..5aa1ef86a --- /dev/null +++ b/src/engine/scene/SceneRenderState.cpp @@ -0,0 +1,284 @@ +#include "SceneRenderState.h" +#include "Scene.h" + +#include "common/ColorConverter.h" +#include "common/Packing.h" + +// Move most of the things in the main renderer, like the bindless update or the materials to here +// Also move rendering related map updates from the scene to here +namespace Atlas::Scene { + + SceneRenderState::SceneRenderState(Scene* scene) : scene(scene) { + + materialBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | + Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit, sizeof(Renderer::PackedMaterial)); + + } + + void SceneRenderState::PrepareMaterials() { + + JobSystem::Execute(materialUpdateJob, [&](JobData&) { + auto sceneMaterials = scene->GetMaterials(); + + // For debugging purpose + if (scene->irradianceVolume && scene->irradianceVolume->debug) { + const auto& internalVolume = scene->irradianceVolume->internal; + sceneMaterials.push_back(internalVolume.probeDebugMaterial); + sceneMaterials.push_back(internalVolume.probeDebugActiveMaterial); + sceneMaterials.push_back(internalVolume.probeDebugInactiveMaterial); + sceneMaterials.push_back(internalVolume.probeDebugOffsetMaterial); + } + + uint16_t idx = 0; + + if (!materials.empty()) { + materials.clear(); + materialMap.clear(); + } + + for (auto material : sceneMaterials) { + // Might happen due to the scene giving back materials on a mesh basis + if (materialMap.contains(material.get())) + continue; + + Renderer::PackedMaterial packed; + + packed.baseColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(material->baseColor), 0.0f)); + packed.emissiveColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(material->emissiveColor), 0.0f)); + packed.transmissionColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(material->transmissiveColor), 0.0f)); + + packed.emissiveIntensityTiling = glm::packHalf2x16(vec2(material->emissiveIntensity, material->tiling)); + + vec4 data0, data1, data2; + + data0.x = material->opacity; + data0.y = material->roughness; + data0.z = material->metalness; + + data1.x = material->ao; + data1.y = material->HasNormalMap() ? material->normalScale : 0.0f; + data1.z = material->HasDisplacementMap() ? material->displacementScale : 0.0f; + + data2.x = material->reflectance; + // Note used + data2.y = 0.0f; + data2.z = 0.0f; + + packed.data0 = Common::Packing::PackUnsignedVector3x10_1x2(data0); + packed.data1 = Common::Packing::PackUnsignedVector3x10_1x2(data1); + packed.data2 = Common::Packing::PackUnsignedVector3x10_1x2(data2); + + packed.features = 0; + + packed.features |= material->HasBaseColorMap() ? Renderer::MaterialFeatures::FEATURE_BASE_COLOR_MAP : 0; + packed.features |= material->HasOpacityMap() ? Renderer::MaterialFeatures::FEATURE_OPACITY_MAP : 0; + packed.features |= material->HasNormalMap() ? Renderer::MaterialFeatures::FEATURE_NORMAL_MAP : 0; + packed.features |= material->HasRoughnessMap() ? Renderer::MaterialFeatures::FEATURE_ROUGHNESS_MAP : 0; + packed.features |= material->HasMetalnessMap() ? Renderer::MaterialFeatures::FEATURE_METALNESS_MAP : 0; + packed.features |= material->HasAoMap() ? Renderer::MaterialFeatures::FEATURE_AO_MAP : 0; + packed.features |= glm::length(material->transmissiveColor) > 0.0f ? Renderer::MaterialFeatures::FEATURE_TRANSMISSION : 0; + packed.features |= material->vertexColors ? Renderer::MaterialFeatures::FEATURE_VERTEX_COLORS : 0; + + materials.push_back(packed); + + materialMap[material.get()] = idx++; + } + + auto meshes = scene->GetMeshes(); + + for (auto mesh : meshes) { + if (!mesh.IsLoaded()) + continue; + + auto impostor = mesh->impostor; + + if (!impostor) + continue; + + Renderer::PackedMaterial packed; + + packed.baseColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(1.0f)); + packed.emissiveColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(0.0f)); + packed.transmissionColor = Common::Packing::PackUnsignedVector3x10_1x2(vec4(Common::ColorConverter::ConvertSRGBToLinear(impostor->transmissiveColor), 1.0f)); + + vec4 data0, data1, data2; + + data0.x = 1.0f; + data0.y = 1.0f; + data0.z = 1.0f; + + data1.x = 1.0f; + data1.y = 0.0f; + data1.z = 0.0f; + + data2.x = 0.5f; + // Note used + data2.y = 0.0f; + data2.z = 0.0f; + + packed.data0 = Common::Packing::PackUnsignedVector3x10_1x2(data0); + packed.data1 = Common::Packing::PackUnsignedVector3x10_1x2(data1); + packed.data2 = Common::Packing::PackUnsignedVector3x10_1x2(data2); + + packed.features = 0; + + packed.features |= Renderer::MaterialFeatures::FEATURE_BASE_COLOR_MAP | + Renderer::MaterialFeatures::FEATURE_ROUGHNESS_MAP | + Renderer::MaterialFeatures::FEATURE_METALNESS_MAP | + Renderer::MaterialFeatures::FEATURE_AO_MAP; + packed.features |= glm::length(impostor->transmissiveColor) > 0.0f ? + Renderer::MaterialFeatures::FEATURE_TRANSMISSION : 0; + + materials.push_back(packed); + + materialMap[impostor.get()] = idx++; + } + + if (materials.size() > materialBuffer.GetElementCount()) { + materialBuffer.SetSize(materials.size()); + } + + materialBuffer.SetData(materials.data(), 0, materials.size()); + + }); + + } + + void SceneRenderState::UpdateMeshBindlessData() { + + auto bindlessMeshBuffersUpdate = [&](JobData&) { + JobSystem::Wait(bindlessMeshMapUpdateJob); + + if (blasBuffers.size() < meshIdToBindlessIdx.size()) { + blasBuffers.resize(meshIdToBindlessIdx.size()); + triangleBuffers.resize(meshIdToBindlessIdx.size()); + bvhTriangleBuffers.resize(meshIdToBindlessIdx.size()); + triangleOffsetBuffers.resize(meshIdToBindlessIdx.size()); + } + + for (const auto& [meshId, idx] : meshIdToBindlessIdx) { + if (!scene->registeredMeshes.contains(meshId)) continue; + + const auto& mesh = scene->registeredMeshes[meshId].resource; + + auto blasBuffer = mesh->blasNodeBuffer.Get(); + auto triangleBuffer = mesh->triangleBuffer.Get(); + auto bvhTriangleBuffer = mesh->bvhTriangleBuffer.Get(); + auto triangleOffsetBuffer = mesh->triangleOffsetBuffer.Get(); + + AE_ASSERT(triangleBuffer != nullptr); + + blasBuffers[idx] = blasBuffer; + triangleBuffers[idx] = triangleBuffer; + bvhTriangleBuffers[idx] = bvhTriangleBuffer; + triangleOffsetBuffers[idx] = triangleOffsetBuffer; + } + }; + + auto bindlessMeshMapUpdate = [&, bindlessMeshBuffersUpdate](JobData&) { + auto meshes = scene->GetMeshes(); + + meshIdToBindlessIdx.clear(); + + uint32_t bufferIdx = 0; + for (const auto& mesh : meshes) { + if (!mesh.IsLoaded()) continue; + + // Not all meshes might have a bvh + if (!mesh->IsBVHBuilt()) + continue; + + meshIdToBindlessIdx[mesh.GetID()] = bufferIdx++; + } + + JobSystem::Execute(prepareBindlessMeshesJob, bindlessMeshBuffersUpdate); + }; + + JobSystem::Execute(bindlessMeshMapUpdateJob, bindlessMeshMapUpdate); + + } + + void SceneRenderState::UpdateTextureBindlessData() { + + auto bindlessTextureBuffersUpdate = [&](JobData&) { + JobSystem::Wait(bindlessTextureMapUpdateJob); + + if (images.size() < textureToBindlessIdx.size()) { + images.resize(textureToBindlessIdx.size()); + } + + for (const auto& [texture, idx] : textureToBindlessIdx) { + + images[idx] = texture->image; + + } + }; + + auto bindlessTextureMapUpdate = [&, bindlessTextureBuffersUpdate](JobData&) { + auto meshes = scene->GetMeshes(); + textureToBindlessIdx.clear(); + + std::set> materials; + std::set> textures; + + uint32_t textureIdx = 0; + for (const auto& mesh : meshes) { + if (!mesh.IsLoaded()) continue; + + for (auto& material : mesh->data.materials) + if (material.IsLoaded()) + materials.insert(material.Get()); + } + + for (const auto& material : materials) { + if (material->HasBaseColorMap()) + textures.insert(material->baseColorMap.Get()); + if (material->HasOpacityMap()) + textures.insert(material->opacityMap.Get()); + if (material->HasNormalMap()) + textures.insert(material->normalMap.Get()); + if (material->HasRoughnessMap()) + textures.insert(material->roughnessMap.Get()); + if (material->HasMetalnessMap()) + textures.insert(material->metalnessMap.Get()); + if (material->HasAoMap()) + textures.insert(material->aoMap.Get()); + if (material->HasDisplacementMap()) + textures.insert(material->displacementMap.Get()); + } + + for (const auto& texture : textures) { + + textureToBindlessIdx[texture] = textureIdx++; + + } + + JobSystem::Execute(prepareBindlessTexturesJob, bindlessTextureBuffersUpdate); + }; + + JobSystem::Execute(bindlessTextureMapUpdateJob, bindlessTextureMapUpdate); + + } + + void SceneRenderState::UpdateOtherTextureBindlessData() { + + JobSystem::Execute(bindlessOtherTextureMapUpdateJob, [&](JobData&) { + auto lightSubset = scene->entityManager.GetSubset(); + for (auto entity : lightSubset) { + const auto& lightComponent = lightSubset.Get(entity); + + if (!lightComponent.shadow) + continue; + + if (lightComponent.shadow->useCubemap) { + + } + else { + + } + } + }); + + } + +} \ No newline at end of file diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h new file mode 100644 index 000000000..e03a1668d --- /dev/null +++ b/src/engine/scene/SceneRenderState.h @@ -0,0 +1,57 @@ +#pragma once + +#include "jobsystem/JobGroup.h" +#include "texture/Texture2D.h" +#include "texture/Texture2DArray.h" +#include "texture/Cubemap.h" + +#include "buffer/UniformBuffer.h" + +#include "renderer/helper/CommonStructures.h" + +#include + +namespace Atlas::Scene { + + class Scene; + + class SceneRenderState { + + public: + SceneRenderState(Scene* scene); + + void PrepareMaterials(); + + void UpdateMeshBindlessData(); + + void UpdateTextureBindlessData(); + + void UpdateOtherTextureBindlessData(); + + Scene* scene; + + Buffer::Buffer materialBuffer; + std::vector> images; + std::vector> blasBuffers; + std::vector> triangleBuffers; + std::vector> bvhTriangleBuffers; + std::vector> triangleOffsetBuffers; + + std::vector materials; + std::unordered_map materialMap; + std::unordered_map, uint32_t> textureToBindlessIdx; + std::unordered_map, uint32_t> textureArrayToBindlessIdx; + std::unordered_map, uint32_t> cubemapToBindlessIdx; + std::unordered_map meshIdToBindlessIdx; + + JobGroup materialUpdateJob { JobPriority::High }; + JobGroup rayTracingWorldUpdateJob { JobPriority::High }; + JobGroup bindlessMeshMapUpdateJob { JobPriority::High }; + JobGroup bindlessTextureMapUpdateJob { JobPriority::High }; + JobGroup bindlessOtherTextureMapUpdateJob { JobPriority::High }; + JobGroup prepareBindlessMeshesJob { JobPriority::High }; + JobGroup prepareBindlessTexturesJob { JobPriority::High }; + + }; + +} \ No newline at end of file diff --git a/src/engine/volume/BVH.cpp b/src/engine/volume/BVH.cpp index 233198c5b..225748693 100644 --- a/src/engine/volume/BVH.cpp +++ b/src/engine/volume/BVH.cpp @@ -372,7 +372,7 @@ namespace Atlas { refs.clear(); refs.shrink_to_fit(); - if (depth <= 6 && parallelBuild) { + if (depth <= 8 && parallelBuild) { auto leftRefSize = leftRefs.size(), rightRefSize = rightRefs.size(); auto leftLambda = [=, &jobGroup, leftRefs = std::move(leftRefs)](JobData&) { auto refs = std::move(leftRefs); From 9c8c6ee048cffbe8770b7359e4174a23ba3730ef Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 27 Aug 2024 14:42:24 +0200 Subject: [PATCH 09/66] Fixed a few things + started working on bloom --- data/shader/bloom | 12 - data/shader/bloom.fsh | 16 -- data/shader/bloom.vsh | 10 - data/shader/bloom/bloom.hsh | 0 data/shader/bloom/bloomDownsample.csh | 62 +++++ data/shader/bloom/bloomUpsample.csh | 0 .../panels/PostProcessingPanel.cpp | 2 + src/engine/jobsystem/Job.h | 1 + src/engine/jobsystem/JobSystem.cpp | 13 +- src/engine/jobsystem/JobSystem.h | 2 + src/engine/jobsystem/PriorityPool.cpp | 12 +- src/engine/jobsystem/Signal.h | 34 +++ src/engine/jobsystem/ThreadSafeJobQueue.cpp | 7 + src/engine/jobsystem/ThreadSafeJobQueue.h | 2 + src/engine/jobsystem/Worker.cpp | 3 +- src/engine/jobsystem/Worker.h | 9 +- src/engine/physics/ShapesManager.cpp | 7 +- src/engine/postprocessing/Bloom.h | 18 ++ src/engine/postprocessing/PostProcessing.h | 2 + src/engine/renderer/DirectLightRenderer.cpp | 8 +- src/engine/renderer/DirectLightRenderer.h | 3 +- src/engine/renderer/MainRenderer.cpp | 126 +++------ src/engine/renderer/MainRenderer.h | 6 - src/engine/renderer/PostProcessRenderer.cpp | 68 ++++- src/engine/renderer/PostProcessRenderer.h | 3 + src/engine/renderer/helper/LightData.cpp | 127 --------- src/engine/renderer/helper/LightData.h | 34 --- src/engine/renderer/helper/RenderList.cpp | 4 +- src/engine/renderer/helper/RenderList.h | 8 +- src/engine/renderer/target/RenderTarget.cpp | 5 +- src/engine/renderer/target/RenderTarget.h | 1 + src/engine/scene/Scene.cpp | 8 +- src/engine/scene/SceneRenderState.cpp | 242 ++++++++++++++++-- src/engine/scene/SceneRenderState.h | 39 ++- src/engine/volume/BVH.cpp | 24 +- src/tests/App.cpp | 18 +- src/tests/App.h | 2 +- src/tests/Main.cpp | 1 + 38 files changed, 560 insertions(+), 379 deletions(-) delete mode 100644 data/shader/bloom delete mode 100644 data/shader/bloom.fsh delete mode 100644 data/shader/bloom.vsh create mode 100644 data/shader/bloom/bloom.hsh create mode 100644 data/shader/bloom/bloomDownsample.csh create mode 100644 data/shader/bloom/bloomUpsample.csh create mode 100644 src/engine/jobsystem/Signal.h create mode 100644 src/engine/postprocessing/Bloom.h delete mode 100644 src/engine/renderer/helper/LightData.cpp delete mode 100644 src/engine/renderer/helper/LightData.h diff --git a/data/shader/bloom b/data/shader/bloom deleted file mode 100644 index d612e268e..000000000 --- a/data/shader/bloom +++ /dev/null @@ -1,12 +0,0 @@ -uniform bool bloom; - -vec3 CalculateBloom(vec3 color) { - - if(bloom) { - - float brightness = dot(color, vec3(1.0f)); - return max(color * (brightness), 0.0f); - - } - -} \ No newline at end of file diff --git a/data/shader/bloom.fsh b/data/shader/bloom.fsh deleted file mode 100644 index b0fa66582..000000000 --- a/data/shader/bloom.fsh +++ /dev/null @@ -1,16 +0,0 @@ -in vec2 fTexCoord; - -uniform sampler2D diffuseMap; -uniform vec3 bloomThreshold; -uniform float bloomPower; - -out vec3 color; - -void main() { - - vec3 fragColor = texture(diffuseMap, fTexCoord).rgb; - - float bloomBrightness = pow(dot(fragColor.xyz, bloomThreshold.xyz), bloomPower); - color = fragColor.xyz * bloomBrightness; - -} \ No newline at end of file diff --git a/data/shader/bloom.vsh b/data/shader/bloom.vsh deleted file mode 100644 index d0f26ddaf..000000000 --- a/data/shader/bloom.vsh +++ /dev/null @@ -1,10 +0,0 @@ -layout(location=0)in vec2 vPosition; - -out vec2 fTexCoord; - -void main() { - - fTexCoord = (vPosition + 1.0) / 2.0; - gl_Position = vec4(vPosition, 0.0, 1.0); - -} \ No newline at end of file diff --git a/data/shader/bloom/bloom.hsh b/data/shader/bloom/bloom.hsh new file mode 100644 index 000000000..e69de29bb diff --git a/data/shader/bloom/bloomDownsample.csh b/data/shader/bloom/bloomDownsample.csh new file mode 100644 index 000000000..8d970a594 --- /dev/null +++ b/data/shader/bloom/bloomDownsample.csh @@ -0,0 +1,62 @@ +layout (local_size_x = 8, local_size_y = 8) in; + +#include +#include + +layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; +layout (set = 3, binding = 1) uniform sampler2D textureIn; + +layout(push_constant) uniform constants { + int mipLevel; +} pushConstants; + +vec3 Sample(vec2 texCoord) { + + return textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb; + +} + +void main() { + + ivec2 size = imageSize(textureOut); + ivec2 coord = ivec2(gl_GlobalInvocationID); + + if (coord.x < size.x && + coord.y < size.y) { + + // Lower mip tex coord + vec2 texCoord = (coord + 0.5) / size; + // Upper mip texel size + vec2 texelSize = 1.0 / vec2(textureSize(textureIn, pushConstants.mipLevel)); + + // We always sample at pixel border, not centers + vec3 outer00 = Sample(texCoord + vec2(-2.0 * texelSize.x, -2.0 * texelSize.y)); + vec3 outer10 = Sample(texCoord + vec2(0.0, -2.0 * texelSize.y)); + vec3 outer20 = Sample(texCoord + vec2(2.0 * texelSize.x, -2.0 * texelSize.y)); + + vec3 outer01 = Sample(texCoord + vec2(-2.0 * texelSize.x, 0.0)); + vec3 outer11 = Sample(texCoord + vec2(0.0, 0.0)); + vec3 outer21 = Sample(texCoord + vec2(2.0 * texelSize.x, 0.0)); + + vec3 outer02 = Sample(texCoord + vec2(-2.0 * texelSize.x, 2.0 * texelSize.y)); + vec3 outer12 = Sample(texCoord + vec2(0.0, 2.0 * texelSize.y)); + vec3 outer22 = Sample(texCoord + vec2(2.0 * texelSize.x, 2.0 * texelSize.y)); + + vec3 inner00 = Sample(texCoord + vec2(-texelSize.x, -texelSize.y)); + vec3 inner10 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); + vec3 inner01 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); + vec3 inner11 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); + + vec3 filtered = vec3(0.0); + + filtered += 0.125 * (outer00 + outer10 + outer01 + outer11) * 0.25; + filtered += 0.125 * (outer10 + outer20 + outer11 + outer21) * 0.25; + filtered += 0.125 * (outer01 + outer11 + outer02 + outer12) * 0.25; + filtered += 0.125 * (outer11 + outer21 + outer12 + outer22) * 0.25; + filtered += 0.5 * (inner00 + inner10 + inner01 + inner11) * 0.25; + + imageStore(textureOut, coord, vec4(filtered, 1.0)); + + } + +} \ No newline at end of file diff --git a/data/shader/bloom/bloomUpsample.csh b/data/shader/bloom/bloomUpsample.csh new file mode 100644 index 000000000..e69de29bb diff --git a/libs/ImguiExtension/panels/PostProcessingPanel.cpp b/libs/ImguiExtension/panels/PostProcessingPanel.cpp index 04b4aea86..c3934d11b 100644 --- a/libs/ImguiExtension/panels/PostProcessingPanel.cpp +++ b/libs/ImguiExtension/panels/PostProcessingPanel.cpp @@ -31,6 +31,8 @@ namespace Atlas::ImguiExtension { ImGui::Text("Film grain"); ImGui::Checkbox("Enable##Film grain", &postProcessing.filmGrain.enable); ImGui::SliderFloat("Strength##Film grain", &postProcessing.filmGrain.strength, 0.0f, 1.0f); + ImGui::Text("Bloom"); + ImGui::Checkbox("Enable##Bloom", &postProcessing.bloom.enable); ImGui::PopID(); diff --git a/src/engine/jobsystem/Job.h b/src/engine/jobsystem/Job.h index 59c789d63..b0eb8f043 100644 --- a/src/engine/jobsystem/Job.h +++ b/src/engine/jobsystem/Job.h @@ -16,6 +16,7 @@ namespace Atlas { struct JobData { int32_t idx = 0; + int32_t workerIdx = 0; void* userData = nullptr; }; diff --git a/src/engine/jobsystem/JobSystem.cpp b/src/engine/jobsystem/JobSystem.cpp index b0874e606..078f8da07 100644 --- a/src/engine/jobsystem/JobSystem.cpp +++ b/src/engine/jobsystem/JobSystem.cpp @@ -65,7 +65,7 @@ namespace Atlas { auto& worker = priorityPool.GetNextWorker(); worker.queue.Push(job); - worker.semaphore.release(); + worker.signal.Notify(); } @@ -87,7 +87,7 @@ namespace Atlas { job.idx = i; worker.queue.Push(job); - worker.semaphore.release(); + worker.signal.Notify(); } return; } @@ -110,7 +110,7 @@ namespace Atlas { auto& worker = priorityPool.GetNextWorker(); worker.queue.PushMultiple(jobs); - worker.semaphore.release(); + worker.signal.Notify(); jobs.clear(); remainingJobs -= jobsToPush; @@ -156,4 +156,11 @@ namespace Atlas { } + int32_t JobSystem::GetWorkerCount(const JobPriority priority) { + + auto& priorityPool = priorityPools[static_cast(priority)]; + return priorityPool.workerCount; + + } + } \ No newline at end of file diff --git a/src/engine/jobsystem/JobSystem.h b/src/engine/jobsystem/JobSystem.h index e028c12d7..a61155697 100644 --- a/src/engine/jobsystem/JobSystem.h +++ b/src/engine/jobsystem/JobSystem.h @@ -38,6 +38,8 @@ namespace Atlas { static void WaitSpin(JobGroup& group); static void WaitAll(); + + static int32_t GetWorkerCount(const JobPriority priority); private: static PriorityPool priorityPools[static_cast(JobPriority::Count)]; diff --git a/src/engine/jobsystem/PriorityPool.cpp b/src/engine/jobsystem/PriorityPool.cpp index 87ab6f9a5..53681afea 100644 --- a/src/engine/jobsystem/PriorityPool.cpp +++ b/src/engine/jobsystem/PriorityPool.cpp @@ -15,9 +15,11 @@ namespace Atlas { for (int32_t i = 0; i < workerCount; i++) { workers[i].Start([&](Worker& worker) { while (!shutdown) { - worker.semaphore.acquire(); + worker.signal.Wait(); + Work(worker.workerId); } + worker.quit = true; }); } @@ -27,7 +29,11 @@ namespace Atlas { shutdown = true; for (auto& worker : workers) { - worker.semaphore.release(); + // Try to get it to quit + while(!worker.quit) { + worker.signal.Notify(); + std::this_thread::yield(); + } worker.thread.join(); } @@ -60,4 +66,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/jobsystem/Signal.h b/src/engine/jobsystem/Signal.h new file mode 100644 index 000000000..accd675b1 --- /dev/null +++ b/src/engine/jobsystem/Signal.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +namespace Atlas { + + // This whole construct is here to avoid undefined behaviour of the semaphore when released more than once before one acquire + class Signal { + + public: + inline void Notify() { + + bool expected = false; + if (condition.compare_exchange_strong(expected, true)) { + semaphore.release(); + } + + } + + inline void Wait() { + + semaphore.acquire(); + condition = false; + + } + + private: + std::atomic_bool condition {false}; + std::binary_semaphore semaphore {0}; + + }; + +} \ No newline at end of file diff --git a/src/engine/jobsystem/ThreadSafeJobQueue.cpp b/src/engine/jobsystem/ThreadSafeJobQueue.cpp index f5da60ea8..e32a2ac6b 100644 --- a/src/engine/jobsystem/ThreadSafeJobQueue.cpp +++ b/src/engine/jobsystem/ThreadSafeJobQueue.cpp @@ -2,6 +2,13 @@ namespace Atlas { + bool ThreadSafeJobQueue::Empty() { + + std::scoped_lock lock(mutex); + return jobs.empty(); + + } + void ThreadSafeJobQueue::Push(const Job& job) { std::scoped_lock lock(mutex); diff --git a/src/engine/jobsystem/ThreadSafeJobQueue.h b/src/engine/jobsystem/ThreadSafeJobQueue.h index 1e3053473..159a78830 100644 --- a/src/engine/jobsystem/ThreadSafeJobQueue.h +++ b/src/engine/jobsystem/ThreadSafeJobQueue.h @@ -14,6 +14,8 @@ namespace Atlas { public: ThreadSafeJobQueue() = default; + bool Empty(); + void Push(const Job& job); void PushMultiple(const std::vector& jobs); diff --git a/src/engine/jobsystem/Worker.cpp b/src/engine/jobsystem/Worker.cpp index e373b4bfd..e83f40352 100644 --- a/src/engine/jobsystem/Worker.cpp +++ b/src/engine/jobsystem/Worker.cpp @@ -9,7 +9,6 @@ #include #endif - namespace Atlas { Worker::Worker(int32_t workerId, JobPriority priority) : workerId(workerId), priority(priority) { @@ -54,4 +53,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/jobsystem/Worker.h b/src/engine/jobsystem/Worker.h index 40dde4253..2b1777b2c 100644 --- a/src/engine/jobsystem/Worker.h +++ b/src/engine/jobsystem/Worker.h @@ -2,10 +2,10 @@ #include "../System.h" +#include "Signal.h" #include "ThreadSafeJobQueue.h" #include -#include namespace Atlas { @@ -36,7 +36,9 @@ namespace Atlas { JobPriority priority; std::thread thread; - std::binary_semaphore semaphore{0}; + std::atomic_bool quit = false; + + Signal signal; ThreadSafeJobQueue queue; private: @@ -44,6 +46,7 @@ namespace Atlas { JobData data = { .idx = job.idx, + .workerIdx = workerId, .userData = job.userData }; @@ -55,4 +58,4 @@ namespace Atlas { }; -} \ No newline at end of file +} diff --git a/src/engine/physics/ShapesManager.cpp b/src/engine/physics/ShapesManager.cpp index 8a03bdeb6..78c2fa030 100644 --- a/src/engine/physics/ShapesManager.cpp +++ b/src/engine/physics/ShapesManager.cpp @@ -29,7 +29,9 @@ namespace Atlas { const auto& scale = settings.scale; // This all assumes right now that mesh data doesn't change in the objects lifetime + meshShapeCacheMutex.lock(); if (!meshShapeCache.contains(mesh.GetID())) { + meshShapeCacheMutex.unlock(); JPH::VertexList vertexList; JPH::IndexedTriangleList triangleList; @@ -59,6 +61,7 @@ namespace Atlas { shape->ref = result.Get(); + meshShapeCacheMutex.lock(); meshShapeCache[mesh.GetID()] = { mesh.Get(), shape->ref }; } @@ -67,6 +70,7 @@ namespace Atlas { shape->ref = meshShapeCache[mesh.GetID()].ref; } + meshShapeCacheMutex.unlock(); if (scale.x != 1.0f || scale.y != 1.0f || scale.z != 1.0f) { return shape->Scale(scale); @@ -196,10 +200,11 @@ namespace Atlas { void ShapesManager::Update() { + std::scoped_lock lock(meshShapeCacheMutex); std::erase_if(meshShapeCache, [](auto& item) { return item.second.resource.expired(); } ); } } -} \ No newline at end of file +} diff --git a/src/engine/postprocessing/Bloom.h b/src/engine/postprocessing/Bloom.h new file mode 100644 index 000000000..f5aa12cd0 --- /dev/null +++ b/src/engine/postprocessing/Bloom.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../System.h" + +namespace Atlas::PostProcessing { + + class Bloom { + + public: + Bloom() = default; + + bool enable = true; + uint32_t mipLevels = 6; + + }; + + +} \ No newline at end of file diff --git a/src/engine/postprocessing/PostProcessing.h b/src/engine/postprocessing/PostProcessing.h index d12cd9ef9..7964800c6 100644 --- a/src/engine/postprocessing/PostProcessing.h +++ b/src/engine/postprocessing/PostProcessing.h @@ -7,6 +7,7 @@ #include "Sharpen.h" #include "FilmGrain.h" #include "TAA.h" +#include "Bloom.h" namespace Atlas { @@ -31,6 +32,7 @@ namespace Atlas { ChromaticAberration chromaticAberration; FilmGrain filmGrain; Sharpen sharpen; + Bloom bloom; }; diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index b490d5dd2..35a647cce 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -22,11 +22,13 @@ namespace Atlas { } void DirectLightRenderer::Render(Ref target, Ref scene, - Helper::LightData& lightData, Graphics::CommandList* commandList) { + Graphics::CommandList* commandList) { auto mainLightEntity = GetMainLightEntity(scene); if (!mainLightEntity.IsValid()) return; + auto renderState = &scene->renderState; + Graphics::Profiler::BeginQuery("Direct lighting"); auto& camera = scene->GetMainCamera(); @@ -38,9 +40,9 @@ namespace Atlas { std::vector> cubeMaps; PushConstants pushConstants; - pushConstants.lightCount = std::min(8, int32_t(lightData.lightEntities.size())); + pushConstants.lightCount = std::min(8, int32_t(renderState->lightEntities.size())); for (int32_t i = 0; i < pushConstants.lightCount; i++) { - auto& comp = lightData.lightEntities[i].comp; + auto& comp = renderState->lightEntities[i].comp; if (comp.shadow) { auto& shadow = comp.shadow; diff --git a/src/engine/renderer/DirectLightRenderer.h b/src/engine/renderer/DirectLightRenderer.h index a87529417..d27bdb331 100644 --- a/src/engine/renderer/DirectLightRenderer.h +++ b/src/engine/renderer/DirectLightRenderer.h @@ -1,7 +1,6 @@ #pragma once #include "Renderer.h" -#include "helper/LightData.h" namespace Atlas { @@ -15,7 +14,7 @@ namespace Atlas { void Init(Graphics::GraphicsDevice* device); void Render(Ref target, Ref scene, - Helper::LightData& lightData, Graphics::CommandList* commandList); + Graphics::CommandList* commandList); private: struct alignas(16) PushConstants { diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 6389ae493..d5a508d7d 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -97,16 +97,11 @@ namespace Atlas { camera.Jitter(vec2(0.0f)); } - auto sceneState = &scene->renderState; + auto renderState = &scene->renderState; Graphics::Profiler::BeginThread("Main renderer", commandList); Graphics::Profiler::BeginQuery("Render scene"); - JobGroup fillRenderListGroup { JobPriority::High }; - JobSystem::Execute(fillRenderListGroup, [&](JobData&) { FillRenderList(scene, camera); }); - - lightData.CullAndSort(scene); - SetUniforms(target, scene, camera); commandList->BindBuffer(globalUniformBuffer, 1, 31); @@ -137,33 +132,26 @@ namespace Atlas { volumetricCloudRenderer.RenderShadow(target, scene, commandList); - Log::Warning("Begin wait material"); - JobSystem::WaitSpin(sceneState->materialUpdateJob); - Log::Warning("End wait material"); - sceneState->materialBuffer.Bind(commandList, 1, 14); + JobSystem::WaitSpin(renderState->materialUpdateJob); + renderState->materialBuffer.Bind(commandList, 1, 14); // Wait as long as possible for this to finish - Log::Warning("Begin wait bindless"); - JobSystem::WaitSpin(sceneState->bindlessMeshMapUpdateJob); - JobSystem::WaitSpin(sceneState->bindlessTextureMapUpdateJob); - JobSystem::WaitSpin(sceneState->prepareBindlessMeshesJob); - JobSystem::WaitSpin(sceneState->prepareBindlessTexturesJob); - Log::Warning("End wait bindless"); - lightData.UpdateBindlessIndices(scene); - commandList->BindBuffers(sceneState->triangleBuffers, 0, 1); - if (sceneState->images.size()) - commandList->BindSampledImages(sceneState->images, 0, 3); + JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(renderState->prepareBindlessTexturesJob); + commandList->BindBuffers(renderState->triangleBuffers, 0, 1); + if (renderState->images.size()) + commandList->BindSampledImages(renderState->images, 0, 3); if (device->support.hardwareRayTracing) { - commandList->BindBuffers(sceneState->triangleOffsetBuffers, 0, 2); + commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); } else { - commandList->BindBuffers(sceneState->blasBuffers, 0, 0); - commandList->BindBuffers(sceneState->bvhTriangleBuffers, 0, 2); + commandList->BindBuffers(renderState->blasBuffers, 0, 0); + commandList->BindBuffers(renderState->bvhTriangleBuffers, 0, 2); } { - shadowRenderer.Render(target, scene, commandList, &renderList); + shadowRenderer.Render(target, scene, commandList, &renderState->renderList); terrainShadowRenderer.Render(target, scene, commandList); } @@ -197,32 +185,30 @@ namespace Atlas { commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } - Log::Warning("Begin wait ray tracing"); JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); - Log::Warning("End wait ray tracing"); - lightData.FillBuffer(scene); - lightData.lightBuffer.Bind(commandList, 1, 16); + JobSystem::WaitSpin(renderState->cullAndSortLightsJob); + renderState->lightBuffer.Bind(commandList, 1, 16); ddgiRenderer.TraceAndUpdateProbes(scene, commandList); // Only here does the main pass need to be ready - JobSystem::Wait(fillRenderListGroup); + JobSystem::Wait(renderState->fillRenderListJob); { Graphics::Profiler::BeginQuery("Main render pass"); commandList->BeginRenderPass(target->gBufferRenderPass, target->gBufferFrameBuffer, true); - opaqueRenderer.Render(target, scene, commandList, &renderList, sceneState->materialMap); + opaqueRenderer.Render(target, scene, commandList, &renderState->renderList, renderState->materialMap); - ddgiRenderer.DebugProbes(target, scene, commandList, sceneState->materialMap); + ddgiRenderer.DebugProbes(target, scene, commandList, renderState->materialMap); - vegetationRenderer.Render(target, scene, commandList, sceneState->materialMap); + vegetationRenderer.Render(target, scene, commandList, renderState->materialMap); - terrainRenderer.Render(target, scene, commandList, sceneState->materialMap); + terrainRenderer.Render(target, scene, commandList, renderState->materialMap); - impostorRenderer.Render(target, scene, commandList, &renderList, sceneState->materialMap); + impostorRenderer.Render(target, scene, commandList, &renderState->renderList, renderState->materialMap); commandList->EndRenderPass(); @@ -320,7 +306,7 @@ namespace Atlas { commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - directLightRenderer.Render(target, scene, lightData, commandList); + directLightRenderer.Render(target, scene, commandList); if (!scene->rtgi || !scene->rtgi->enable || !scene->IsRtDataValid()) { commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, @@ -401,7 +387,7 @@ namespace Atlas { commandList->EndCommands(); device->SubmitCommandList(commandList); - renderList.Clear(); + renderState->renderList.Clear(); } @@ -411,7 +397,7 @@ namespace Atlas { if (!scene->IsRtDataValid() || !device->swapChain->isComplete || !scene->HasMainCamera()) return; - auto sceneState = &scene->renderState; + auto renderState = &scene->renderState; static vec2 lastJitter = vec2(0.0f); @@ -455,23 +441,23 @@ namespace Atlas { pathTraceGlobalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); - JobSystem::WaitSpin(sceneState->prepareBindlessMeshesJob); - JobSystem::WaitSpin(sceneState->prepareBindlessTexturesJob); + JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(renderState->prepareBindlessTexturesJob); commandList->BindBuffer(pathTraceGlobalUniformBuffer, 1, 31); commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 12); commandList->BindSampler(globalSampler, 1, 13); commandList->BindSampler(globalNearestSampler, 1, 15); - commandList->BindBuffers(sceneState->triangleBuffers, 0, 1); - if (sceneState->images.size()) - commandList->BindSampledImages(sceneState->images, 0, 3); + commandList->BindBuffers(renderState->triangleBuffers, 0, 1); + if (renderState->images.size()) + commandList->BindSampledImages(renderState->images, 0, 3); if (device->support.hardwareRayTracing) { - commandList->BindBuffers(sceneState->triangleOffsetBuffers, 0, 2); + commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); } else { - commandList->BindBuffers(sceneState->blasBuffers, 0, 0); - commandList->BindBuffers(sceneState->bvhTriangleBuffers, 0, 2); + commandList->BindBuffers(renderState->blasBuffers, 0, 0); + commandList->BindBuffers(renderState->bvhTriangleBuffers, 0, 2); } @@ -1053,56 +1039,6 @@ namespace Atlas { } - void MainRenderer::FillRenderList(Ref scene, const CameraComponent& camera) { - - auto meshes = scene->GetMeshes(); - renderList.NewFrame(scene); - - auto lightSubset = scene->GetSubset(); - - JobGroup group; - for (auto& lightEntity : lightSubset) { - - auto& light = lightEntity.GetComponent(); - if (!light.shadow || !light.shadow->update) - continue; - - auto& shadow = light.shadow; - - auto componentCount = shadow->longRange ? - shadow->viewCount - 1 : shadow->viewCount; - - JobSystem::ExecuteMultiple(group, componentCount, - [&, shadow=shadow, lightEntity=lightEntity](JobData& data) { - auto component = &shadow->views[data.idx]; - auto frustum = Volume::Frustum(component->frustumMatrix); - - auto shadowPass = renderList.GetShadowPass(lightEntity, data.idx); - if (shadowPass == nullptr) - shadowPass = renderList.NewShadowPass(lightEntity, data.idx); - - shadowPass->NewFrame(scene, meshes); - scene->GetRenderList(frustum, shadowPass); - shadowPass->Update(camera.GetLocation()); - shadowPass->FillBuffers(); - renderList.FinishPass(shadowPass); - }); - } - - JobSystem::Wait(group); - - auto mainPass = renderList.GetMainPass(); - if (mainPass == nullptr) - mainPass = renderList.NewMainPass(); - - mainPass->NewFrame(scene, meshes); - scene->GetRenderList(camera.frustum, mainPass); - mainPass->Update(camera.GetLocation()); - mainPass->FillBuffers(); - renderList.FinishPass(mainPass); - - } - void MainRenderer::PreintegrateBRDF() { auto pipelineConfig = PipelineConfig("brdf/preintegrateDFG.csh"); diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index d07adc197..b60e2a59c 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -4,7 +4,6 @@ #include "../graphics/GraphicsDevice.h" #include "PrimitiveBatch.h" -#include "helper/LightData.h" #include "OpaqueRenderer.h" #include "ImpostorRenderer.h" @@ -74,8 +73,6 @@ namespace Atlas { void SetUniforms(const Ref& target, const Ref& scene, const CameraComponent& camera); - void FillRenderList(Ref scene, const CameraComponent& camera); - void PreintegrateBRDF(); PipelineConfig GetPipelineConfigForPrimitives(Ref& frameBuffer, @@ -121,9 +118,6 @@ namespace Atlas { VolumetricCloudRenderer volumetricCloudRenderer; FSR2Renderer fsr2Renderer; - RenderList renderList; - Helper::LightData lightData; - std::vector haltonSequence; size_t haltonIndex = 0; uint32_t frameCount = 0; diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index cc18d4098..a0446e3ac 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -33,9 +33,14 @@ namespace Atlas { const auto& vignette = postProcessing.vignette; const auto& taa = postProcessing.taa; auto& sharpen = postProcessing.sharpen; + auto& bloom = postProcessing.bloom; ivec2 resolution = ivec2(target->GetWidth(), target->GetHeight()); + if (bloom.enable) { + GenerateBloom(bloom, &target->hdrTexture, &target->bloomTexture, commandList); + } + ivec2 groupCount = resolution / 8; groupCount.x += ((groupCount.x * 8 == resolution.x) ? 0 : 1); groupCount.y += ((groupCount.y * 8 == resolution.y) ? 0 : 1); @@ -182,6 +187,7 @@ namespace Atlas { const auto& vignette = postProcessing.vignette; const auto& taa = postProcessing.taa; auto& sharpen = postProcessing.sharpen; + auto& bloom = postProcessing.bloom; ivec2 resolution = ivec2(target->GetWidth(), target->GetHeight()); @@ -279,6 +285,66 @@ namespace Atlas { } + void PostProcessRenderer::GenerateBloom(PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, + Texture::Texture2D* bloomTexture, Graphics::CommandList* commandList) { + + CopyToTexture(hdrTexture, bloomTexture, commandList); + + // Downsample + { + struct PushConstants { + int mipLevel; + }; + + auto textureIn = hdrTexture; + auto textureOut = bloomTexture; + + auto pipelineConfig = PipelineConfig("bloom/bloomDownsample.csh"); + auto pipeline = PipelineManager::GetPipeline(pipelineConfig); + commandList->BindPipeline(pipeline); + + ivec2 resolution = ivec2(bloomTexture->width, bloomTexture->height); + auto mipLevels = std::min(bloom.mipLevels, bloomTexture->image->mipLevels); + // Want to end on the bloom texture + if (mipLevels % 2 != 1) + mipLevels--; + + for (int32_t i = 1; i < mipLevels; i++) { + + std::vector bufferBarriers; + std::vector imageBarriers = { + {textureIn->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {textureOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} + }; + commandList->PipelineBarrier(imageBarriers, bufferBarriers); + + ivec2 groupCount = resolution / 8; + groupCount.x += ((groupCount.x * 8 == resolution.x) ? 0 : 1); + groupCount.y += ((groupCount.y * 8 == resolution.y) ? 0 : 1); + + PushConstants constants { + .mipLevel = i + }; + commandList->PushConstants("constants", &constants); + + commandList->BindImage(textureOut->image, 3, 0, i); + textureIn->Bind(commandList, 3, 1); + + commandList->Dispatch(groupCount.x, groupCount.y, 1); + + std::swap(textureIn, textureOut); + resolution /= 2; + } + + } + + // Upsample + { + + } + + } + void PostProcessRenderer::CopyToTexture(Texture::Texture2D* sourceTexture, Texture::Texture2D *texture, Graphics::CommandList* commandList) { @@ -397,4 +463,4 @@ namespace Atlas { } - }} \ No newline at end of file + }} diff --git a/src/engine/renderer/PostProcessRenderer.h b/src/engine/renderer/PostProcessRenderer.h index 9af21337f..bf2629976 100644 --- a/src/engine/renderer/PostProcessRenderer.h +++ b/src/engine/renderer/PostProcessRenderer.h @@ -39,6 +39,9 @@ namespace Atlas { vec4 tintColor; }; + void GenerateBloom(PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, + Texture::Texture2D* bloomTexture, Graphics::CommandList* commandList); + void CopyToTexture(Texture::Texture2D* sourceTexture, Texture::Texture2D* texture, Graphics::CommandList* commandList); diff --git a/src/engine/renderer/helper/LightData.cpp b/src/engine/renderer/helper/LightData.cpp deleted file mode 100644 index 57895aeb2..000000000 --- a/src/engine/renderer/helper/LightData.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "LightData.h" -#include "CommonStructures.h" - -#include "common/ColorConverter.h" -#include - -namespace Atlas::Renderer::Helper { - - void LightData::CullAndSort(const Ref& scene) { - - auto& camera = scene->GetMainCamera(); - - lightEntities.clear(); - auto lightSubset = scene->GetSubset(); - for (auto& lightEntity : lightSubset) { - auto& light = lightEntity.GetComponent(); - lightEntities.emplace_back(LightEntity { lightEntity, light, -1 }); - } - - if (lightEntities.size() <= 1) - return; - - std::sort(lightEntities.begin(), lightEntities.end(), - [&](const LightEntity& light0, const LightEntity& light1) { - if (light0.comp.isMain) - return true; - - if (light0.comp.type == LightType::DirectionalLight) - return true; - - if (light0.comp.type == LightType::PointLight && - light1.comp.type == LightType::PointLight) { - return glm::distance2(light0.comp.transformedProperties.point.position, camera.GetLocation()) - < glm::distance2(light1.comp.transformedProperties.point.position, camera.GetLocation()); - } - - return false; - }); - - } - - void LightData::UpdateBindlessIndices(const Ref& scene) { - - - - } - - void LightData::FillBuffer(const Ref& scene) { - - auto& camera = scene->GetMainCamera(); - - std::vector lights; - lights.reserve(lightEntities.size()); - for (const auto& entity : lightEntities) { - auto& light = entity.comp; - - auto type = static_cast(light.type); - auto packedType = reinterpret_cast(type); - Light lightUniform { - .color = vec4(Common::ColorConverter::ConvertSRGBToLinear(light.color), packedType), - .intensity = light.intensity, - .scatteringFactor = 1.0f, - }; - - const auto& prop = light.transformedProperties; - if (light.type == LightType::DirectionalLight) { - lightUniform.direction = camera.viewMatrix * vec4(prop.directional.direction, 0.0f); - } - else if (light.type == LightType::PointLight) { - lightUniform.location = camera.viewMatrix * vec4(prop.point.position, 1.0f); - lightUniform.radius = prop.point.radius; - lightUniform.attenuation = prop.point.attenuation; - } - - if (light.shadow) { - auto shadow = light.shadow; - auto& shadowUniform = lightUniform.shadow; - shadowUniform.distance = !shadow->longRange ? shadow->distance : shadow->longRangeDistance; - shadowUniform.bias = shadow->bias; - shadowUniform.edgeSoftness = shadow->edgeSoftness; - shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; - shadowUniform.cascadeCount = shadow->viewCount; - shadowUniform.resolution = vec2(shadow->resolution); - shadowUniform.mapIdx = entity.mapIdx; - - auto componentCount = shadow->viewCount; - for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { - if (i < componentCount) { - auto cascade = &shadow->views[i]; - auto frustum = Volume::Frustum(cascade->frustumMatrix); - auto corners = frustum.GetCorners(); - auto texelSize = glm::max(abs(corners[0].x - corners[1].x), - abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; - shadowUniform.cascades[i].distance = cascade->farDistance; - if (light.type == LightType::DirectionalLight) { - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix; - } - else if (light.type == LightType::PointLight) { - if (i == 0) - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix; - else - shadowUniform.cascades[i].cascadeSpace = glm::translate(mat4(1.0f), -prop.point.position) * camera.invViewMatrix; - } - shadowUniform.cascades[i].texelSize = texelSize; - } - else { - auto cascade = &shadow->views[componentCount - 1]; - shadowUniform.cascades[i].distance = cascade->farDistance; - } - } - } - - lights.emplace_back(lightUniform); - } - - if (lightBuffer.GetElementCount() < lightEntities.size()) { - lightBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit - | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Light), lightEntities.size(), lights.data()); - } - else { - lightBuffer.SetData(lights.data(), 0, lights.size()); - } - - } - -} \ No newline at end of file diff --git a/src/engine/renderer/helper/LightData.h b/src/engine/renderer/helper/LightData.h deleted file mode 100644 index 80eacbf9b..000000000 --- a/src/engine/renderer/helper/LightData.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "../../System.h" - -#include - -#include "scene/Scene.h" - -namespace Atlas::Renderer::Helper { - - class LightData { - - public: - struct LightEntity { - Scene::Entity entity; - LightComponent comp; - int32_t mapIdx = -1; - }; - - LightData() = default; - - void CullAndSort(const Ref& scene); - - void UpdateBindlessIndices(const Ref& scene); - - void FillBuffer(const Ref& scene); - - Buffer::Buffer lightBuffer; - - std::vector lightEntities; - - }; - -} \ No newline at end of file diff --git a/src/engine/renderer/helper/RenderList.cpp b/src/engine/renderer/helper/RenderList.cpp index 0a4e8b205..6121467bf 100644 --- a/src/engine/renderer/helper/RenderList.cpp +++ b/src/engine/renderer/helper/RenderList.cpp @@ -20,7 +20,7 @@ namespace Atlas { } - void RenderList::NewFrame(const Ref& scene) { + void RenderList::NewFrame(Scene::Scene* scene) { this->scene = scene; @@ -133,7 +133,7 @@ namespace Atlas { } - void RenderList::Pass::NewFrame(const Ref& scene, const std::vector>& meshes) { + void RenderList::Pass::NewFrame(Scene::Scene* scene, const std::vector>& meshes) { this->scene = scene; diff --git a/src/engine/renderer/helper/RenderList.h b/src/engine/renderer/helper/RenderList.h index 6c9efcbde..0ef893f02 100644 --- a/src/engine/renderer/helper/RenderList.h +++ b/src/engine/renderer/helper/RenderList.h @@ -54,7 +54,7 @@ namespace Atlas { Scene::Entity lightEntity; uint32_t layer; - Ref scene = nullptr; + Scene::Scene* scene = nullptr; std::unordered_map meshToEntityMap; std::unordered_map meshToInstancesMap; @@ -70,7 +70,7 @@ namespace Atlas { Ref lastMatricesBuffer; Ref impostorMatricesBuffer; - void NewFrame(const Ref& scene, const std::vector>& meshes); + void NewFrame(Scene::Scene* scene, const std::vector>& meshes); void Add(const ECS::Entity& entity, const MeshComponent& meshComponent); @@ -85,7 +85,7 @@ namespace Atlas { ~RenderList(); - void NewFrame(const Ref& scene); + void NewFrame(Scene::Scene* scene); // Note: The expected behaviour is to first create and process all shadow passes and then finally do the main pass last Ref NewMainPass(); @@ -102,7 +102,7 @@ namespace Atlas { void Clear(); - Ref scene = nullptr; + Scene::Scene* scene = nullptr; std::vector> passes; std::deque> processedPasses; diff --git a/src/engine/renderer/target/RenderTarget.cpp b/src/engine/renderer/target/RenderTarget.cpp index 0ecce5606..10163aa00 100644 --- a/src/engine/renderer/target/RenderTarget.cpp +++ b/src/engine/renderer/target/RenderTarget.cpp @@ -29,7 +29,9 @@ namespace Atlas::Renderer { reactiveMaskTexture = Texture::Texture2D(scaledWidth, scaledWidth, VK_FORMAT_R8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); hdrTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::MipMapLinear); + bloomTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::MipMapLinear); outputTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); @@ -164,6 +166,7 @@ namespace Atlas::Renderer { lightingTexture.Resize(scaledWidth, scaledHeight); reactiveMaskTexture.Resize(scaledWidth, scaledHeight); hdrTexture.Resize(width, height); + bloomTexture.Resize(width, height); outputTexture.Resize(width, height); sssTexture.Resize(scaledWidth, scaledHeight); oceanDepthTexture.Resize(scaledWidth, scaledHeight); diff --git a/src/engine/renderer/target/RenderTarget.h b/src/engine/renderer/target/RenderTarget.h index 330968493..f6c111bfe 100644 --- a/src/engine/renderer/target/RenderTarget.h +++ b/src/engine/renderer/target/RenderTarget.h @@ -196,6 +196,7 @@ namespace Atlas::Renderer { Ref outputFrameBuffer; Texture::Texture2D outputTexture; + Texture::Texture2D bloomTexture; Texture::Texture2D giTexture; Texture::Texture2D swapGiTexture; diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 6366a24db..7d9216319 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -355,6 +355,8 @@ namespace Atlas { if (!mainCameraEntity.IsValid()) return; + renderState.FillRenderList(); + auto& mainCamera = mainCameraEntity.GetComponent(); auto audioSubset = entityManager.GetSubset(); @@ -379,6 +381,8 @@ namespace Atlas { lightComponent.Update(mainCamera); } + renderState.CullAndSortLights(); + if (terrain) { terrain->Update(mainCamera); } @@ -552,6 +556,8 @@ namespace Atlas { } void Scene::ClearRTStructures() { + + WaitForAsyncWorkCompletion(); rtDataValid = false; if (rayTracingWorld != nullptr) @@ -840,4 +846,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 5aa1ef86a..e79289a4f 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -1,20 +1,30 @@ #include "SceneRenderState.h" #include "Scene.h" +#include "renderer/helper/CommonStructures.h" #include "common/ColorConverter.h" #include "common/Packing.h" +#include "common/ColorConverter.h" +#include + // Move most of the things in the main renderer, like the bindless update or the materials to here // Also move rendering related map updates from the scene to here namespace Atlas::Scene { SceneRenderState::SceneRenderState(Scene* scene) : scene(scene) { - materialBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | + materialBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit, sizeof(Renderer::PackedMaterial)); } + SceneRenderState::~SceneRenderState() { + + WaitForAsyncWorkCompletion(); + + } + void SceneRenderState::PrepareMaterials() { JobSystem::Execute(materialUpdateJob, [&](JobData&) { @@ -71,19 +81,19 @@ namespace Atlas::Scene { packed.features = 0; packed.features |= material->HasBaseColorMap() ? Renderer::MaterialFeatures::FEATURE_BASE_COLOR_MAP : 0; - packed.features |= material->HasOpacityMap() ? Renderer::MaterialFeatures::FEATURE_OPACITY_MAP : 0; - packed.features |= material->HasNormalMap() ? Renderer::MaterialFeatures::FEATURE_NORMAL_MAP : 0; - packed.features |= material->HasRoughnessMap() ? Renderer::MaterialFeatures::FEATURE_ROUGHNESS_MAP : 0; - packed.features |= material->HasMetalnessMap() ? Renderer::MaterialFeatures::FEATURE_METALNESS_MAP : 0; - packed.features |= material->HasAoMap() ? Renderer::MaterialFeatures::FEATURE_AO_MAP : 0; - packed.features |= glm::length(material->transmissiveColor) > 0.0f ? Renderer::MaterialFeatures::FEATURE_TRANSMISSION : 0; - packed.features |= material->vertexColors ? Renderer::MaterialFeatures::FEATURE_VERTEX_COLORS : 0; + packed.features |= material->HasOpacityMap() ? Renderer::MaterialFeatures::FEATURE_OPACITY_MAP : 0; + packed.features |= material->HasNormalMap() ? Renderer::MaterialFeatures::FEATURE_NORMAL_MAP : 0; + packed.features |= material->HasRoughnessMap() ? Renderer::MaterialFeatures::FEATURE_ROUGHNESS_MAP : 0; + packed.features |= material->HasMetalnessMap() ? Renderer::MaterialFeatures::FEATURE_METALNESS_MAP : 0; + packed.features |= material->HasAoMap() ? Renderer::MaterialFeatures::FEATURE_AO_MAP : 0; + packed.features |= glm::length(material->transmissiveColor) > 0.0f ? Renderer::MaterialFeatures::FEATURE_TRANSMISSION : 0; + packed.features |= material->vertexColors ? Renderer::MaterialFeatures::FEATURE_VERTEX_COLORS : 0; materials.push_back(packed); materialMap[material.get()] = idx++; } - + auto meshes = scene->GetMeshes(); for (auto mesh : meshes) { @@ -122,23 +132,24 @@ namespace Atlas::Scene { packed.features = 0; - packed.features |= Renderer::MaterialFeatures::FEATURE_BASE_COLOR_MAP | - Renderer::MaterialFeatures::FEATURE_ROUGHNESS_MAP | - Renderer::MaterialFeatures::FEATURE_METALNESS_MAP | + packed.features |= Renderer::MaterialFeatures::FEATURE_BASE_COLOR_MAP | + Renderer::MaterialFeatures::FEATURE_ROUGHNESS_MAP | + Renderer::MaterialFeatures::FEATURE_METALNESS_MAP | Renderer::MaterialFeatures::FEATURE_AO_MAP; - packed.features |= glm::length(impostor->transmissiveColor) > 0.0f ? + packed.features |= glm::length(impostor->transmissiveColor) > 0.0f ? Renderer::MaterialFeatures::FEATURE_TRANSMISSION : 0; materials.push_back(packed); - materialMap[impostor.get()] = idx++; + materialMap[impostor.get()] = idx++; } if (materials.size() > materialBuffer.GetElementCount()) { materialBuffer.SetSize(materials.size()); } - materialBuffer.SetData(materials.data(), 0, materials.size()); + if (!materials.empty()) + materialBuffer.SetData(materials.data(), 0, materials.size()); }); @@ -190,11 +201,10 @@ namespace Atlas::Scene { meshIdToBindlessIdx[mesh.GetID()] = bufferIdx++; } - - JobSystem::Execute(prepareBindlessMeshesJob, bindlessMeshBuffersUpdate); }; JobSystem::Execute(bindlessMeshMapUpdateJob, bindlessMeshMapUpdate); + JobSystem::Execute(prepareBindlessMeshesJob, bindlessMeshBuffersUpdate); } @@ -252,11 +262,10 @@ namespace Atlas::Scene { textureToBindlessIdx[texture] = textureIdx++; } + }; - JobSystem::Execute(prepareBindlessTexturesJob, bindlessTextureBuffersUpdate); - }; - JobSystem::Execute(bindlessTextureMapUpdateJob, bindlessTextureMapUpdate); + JobSystem::Execute(prepareBindlessTexturesJob, bindlessTextureBuffersUpdate); } @@ -281,4 +290,195 @@ namespace Atlas::Scene { } -} \ No newline at end of file + void SceneRenderState::FillRenderList() { + + if (!scene->HasMainCamera()) + return; + + JobSystem::Execute(fillRenderListJob, [&](JobData&) { + auto& camera = scene->GetMainCamera(); + + auto meshes = scene->GetMeshes(); + renderList.NewFrame(scene); + + auto lightSubset = scene->GetSubset(); + + JobGroup group; + for (auto& lightEntity : lightSubset) { + + auto& light = lightEntity.GetComponent(); + if (!light.shadow || !light.shadow->update) + continue; + + auto& shadow = light.shadow; + + auto componentCount = shadow->longRange ? + shadow->viewCount - 1 : shadow->viewCount; + + JobSystem::ExecuteMultiple(group, componentCount, + [&, shadow = shadow, lightEntity = lightEntity](JobData& data) { + auto component = &shadow->views[data.idx]; + auto frustum = Volume::Frustum(component->frustumMatrix); + + auto shadowPass = renderList.GetShadowPass(lightEntity, data.idx); + if (shadowPass == nullptr) + shadowPass = renderList.NewShadowPass(lightEntity, data.idx); + + shadowPass->NewFrame(scene, meshes); + scene->GetRenderList(frustum, shadowPass); + shadowPass->Update(camera.GetLocation()); + shadowPass->FillBuffers(); + renderList.FinishPass(shadowPass); + }); + } + + JobSystem::Wait(group); + + auto mainPass = renderList.GetMainPass(); + if (mainPass == nullptr) + mainPass = renderList.NewMainPass(); + + mainPass->NewFrame(scene, meshes); + scene->GetRenderList(camera.frustum, mainPass); + mainPass->Update(camera.GetLocation()); + mainPass->FillBuffers(); + renderList.FinishPass(mainPass); + + }); + } + + void SceneRenderState::CullAndSortLights() { + + JobSystem::Execute(cullAndSortLightsJob, [&](JobData&) { + auto& camera = scene->GetMainCamera(); + + lightEntities.clear(); + auto lightSubset = scene->GetSubset(); + for (auto& lightEntity : lightSubset) { + auto& light = lightEntity.GetComponent(); + lightEntities.emplace_back(LightEntity{ lightEntity, light, -1 }); + } + + if (lightEntities.size() > 1) { + std::sort(lightEntities.begin(), lightEntities.end(), + [&](const LightEntity& light0, const LightEntity& light1) { + if (light0.comp.isMain) + return true; + + if (light0.comp.type == LightType::DirectionalLight) + return true; + + if (light0.comp.type == LightType::PointLight && + light1.comp.type == LightType::PointLight) { + return glm::distance2(light0.comp.transformedProperties.point.position, camera.GetLocation()) + < glm::distance2(light1.comp.transformedProperties.point.position, camera.GetLocation()); + } + + return false; + }); + } + + std::vector lights; + if (lightEntities.size()) { + lights.reserve(lightEntities.size()); + for (const auto& entity : lightEntities) { + auto& light = entity.comp; + + auto type = static_cast(light.type); + auto packedType = reinterpret_cast(type); + Renderer::Light lightUniform { + .color = vec4(Common::ColorConverter::ConvertSRGBToLinear(light.color), packedType), + .intensity = light.intensity, + .scatteringFactor = 1.0f, + }; + + const auto& prop = light.transformedProperties; + if (light.type == LightType::DirectionalLight) { + lightUniform.direction = camera.viewMatrix * vec4(prop.directional.direction, 0.0f); + } + else if (light.type == LightType::PointLight) { + lightUniform.location = camera.viewMatrix * vec4(prop.point.position, 1.0f); + lightUniform.radius = prop.point.radius; + lightUniform.attenuation = prop.point.attenuation; + } + + if (light.shadow) { + auto shadow = light.shadow; + auto& shadowUniform = lightUniform.shadow; + shadowUniform.distance = !shadow->longRange ? shadow->distance : shadow->longRangeDistance; + shadowUniform.bias = shadow->bias; + shadowUniform.edgeSoftness = shadow->edgeSoftness; + shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; + shadowUniform.cascadeCount = shadow->viewCount; + shadowUniform.resolution = vec2(shadow->resolution); + shadowUniform.mapIdx = entity.mapIdx; + + auto componentCount = shadow->viewCount; + for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { + if (i < componentCount) { + auto cascade = &shadow->views[i]; + auto frustum = Volume::Frustum(cascade->frustumMatrix); + auto corners = frustum.GetCorners(); + auto texelSize = glm::max(abs(corners[0].x - corners[1].x), + abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; + shadowUniform.cascades[i].distance = cascade->farDistance; + if (light.type == LightType::DirectionalLight) { + shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * + cascade->viewMatrix * camera.invViewMatrix; + } + else if (light.type == LightType::PointLight) { + if (i == 0) + shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix; + else + shadowUniform.cascades[i].cascadeSpace = glm::translate(mat4(1.0f), -prop.point.position) * camera.invViewMatrix; + } + shadowUniform.cascades[i].texelSize = texelSize; + } + else { + auto cascade = &shadow->views[componentCount - 1]; + shadowUniform.cascades[i].distance = cascade->farDistance; + } + } + } + + lights.emplace_back(lightUniform); + } + } + else { + // We need to have at least a fake light + auto type = 0; + auto packedType = reinterpret_cast(type); + lights.emplace_back(Renderer::Light { + .color = vec4(vec3(0.0f), packedType), + .intensity = 0.0f, + .direction = vec4(0.0f, -1.0f, 0.0f, 0.0f) + }); + } + + if (lightBuffer.GetElementCount() < lightEntities.size()) { + lightBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit + | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Renderer::Light), lightEntities.size(), lights.data()); + } + else { + lightBuffer.SetData(lights.data(), 0, lights.size()); + } + + }); + + } + + void SceneRenderState::WaitForAsyncWorkCompletion() { + + JobSystem::Wait(bindlessMeshMapUpdateJob); + JobSystem::Wait(bindlessTextureMapUpdateJob); + JobSystem::Wait(bindlessOtherTextureMapUpdateJob); + JobSystem::Wait(materialUpdateJob); + JobSystem::Wait(rayTracingWorldUpdateJob); + JobSystem::Wait(prepareBindlessMeshesJob); + JobSystem::Wait(prepareBindlessTexturesJob); + JobSystem::Wait(fillRenderListJob); + JobSystem::Wait(cullAndSortLightsJob); + + } + +} diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index e03a1668d..914f6a903 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -1,5 +1,6 @@ #pragma once +#include "Entity.h" #include "jobsystem/JobGroup.h" #include "texture/Texture2D.h" #include "texture/Texture2DArray.h" @@ -8,6 +9,7 @@ #include "buffer/UniformBuffer.h" #include "renderer/helper/CommonStructures.h" +#include "renderer/helper/RenderList.h" #include @@ -15,10 +17,18 @@ namespace Atlas::Scene { class Scene; + struct LightEntity { + Entity entity; + LightComponent comp; + int32_t mapIdx = -1; + }; + class SceneRenderState { public: SceneRenderState(Scene* scene); + + ~SceneRenderState(); void PrepareMaterials(); @@ -28,9 +38,17 @@ namespace Atlas::Scene { void UpdateOtherTextureBindlessData(); + void FillRenderList(); + + void CullAndSortLights(); + + void WaitForAsyncWorkCompletion(); + Scene* scene; + RenderList renderList; Buffer::Buffer materialBuffer; + Buffer::Buffer lightBuffer; std::vector> images; std::vector> blasBuffers; std::vector> triangleBuffers; @@ -43,15 +61,18 @@ namespace Atlas::Scene { std::unordered_map, uint32_t> textureArrayToBindlessIdx; std::unordered_map, uint32_t> cubemapToBindlessIdx; std::unordered_map meshIdToBindlessIdx; - - JobGroup materialUpdateJob { JobPriority::High }; - JobGroup rayTracingWorldUpdateJob { JobPriority::High }; - JobGroup bindlessMeshMapUpdateJob { JobPriority::High }; - JobGroup bindlessTextureMapUpdateJob { JobPriority::High }; - JobGroup bindlessOtherTextureMapUpdateJob { JobPriority::High }; - JobGroup prepareBindlessMeshesJob { JobPriority::High }; - JobGroup prepareBindlessTexturesJob { JobPriority::High }; + std::vector lightEntities; + + JobGroup materialUpdateJob{ JobPriority::High }; + JobGroup rayTracingWorldUpdateJob{ JobPriority::High }; + JobGroup bindlessMeshMapUpdateJob{ JobPriority::High }; + JobGroup bindlessTextureMapUpdateJob{ JobPriority::High }; + JobGroup bindlessOtherTextureMapUpdateJob{ JobPriority::High }; + JobGroup prepareBindlessMeshesJob{ JobPriority::High }; + JobGroup prepareBindlessTexturesJob{ JobPriority::High }; + JobGroup fillRenderListJob{ JobPriority::High }; + JobGroup cullAndSortLightsJob{ JobPriority::High }; }; -} \ No newline at end of file +} diff --git a/src/engine/volume/BVH.cpp b/src/engine/volume/BVH.cpp index 225748693..3a78c0103 100644 --- a/src/engine/volume/BVH.cpp +++ b/src/engine/volume/BVH.cpp @@ -69,7 +69,7 @@ namespace Atlas { for (auto& ref : refs) aabb.Grow(aabbs[ref.idx]); - auto builder = new BVHBuilder(aabb, 0, refs.size(), 64); + auto builder = new BVHBuilder(aabb, 0, refs.size(), 128); JobGroup group { JobPriority::Medium }; builder->Build(refs, group, parallelBuild); @@ -307,7 +307,7 @@ namespace Atlas { refs.clear(); refs.shrink_to_fit(); - if (depth <= 6 && parallelBuild) { + if (depth <= 8 && parallelBuild) { auto leftRefSize = leftRefs.size(), rightRefSize = rightRefs.size(); auto leftLambda = [=, &jobGroup, leftRefs = std::move(leftRefs)](JobData&) { auto refs = std::move(leftRefs); @@ -320,11 +320,9 @@ namespace Atlas { rightChild = new BVHBuilder(split.rightAABB, depth + 1, refs.size(), binCount); rightChild->Build(refs, jobGroup, parallelBuild); }; - - if (leftRefSize > 0) - JobSystem::Execute(jobGroup, leftLambda); - if (rightRefSize > 0) - JobSystem::Execute(jobGroup, rightLambda); + + JobSystem::Execute(jobGroup, leftLambda); + JobSystem::Execute(jobGroup, rightLambda); } else { if (leftRefs.size()) { @@ -343,7 +341,7 @@ namespace Atlas { void BVHBuilder::Build(std::vector& refs, JobGroup& jobGroup, bool parallelBuild) { // Create leaf node - if (refs.size() == 1) { + if ((refs.size() == 1 || depth >= 24) && depth > 0) { CreateLeaf(refs); return; } @@ -386,10 +384,8 @@ namespace Atlas { rightChild->Build(refs, jobGroup, parallelBuild); }; - if (leftRefSize > 0) - JobSystem::Execute(jobGroup, leftLambda); - if (rightRefSize > 0) - JobSystem::Execute(jobGroup, rightLambda); + JobSystem::Execute(jobGroup, leftLambda); + JobSystem::Execute(jobGroup, rightLambda); } else { if (leftRefs.size()) { @@ -444,7 +440,7 @@ namespace Atlas { BVHBuilder::Split BVHBuilder::FindObjectSplit(std::vector& refs) { Split split; - const auto depthBinCount = std::max(binCount / (depth + 1), 16u); + const auto depthBinCount = std::max(binCount / (depth + 1), 8u); std::vector bins(depthBinCount); std::vector rightAABBs(bins.size()); @@ -530,7 +526,7 @@ namespace Atlas { void BVHBuilder::PerformObjectSplit(std::vector& refs, std::vector& rightRefs, std::vector& leftRefs, Split& split) { - const auto depthBinCount = std::max(binCount / (depth + 1), 16u); + const auto depthBinCount = std::max(binCount / (depth + 1), 8u); auto start = aabb.min[split.axis]; auto stop = aabb.max[split.axis]; diff --git a/src/tests/App.cpp b/src/tests/App.cpp index 07a54e8c4..bdaa668d8 100644 --- a/src/tests/App.cpp +++ b/src/tests/App.cpp @@ -56,14 +56,16 @@ void App::LoadContent(AppConfiguration config) { Atlas::PipelineManager::EnableHotReload(); - directionalLightEntity = scene->CreateEntity(); - auto& directionalLight = directionalLightEntity.AddComponent(LightType::DirectionalLight); - - directionalLight.properties.directional.direction = glm::vec3(0.0f, -1.0f, 0.33f); - directionalLight.color = glm::vec3(255, 236, 209) / 255.0f; - directionalLight.AddDirectionalShadow(200.0f, 3.0f, 4096, 0.025f, - glm::vec3(0.0f), glm::vec4(-100.0f, 100.0f, -70.0f, 120.0f)); - directionalLight.isMain = true; + if (config.light) { + auto directionalLightEntity = scene->CreateEntity(); + auto& directionalLight = directionalLightEntity.AddComponent(LightType::DirectionalLight); + + directionalLight.properties.directional.direction = glm::vec3(0.0f, -1.0f, 0.33f); + directionalLight.color = glm::vec3(255, 236, 209) / 255.0f; + directionalLight.AddDirectionalShadow(200.0f, 3.0f, 4096, 0.025f, + glm::vec3(0.0f), glm::vec4(-100.0f, 100.0f, -70.0f, 120.0f)); + directionalLight.isMain = true; + } scene->ao = Atlas::CreateRef(16); diff --git a/src/tests/App.h b/src/tests/App.h index a7bc33409..e2c7693b4 100644 --- a/src/tests/App.h +++ b/src/tests/App.h @@ -24,6 +24,7 @@ struct AppConfiguration { bool reflection = true; bool volumetric = true; bool ocean = true; + bool light = true; bool resize = false; bool recreateSwapchain = false; bool minimizeWindow = false; @@ -68,7 +69,6 @@ class App : public Atlas::EngineInstance { std::vector> meshes; Atlas::Scene::Entity cameraEntity; - Atlas::Scene::Entity directionalLightEntity; std::vector entities; Atlas::Lighting::EnvironmentProbe probe; diff --git a/src/tests/Main.cpp b/src/tests/Main.cpp index 8f383dfd4..a87249f10 100644 --- a/src/tests/Main.cpp +++ b/src/tests/Main.cpp @@ -102,6 +102,7 @@ auto testingValues = testing::Values( #endif AppConfiguration { .volumetric = false }, AppConfiguration { .sharpen = false }, + AppConfiguration { .light = false }, AppConfiguration { .recreateSwapchain = true }, AppConfiguration { .resize = true }, AppConfiguration { .exampleRenderer = true }, From 046af84cf5e1001c1125bc1594b1b5479b7240ea Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Wed, 28 Aug 2024 11:32:30 +0200 Subject: [PATCH 10/66] Bloom --- data/shader/bloom/bloomDownsample.csh | 131 +++++++++++++++++- data/shader/bloom/bloomUpsample.csh | 57 ++++++++ data/shader/postprocessing.fsh | 45 ++---- .../panels/PostProcessingPanel.cpp | 6 + src/demo/App.cpp | 7 +- src/editor/ui/panels/PopupPanels.cpp | 2 +- src/engine/postprocessing/Bloom.h | 4 + src/engine/renderer/PostProcessRenderer.cpp | 78 +++++++++-- src/engine/renderer/PostProcessRenderer.h | 2 +- src/engine/scene/Scene.cpp | 3 +- src/engine/scene/SceneRenderState.cpp | 15 +- 11 files changed, 291 insertions(+), 59 deletions(-) diff --git a/data/shader/bloom/bloomDownsample.csh b/data/shader/bloom/bloomDownsample.csh index 8d970a594..a222f93c0 100644 --- a/data/shader/bloom/bloomDownsample.csh +++ b/data/shader/bloom/bloomDownsample.csh @@ -1,29 +1,133 @@ -layout (local_size_x = 8, local_size_y = 8) in; +layout (local_size_x = 16, local_size_y = 16) in; -#include -#include +#include <../common/utility.hsh> +#include <../common/flatten.hsh> layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; layout (set = 3, binding = 1) uniform sampler2D textureIn; layout(push_constant) uniform constants { int mipLevel; + float threshold; } pushConstants; +const uint supportSize = 2; +const uint sharedDataSize = (2u * gl_WorkGroupSize.x + 2u * supportSize) * (2u * gl_WorkGroupSize.y + 2u * supportSize); +const ivec2 unflattenedSharedDataSize = 2 * ivec2(gl_WorkGroupSize) + 2 * int(supportSize); + +shared vec3 sharedMemory[sharedDataSize]; + +const ivec2 pixelOffsets[4] = ivec2[4]( + ivec2(0, 0), + ivec2(1, 0), + ivec2(0, 1), + ivec2(1, 1) +); + +float Luma(vec3 color) { + + const vec3 luma = vec3(0.299, 0.587, 0.114); + return dot(color, luma); + +} + +vec3 Prefilter(vec3 color) { + + float brightness = Luma(color); + float contribution = max(0.0, brightness - pushConstants.threshold); + contribution /= max(brightness, 0.00001); + return color * contribution; + +} + +void LoadGroupSharedData() { + + ivec2 resolution = textureSize(textureIn, pushConstants.mipLevel); + ivec2 workGroupOffset = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize); + + uint workGroupSize = gl_WorkGroupSize.x * gl_WorkGroupSize.y; + for(uint i = gl_LocalInvocationIndex; i < sharedDataSize; i += workGroupSize) { + ivec2 localOffset = Unflatten2D(int(i), unflattenedSharedDataSize); + ivec2 texel = localOffset + 2 * workGroupOffset - ivec2(supportSize); + + texel = clamp(texel, ivec2(0), ivec2(resolution) - ivec2(1)); + + vec3 color = texelFetch(textureIn, texel, pushConstants.mipLevel).rgb; + if (pushConstants.mipLevel == 0) { + color = Prefilter(color); + } + + sharedMemory[i] = color; + } + + barrier(); + +} + vec3 Sample(vec2 texCoord) { - return textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb; +#ifdef NO_SHARED + if (pushConstants.mipLevel == 0) { + return Prefilter(textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb); + } + else { + return textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb; + } +#else + const ivec2 groupOffset = 2 * (ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize)) - ivec2(supportSize); + + vec2 pixel = texCoord * textureSize(textureIn, pushConstants.mipLevel); + pixel -= 0.5; + + float x = fract(pixel.x); + float y = fract(pixel.y); + + float weights[4] = { (1 - x) * (1 - y), x * (1 - y), (1 - x) * y, x * y }; + + bool invalidIdx = false; + + vec3 color = vec3(0.0); + for (int i = 0; i < 4; i++) { + ivec2 offsetPixel = ivec2(pixel) + pixelOffsets[i]; + offsetPixel -= groupOffset; + int sharedMemoryIdx = Flatten2D(offsetPixel, unflattenedSharedDataSize); + if (sharedMemoryIdx < 0 || sharedMemoryIdx >= sharedDataSize) + invalidIdx = true; + color += weights[i] * sharedMemory[sharedMemoryIdx]; + } + return invalidIdx ? vec3(10000.0, 0.0, 0.0) : color; +#endif + +} + +vec3 SampleShared(ivec2 texel) { + + bool invalidIdx = false; + + const ivec2 localOffset = 2 * ivec2(gl_LocalInvocationID); + vec3 color = vec3(0.0); + for (int i = 0; i < 4; i++) { + ivec2 offsetPixel = localOffset + texel + pixelOffsets[i]; + int sharedMemoryIdx = Flatten2D(offsetPixel, unflattenedSharedDataSize); + if (sharedMemoryIdx < 0 || sharedMemoryIdx >= sharedDataSize) + invalidIdx = true; + color += 0.25 * sharedMemory[sharedMemoryIdx]; + } + return invalidIdx ? vec3(10000.0, 0.0, 0.0) : color; } void main() { + LoadGroupSharedData(); + ivec2 size = imageSize(textureOut); ivec2 coord = ivec2(gl_GlobalInvocationID); if (coord.x < size.x && coord.y < size.y) { +#ifdef NO_SHARED // Lower mip tex coord vec2 texCoord = (coord + 0.5) / size; // Upper mip texel size @@ -46,6 +150,25 @@ void main() { vec3 inner10 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); vec3 inner01 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); vec3 inner11 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); +#else + // We always sample at pixel border, not centers + vec3 outer00 = SampleShared(ivec2(0, 0)); + vec3 outer10 = SampleShared(ivec2(2, 0)); + vec3 outer20 = SampleShared(ivec2(4, 0)); + + vec3 outer01 = SampleShared(ivec2(0, 2)); + vec3 outer11 = SampleShared(ivec2(2, 2)); + vec3 outer21 = SampleShared(ivec2(4, 2)); + + vec3 outer02 = SampleShared(ivec2(0, 4)); + vec3 outer12 = SampleShared(ivec2(2, 4)); + vec3 outer22 = SampleShared(ivec2(4, 4)); + + vec3 inner00 = SampleShared(ivec2(1, 1)); + vec3 inner10 = SampleShared(ivec2(3, 1)); + vec3 inner01 = SampleShared(ivec2(1, 3)); + vec3 inner11 = SampleShared(ivec2(3, 3)); +#endif vec3 filtered = vec3(0.0); diff --git a/data/shader/bloom/bloomUpsample.csh b/data/shader/bloom/bloomUpsample.csh index e69de29bb..cc11b0a12 100644 --- a/data/shader/bloom/bloomUpsample.csh +++ b/data/shader/bloom/bloomUpsample.csh @@ -0,0 +1,57 @@ +layout (local_size_x = 8, local_size_y = 8) in; + +#include +#include + +layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; +layout (set = 3, binding = 1) uniform sampler2D textureIn; + +layout(push_constant) uniform constants { + int mipLevel; + float filterSize; +} pushConstants; + +vec3 Sample(vec2 texCoord) { + + return textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb; + +} + +void main() { + + ivec2 size = imageSize(textureOut); + ivec2 coord = ivec2(gl_GlobalInvocationID); + + if (coord.x < size.x && + coord.y < size.y) { + + // Lower mip tex coord + vec2 texCoord = (coord + 0.5) / size; + // Upper mip texel size + vec2 texelSize = vec2(pushConstants.filterSize); + + // We always sample at pixel border, not centers + vec3 filter00 = Sample(texCoord + vec2(-texelSize.x, -texelSize.y)); + vec3 filter10 = Sample(texCoord + vec2(0.0, -texelSize.y)); + vec3 filter20 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); + + vec3 filter01 = Sample(texCoord + vec2(-texelSize.x, 0.0)); + vec3 filter11 = Sample(texCoord + vec2(0.0, 0.0)); + vec3 filter21 = Sample(texCoord + vec2(texelSize.x, 0.0)); + + vec3 filter02 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); + vec3 filter12 = Sample(texCoord + vec2(0.0, texelSize.y)); + vec3 filter22 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); + + vec3 filtered = vec3(0.0); + + filtered += 4.0 * filter11; + filtered += 2.0 * (filter10 + filter01 + filter21 + filter12); + filtered += 1.0 * (filter00 + filter20 + filter02 + filter22); + filtered /= 16.0; + + imageStore(textureOut, coord, vec4(filtered + filter11, 1.0)); + + } + +} \ No newline at end of file diff --git a/data/shader/postprocessing.fsh b/data/shader/postprocessing.fsh index 08cd7a055..6fe34ad85 100644 --- a/data/shader/postprocessing.fsh +++ b/data/shader/postprocessing.fsh @@ -7,9 +7,7 @@ layout (location = 0) out vec4 outColor; layout (location = 0) in vec2 positionVS; layout(set = 3, binding = 0) uniform sampler2D hdrTexture; -layout(set = 3, binding = 1) uniform sampler2D bloomFirstTexture; -layout(set = 3, binding = 2) uniform sampler2D bloomSecondTexture; -layout(set = 3, binding = 3) uniform sampler2D bloomThirdTexture; +layout(set = 3, binding = 1) uniform sampler2D bloomTexture; layout(set = 3, binding = 4) uniform UniformBuffer { float exposure; @@ -18,7 +16,7 @@ layout(set = 3, binding = 4) uniform UniformBuffer { float saturation; float contrast; float filmGrainStrength; - int bloomPasses; + float bloomStrength; float aberrationStrength; float aberrationReversed; float vignetteOffset; @@ -96,42 +94,19 @@ void main() { vec2 uvBlueChannel = (positionVS - positionVS * 0.005f * Uniforms.aberrationStrength * (1.0f - Uniforms.aberrationReversed)) * 0.5f + 0.5f; - color.r = texture(hdrTexture, uvRedChannel).r; - color.g = texture(hdrTexture, uvGreenChannel).g; - color.b = texture(hdrTexture, uvBlueChannel).b; + color.r = textureLod(hdrTexture, uvRedChannel, 0.0).r; + color.g = textureLod(hdrTexture, uvGreenChannel, 0.0).g; + color.b = textureLod(hdrTexture, uvBlueChannel, 0.0).b; #ifdef BLOOM - // We want to keep a constant expression in texture[const] - // because OpenGL ES doesn't support dynamic texture fetches - // inside a loop - if (Uniforms.bloomPasses > 0) { - color.r += texture(bloomFirstTexture, uvRedChannel).r; - color.g += texture(bloomFirstTexture, uvGreenChannel).g; - color.b += texture(bloomFirstTexture, uvBlueChannel).b; - } - if (Uniforms.bloomPasses > 1) { - color.r += texture(bloomSecondTexture, uvRedChannel).r; - color.g += texture(bloomSecondTexture, uvGreenChannel).g; - color.b += texture(bloomSecondTexture, uvBlueChannel).b; - } - if (Uniforms.bloomPasses > 2) { - color.r += texture(bloomThirdTexture, uvRedChannel).r; - color.g += texture(bloomThirdTexture, uvGreenChannel).g; - color.b += texture(bloomThirdTexture, uvBlueChannel).b; - } + color.r += Uniforms.bloomStrength * textureLod(bloomTexture, uvRedChannel, 0.0).r; + color.g += Uniforms.bloomStrength * textureLod(bloomTexture, uvGreenChannel, 0.0).g; + color.b += uniforms.bloomStrength * textureLod(bloomTexture, uvBlueChannel, 0.0).b; #endif #else - color = texture(hdrTexture, texCoord).rgb; + color = textureLod(hdrTexture, texCoord, 0.0).rgb; #ifdef BLOOM - if (Uniforms.bloomPasses > 0) { - color += texture(bloomFirstTexture, texCoord).rgb; - } - if (Uniforms.bloomPasses > 1) { - color += texture(bloomSecondTexture, texCoord).rgb; - } - if (Uniforms.bloomPasses > 2) { - color += texture(bloomThirdTexture, texCoord).rgb; - } + color += Uniforms.bloomStrength * textureLod(bloomTexture, texCoord, 0.0).rgb; #endif #endif diff --git a/libs/ImguiExtension/panels/PostProcessingPanel.cpp b/libs/ImguiExtension/panels/PostProcessingPanel.cpp index c3934d11b..4a49819a6 100644 --- a/libs/ImguiExtension/panels/PostProcessingPanel.cpp +++ b/libs/ImguiExtension/panels/PostProcessingPanel.cpp @@ -33,6 +33,12 @@ namespace Atlas::ImguiExtension { ImGui::SliderFloat("Strength##Film grain", &postProcessing.filmGrain.strength, 0.0f, 1.0f); ImGui::Text("Bloom"); ImGui::Checkbox("Enable##Bloom", &postProcessing.bloom.enable); + ImGui::DragFloat("Strength##Bloom", &postProcessing.bloom.strength, 0.001f, 0.0f, 1.0f); + ImGui::DragFloat("Threshold##Bloom", &postProcessing.bloom.threshold, 0.01f, 0.0f, 10.0f); + ImGui::DragFloat("Filter size##Bloom", &postProcessing.bloom.filterSize, 0.001f, 0.0f, 1.0f); + auto mipLevels = int32_t(postProcessing.bloom.mipLevels); + ImGui::DragInt("Mip levels##Bloom", &mipLevels, 1, 2, 12); + postProcessing.bloom.mipLevels = mipLevels; ImGui::PopID(); diff --git a/src/demo/App.cpp b/src/demo/App.cpp index 1431329ad..f9cf6216e 100644 --- a/src/demo/App.cpp +++ b/src/demo/App.cpp @@ -119,10 +119,13 @@ void App::UnloadContent() { } void App::Update(float deltaTime) { + + scene->WaitForAsyncWorkCompletion(); if (sceneReload) { UnloadScene(); LoadScene(); + scene->WaitForAsyncWorkCompletion(); sceneReload = false; } @@ -646,6 +649,8 @@ void App::Render(float deltaTime) { Atlas::Clock::ResetAverage(); firstFrame = false; } + + scene->WaitForAsyncWorkCompletion(); } @@ -1245,4 +1250,4 @@ Atlas::EngineInstance* GetEngineInstance() { return new App(); -} \ No newline at end of file +} diff --git a/src/editor/ui/panels/PopupPanels.cpp b/src/editor/ui/panels/PopupPanels.cpp index d796caf54..0e7c4df97 100644 --- a/src/editor/ui/panels/PopupPanels.cpp +++ b/src/editor/ui/panels/PopupPanels.cpp @@ -174,7 +174,7 @@ namespace Atlas::Editor::UI { ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); } else { - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(1.0f, 1.0f, 1.0f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(1.0f, 1.0f, 1.0f, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); } ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 2.0f); diff --git a/src/engine/postprocessing/Bloom.h b/src/engine/postprocessing/Bloom.h index f5aa12cd0..590251713 100644 --- a/src/engine/postprocessing/Bloom.h +++ b/src/engine/postprocessing/Bloom.h @@ -10,6 +10,10 @@ namespace Atlas::PostProcessing { Bloom() = default; bool enable = true; + float strength = 0.01f; + float threshold = 0.5f; + + float filterSize = 0.02f; uint32_t mipLevels = 6; }; diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index a0446e3ac..60626b774 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -150,10 +150,15 @@ namespace Atlas { pipelineConfig.ManageMacro("VIGNETTE", postProcessing.vignette.enable); pipelineConfig.ManageMacro("CHROMATIC_ABERRATION", postProcessing.chromaticAberration.enable); pipelineConfig.ManageMacro("FILM_GRAIN", postProcessing.filmGrain.enable); + pipelineConfig.ManageMacro("BLOOM", postProcessing.bloom.enable); auto pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); + if (bloom.enable) { + target->bloomTexture.Bind(commandList, 3, 1); + } + SetUniforms(camera, scene); readTexture->Bind(commandList, 3, 0); @@ -287,30 +292,34 @@ namespace Atlas { void PostProcessRenderer::GenerateBloom(PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, Texture::Texture2D* bloomTexture, Graphics::CommandList* commandList) { + + const uint32_t maxDownsampleCount = 12; + ivec2 resolutions[maxDownsampleCount]; CopyToTexture(hdrTexture, bloomTexture, commandList); + auto mipLevels = std::min(bloom.mipLevels, bloomTexture->image->mipLevels); + mipLevels = std::min(mipLevels, maxDownsampleCount); + + auto textureIn = bloomTexture; + auto textureOut = hdrTexture; + // Downsample { struct PushConstants { int mipLevel; + float threshold; }; - auto textureIn = hdrTexture; - auto textureOut = bloomTexture; - auto pipelineConfig = PipelineConfig("bloom/bloomDownsample.csh"); auto pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); ivec2 resolution = ivec2(bloomTexture->width, bloomTexture->height); - auto mipLevels = std::min(bloom.mipLevels, bloomTexture->image->mipLevels); - // Want to end on the bloom texture - if (mipLevels % 2 != 1) - mipLevels--; - + resolutions[0] = resolution; + resolution /= 2; + for (int32_t i = 1; i < mipLevels; i++) { - std::vector bufferBarriers; std::vector imageBarriers = { {textureIn->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, @@ -318,12 +327,13 @@ namespace Atlas { }; commandList->PipelineBarrier(imageBarriers, bufferBarriers); - ivec2 groupCount = resolution / 8; - groupCount.x += ((groupCount.x * 8 == resolution.x) ? 0 : 1); - groupCount.y += ((groupCount.y * 8 == resolution.y) ? 0 : 1); + ivec2 groupCount = resolution / 16; + groupCount.x += ((groupCount.x * 16 == resolution.x) ? 0 : 1); + groupCount.y += ((groupCount.y * 16 == resolution.y) ? 0 : 1); PushConstants constants { - .mipLevel = i + .mipLevel = i - 1, + .threshold = bloom.threshold }; commandList->PushConstants("constants", &constants); @@ -333,14 +343,49 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); std::swap(textureIn, textureOut); + + resolutions[i] = resolution; resolution /= 2; } - } // Upsample { + struct PushConstants { + int mipLevel; + float filterSize = 2.0f; + }; + + auto pipelineConfig = PipelineConfig("bloom/bloomUpsample.csh"); + auto pipeline = PipelineManager::GetPipeline(pipelineConfig); + commandList->BindPipeline(pipeline); + + for (int32_t i = mipLevels - 2; i >= 0; i--) { + + std::vector bufferBarriers; + std::vector imageBarriers = { + {textureIn->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {textureOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} + }; + commandList->PipelineBarrier(imageBarriers, bufferBarriers); + + ivec2 groupCount = resolutions[i] / 8; + groupCount.x += ((groupCount.x * 8 == resolutions[i].x) ? 0 : 1); + groupCount.y += ((groupCount.y * 8 == resolutions[i].y) ? 0 : 1); + PushConstants constants { + .mipLevel = i + 1, + .filterSize = bloom.filterSize, + }; + commandList->PushConstants("constants", &constants); + + commandList->BindImage(textureOut->image, 3, 0, i); + textureIn->Bind(commandList, 3, 1); + + commandList->Dispatch(groupCount.x, groupCount.y, 1); + + std::swap(textureIn, textureOut); + } } } @@ -379,6 +424,7 @@ namespace Atlas { const auto& chromaticAberration = postProcessing.chromaticAberration; const auto& vignette = postProcessing.vignette; const auto& filmGrain = postProcessing.filmGrain; + const auto& bloom = postProcessing.bloom; Uniforms uniforms = { .exposure = camera.exposure, @@ -408,6 +454,10 @@ namespace Atlas { uniforms.filmGrainStrength = filmGrain.strength; } + if (bloom.enable) { + uniforms.bloomStrength = bloom.strength; + } + uniformBuffer->SetData(&uniforms, 0, sizeof(Uniforms)); } diff --git a/src/engine/renderer/PostProcessRenderer.h b/src/engine/renderer/PostProcessRenderer.h index bf2629976..ff553c97e 100644 --- a/src/engine/renderer/PostProcessRenderer.h +++ b/src/engine/renderer/PostProcessRenderer.h @@ -29,7 +29,7 @@ namespace Atlas { float saturation; float contrast; float filmGrainStrength; - int32_t bloomPasses; + float bloomStrength; float aberrationStrength; float aberrationReversed; float vignetteOffset; diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 7d9216319..f62e98b98 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -355,8 +355,6 @@ namespace Atlas { if (!mainCameraEntity.IsValid()) return; - renderState.FillRenderList(); - auto& mainCamera = mainCameraEntity.GetComponent(); auto audioSubset = entityManager.GetSubset(); @@ -381,6 +379,7 @@ namespace Atlas { lightComponent.Update(mainCamera); } + renderState.FillRenderList(); renderState.CullAndSortLights(); if (terrain) { diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index e79289a4f..e4cde2a1f 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -27,6 +27,8 @@ namespace Atlas::Scene { void SceneRenderState::PrepareMaterials() { + JobSystem::Wait(materialUpdateJob); + JobSystem::Execute(materialUpdateJob, [&](JobData&) { auto sceneMaterials = scene->GetMaterials(); @@ -150,7 +152,6 @@ namespace Atlas::Scene { if (!materials.empty()) materialBuffer.SetData(materials.data(), 0, materials.size()); - }); } @@ -203,6 +204,9 @@ namespace Atlas::Scene { } }; + JobSystem::Wait(bindlessMeshMapUpdateJob); + JobSystem::Wait(prepareBindlessMeshesJob); + JobSystem::Execute(bindlessMeshMapUpdateJob, bindlessMeshMapUpdate); JobSystem::Execute(prepareBindlessMeshesJob, bindlessMeshBuffersUpdate); @@ -264,6 +268,9 @@ namespace Atlas::Scene { } }; + JobSystem::Wait(bindlessTextureMapUpdateJob); + JobSystem::Wait(prepareBindlessTexturesJob); + JobSystem::Execute(bindlessTextureMapUpdateJob, bindlessTextureMapUpdate); JobSystem::Execute(prepareBindlessTexturesJob, bindlessTextureBuffersUpdate); @@ -271,6 +278,8 @@ namespace Atlas::Scene { void SceneRenderState::UpdateOtherTextureBindlessData() { + JobSystem::Wait(bindlessOtherTextureMapUpdateJob); + JobSystem::Execute(bindlessOtherTextureMapUpdateJob, [&](JobData&) { auto lightSubset = scene->entityManager.GetSubset(); for (auto entity : lightSubset) { @@ -295,6 +304,8 @@ namespace Atlas::Scene { if (!scene->HasMainCamera()) return; + JobSystem::Wait(fillRenderListJob); + JobSystem::Execute(fillRenderListJob, [&](JobData&) { auto& camera = scene->GetMainCamera(); @@ -349,6 +360,8 @@ namespace Atlas::Scene { void SceneRenderState::CullAndSortLights() { + JobSystem::Wait(cullAndSortLightsJob); + JobSystem::Execute(cullAndSortLightsJob, [&](JobData&) { auto& camera = scene->GetMainCamera(); From daf0d6ad8ef258a23a4f74dc8a63aadda8181b09 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Wed, 28 Aug 2024 12:35:59 +0200 Subject: [PATCH 11/66] Fixed some smaller issues --- data/shader/bloom/bloomUpsample.csh | 3 --- src/editor/ui/windows/SceneWindow.cpp | 6 +++--- src/engine/renderer/PostProcessRenderer.cpp | 12 +++++++++++- src/engine/resource/Resource.h | 2 +- src/engine/scene/SceneRenderState.cpp | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/data/shader/bloom/bloomUpsample.csh b/data/shader/bloom/bloomUpsample.csh index cc11b0a12..4e99fc60d 100644 --- a/data/shader/bloom/bloomUpsample.csh +++ b/data/shader/bloom/bloomUpsample.csh @@ -1,8 +1,5 @@ layout (local_size_x = 8, local_size_y = 8) in; -#include -#include - layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; layout (set = 3, binding = 1) uniform sampler2D textureIn; diff --git a/src/editor/ui/windows/SceneWindow.cpp b/src/editor/ui/windows/SceneWindow.cpp index 1e341e816..d98d3e1d2 100644 --- a/src/editor/ui/windows/SceneWindow.cpp +++ b/src/editor/ui/windows/SceneWindow.cpp @@ -60,8 +60,8 @@ namespace Atlas::Editor::UI { if (inFocus && controlDown && ImGui::IsKeyPressed(ImGuiKey_S, false) && !isPlaying) { SaveScene(); } - - if (controlDown && playMaximized && isPlaying && ImGui::IsKeyPressed(ImGuiKey_Escape, false)) { + + if (controlDown && playMaximized && isPlaying && ImGui::IsKeyPressed(ImGuiKey_Q, false)) { StopPlaying(); } @@ -611,7 +611,7 @@ namespace Atlas::Editor::UI { isPlaying = true; if (playMaximized) { - Notifications::Push({ "To stop playing, press Ctrl + Esc" }); + Notifications::Push({ "To stop playing, press Ctrl + Q" }); } } diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index 60626b774..7fcf5a8bf 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -296,16 +296,21 @@ namespace Atlas { const uint32_t maxDownsampleCount = 12; ivec2 resolutions[maxDownsampleCount]; + Graphics::Profiler::BeginQuery("Bloom"); + Graphics::Profiler::BeginQuery("Copy texture"); + CopyToTexture(hdrTexture, bloomTexture, commandList); auto mipLevels = std::min(bloom.mipLevels, bloomTexture->image->mipLevels); mipLevels = std::min(mipLevels, maxDownsampleCount); auto textureIn = bloomTexture; - auto textureOut = hdrTexture; + auto textureOut = hdrTexture; // Downsample { + Graphics::Profiler::EndAndBeginQuery("Downsample"); + struct PushConstants { int mipLevel; float threshold; @@ -351,6 +356,8 @@ namespace Atlas { // Upsample { + Graphics::Profiler::EndAndBeginQuery("Upsample"); + struct PushConstants { int mipLevel; float filterSize = 2.0f; @@ -386,6 +393,9 @@ namespace Atlas { std::swap(textureIn, textureOut); } + + Graphics::Profiler::EndQuery(); + Graphics::Profiler::EndQuery(); } } diff --git a/src/engine/resource/Resource.h b/src/engine/resource/Resource.h index 6fdae3631..48ceaa0bc 100644 --- a/src/engine/resource/Resource.h +++ b/src/engine/resource/Resource.h @@ -136,7 +136,7 @@ namespace Atlas { Ref data; std::atomic_bool isLoaded = false; - JobGroup jobGroup; + JobGroup jobGroup{ JobPriority::Low }; std::shared_future future; int32_t framesToDeletion = RESOURCE_RETENTION_FRAME_COUNT; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index e4cde2a1f..1d2155e89 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -462,9 +462,9 @@ namespace Atlas::Scene { auto type = 0; auto packedType = reinterpret_cast(type); lights.emplace_back(Renderer::Light { + .direction = vec4(0.0f, -1.0f, 0.0f, 0.0f), .color = vec4(vec3(0.0f), packedType), .intensity = 0.0f, - .direction = vec4(0.0f, -1.0f, 0.0f, 0.0f) }); } From 7992ccab80cdad1ef9ec3ec08bd6871656438a75 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Wed, 28 Aug 2024 20:11:30 +0200 Subject: [PATCH 12/66] Fixed a few more issues --- .../panels/PostProcessingPanel.cpp | 2 +- src/demo/App.cpp | 1 + src/engine/postprocessing/Bloom.h | 8 +++-- .../PostProcessingSerializer.cpp | 30 +++++++++++++++++++ .../postprocessing/PostProcessingSerializer.h | 4 +++ src/engine/renderer/PostProcessRenderer.cpp | 2 ++ src/engine/renderer/helper/RenderList.cpp | 3 +- src/engine/scene/Scene.cpp | 6 +--- src/engine/scene/SceneRenderState.cpp | 4 +-- src/tests/App.cpp | 2 ++ 10 files changed, 51 insertions(+), 11 deletions(-) diff --git a/libs/ImguiExtension/panels/PostProcessingPanel.cpp b/libs/ImguiExtension/panels/PostProcessingPanel.cpp index 4a49819a6..1797d52cb 100644 --- a/libs/ImguiExtension/panels/PostProcessingPanel.cpp +++ b/libs/ImguiExtension/panels/PostProcessingPanel.cpp @@ -27,7 +27,7 @@ namespace Atlas::ImguiExtension { ImGui::Text("Chromatic aberration"); ImGui::Checkbox("Enable##Chromatic aberration", &postProcessing.chromaticAberration.enable); ImGui::Checkbox("Colors reversed", &postProcessing.chromaticAberration.colorsReversed); - ImGui::SliderFloat("Strength##v", &postProcessing.chromaticAberration.strength, 0.0f, 4.0f); + ImGui::SliderFloat("Strength##Chromatic abberation", &postProcessing.chromaticAberration.strength, 0.0f, 4.0f); ImGui::Text("Film grain"); ImGui::Checkbox("Enable##Film grain", &postProcessing.filmGrain.enable); ImGui::SliderFloat("Strength##Film grain", &postProcessing.filmGrain.strength, 0.0f, 1.0f); diff --git a/src/demo/App.cpp b/src/demo/App.cpp index f9cf6216e..c0f5b32ad 100644 --- a/src/demo/App.cpp +++ b/src/demo/App.cpp @@ -639,6 +639,7 @@ void App::Render(float deltaTime) { } recreateSwapchain = false; + } if (slowMode) { using namespace std::chrono_literals; std::this_thread::sleep_for(60ms); } diff --git a/src/engine/postprocessing/Bloom.h b/src/engine/postprocessing/Bloom.h index 590251713..363e19633 100644 --- a/src/engine/postprocessing/Bloom.h +++ b/src/engine/postprocessing/Bloom.h @@ -2,6 +2,9 @@ #include "../System.h" +#include "resource/Resource.h" +#include "texture/Texture2D.h" + namespace Atlas::PostProcessing { class Bloom { @@ -11,12 +14,13 @@ namespace Atlas::PostProcessing { bool enable = true; float strength = 0.01f; - float threshold = 0.5f; + float threshold = 1.0f; float filterSize = 0.02f; uint32_t mipLevels = 6; - }; + ResourceHandle dirtMap; + }; } \ No newline at end of file diff --git a/src/engine/postprocessing/PostProcessingSerializer.cpp b/src/engine/postprocessing/PostProcessingSerializer.cpp index 3239151d2..365e6f1ae 100644 --- a/src/engine/postprocessing/PostProcessingSerializer.cpp +++ b/src/engine/postprocessing/PostProcessingSerializer.cpp @@ -1,5 +1,7 @@ #include "PostProcessingSerializer.h" +#include "resource/ResourceManager.h" + namespace Atlas::PostProcessing { void to_json(json& j, const ChromaticAberration& p) { @@ -70,6 +72,32 @@ namespace Atlas::PostProcessing { j.at("color").get_to(p.color); } + void to_json(json& j, const Bloom& p) { + j = json { + {"enable", p.enable}, + {"filterSize", p.filterSize}, + {"mipLevels", p.mipLevels}, + {"strength", p.strength}, + {"threshold", p.threshold}, + }; + + if (p.dirtMap.IsValid()) + j["dirtMap"] = p.dirtMap.GetResource()->path; + + } + + void from_json(const json& j, Bloom& p) { + j.at("enable").get_to(p.enable); + j.at("filterSize").get_to(p.filterSize); + j.at("mipLevels").get_to(p.mipLevels); + j.at("strength").get_to(p.strength); + j.at("threshold").get_to(p.threshold); + + if (j.contains("dirtMap")) + p.dirtMap = ResourceManager::GetOrLoadResource(j["dirtMap"], false, + Texture::Wrapping::Repeat, Texture::Filtering::Linear, 0); + } + void to_json(json& j, const PostProcessing& p) { j = json { {"tint", p.tint}, @@ -84,6 +112,7 @@ namespace Atlas::PostProcessing { {"chromaticAberration", p.chromaticAberration}, {"filmGrain", p.filmGrain}, {"sharpen", p.sharpen}, + {"bloom", p.bloom}, }; } @@ -100,6 +129,7 @@ namespace Atlas::PostProcessing { j.at("chromaticAberration").get_to(p.chromaticAberration); j.at("filmGrain").get_to(p.filmGrain); j.at("sharpen").get_to(p.sharpen); + try_get_json(j, "bloom", p.bloom); } } \ No newline at end of file diff --git a/src/engine/postprocessing/PostProcessingSerializer.h b/src/engine/postprocessing/PostProcessingSerializer.h index 86331802f..5b2a1a949 100644 --- a/src/engine/postprocessing/PostProcessingSerializer.h +++ b/src/engine/postprocessing/PostProcessingSerializer.h @@ -26,6 +26,10 @@ namespace Atlas::PostProcessing { void from_json(const json& j, Vignette& p); + void to_json(json& j, const Bloom& p); + + void from_json(const json& j, Bloom& p); + void to_json(json& j, const PostProcessing& p); void from_json(const json& j, PostProcessing& p); diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index 7fcf5a8bf..13115434d 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -364,6 +364,8 @@ namespace Atlas { }; auto pipelineConfig = PipelineConfig("bloom/bloomUpsample.csh"); + pipelineConfig.ManageMacro("DIRT_MAP", bloom.dirtMap.IsLoaded()); + auto pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); diff --git a/src/engine/renderer/helper/RenderList.cpp b/src/engine/renderer/helper/RenderList.cpp index 6121467bf..6c45d309e 100644 --- a/src/engine/renderer/helper/RenderList.cpp +++ b/src/engine/renderer/helper/RenderList.cpp @@ -22,6 +22,7 @@ namespace Atlas { void RenderList::NewFrame(Scene::Scene* scene) { + std::scoped_lock lock(mutex); this->scene = scene; doneProcessingShadows = false; @@ -321,4 +322,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index f62e98b98..85c571195 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -576,11 +576,7 @@ namespace Atlas { void Scene::WaitForAsyncWorkCompletion() { - JobSystem::Wait(renderState.bindlessMeshMapUpdateJob); - JobSystem::Wait(renderState.bindlessTextureMapUpdateJob); - JobSystem::Wait(renderState.bindlessOtherTextureMapUpdateJob); - JobSystem::Wait(renderState.materialUpdateJob); - JobSystem::Wait(renderState.rayTracingWorldUpdateJob); + renderState.WaitForAsyncWorkCompletion(); } diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 1d2155e89..f6b63bbc7 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -468,9 +468,9 @@ namespace Atlas::Scene { }); } - if (lightBuffer.GetElementCount() < lightEntities.size()) { + if (lightBuffer.GetElementCount() < lights.size()) { lightBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit - | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Renderer::Light), lightEntities.size(), lights.data()); + | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Renderer::Light), lights.size(), lights.data()); } else { lightBuffer.SetData(lights.data(), 0, lights.size()); diff --git a/src/tests/App.cpp b/src/tests/App.cpp index bdaa668d8..5d1234b24 100644 --- a/src/tests/App.cpp +++ b/src/tests/App.cpp @@ -154,6 +154,7 @@ void App::Update(float deltaTime) { if (sceneReload) { UnloadScene(); LoadScene(); + scene->WaitForAsyncWorkCompletion(); sceneReload = false; } @@ -211,6 +212,7 @@ void App::Render(float deltaTime) { if (!loadingComplete) { DisplayLoadingScreen(deltaTime); + scene->WaitForAsyncWorkCompletion(); return; } From 2ff44bd1baaaefdc6abf25bdba409cfa37d7129f Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Fri, 30 Aug 2024 21:21:39 +0200 Subject: [PATCH 13/66] Downgrade jolt due to material issue --- CMakeLists.txt | 2 +- src/engine/CMakeLists.txt | 6 +++--- src/engine/physics/Player.cpp | 6 +++--- vcpkg.json | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3941e2069..b49ff4599 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,7 @@ find_package(VulkanMemoryAllocator CONFIG REQUIRED) find_package(glslang CONFIG REQUIRED) find_package(SPIRV-Tools-opt CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) -find_package(Jolt CONFIG REQUIRED) +find_package(unofficial-joltphysics CONFIG REQUIRED) find_package(Lua REQUIRED) find_package(sol2 CONFIG REQUIRED) diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index e603fd324..2688a2547 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -53,7 +53,7 @@ if(WIN32) set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SPIRV-Tools-opt volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator - unofficial::spirv-reflect glslang::SPIRV Jolt::Jolt + unofficial::spirv-reflect glslang::SPIRV unofficial::joltphysics::Jolt ${LUA_LIBRARIES} sol2 fsr2) endif() @@ -67,7 +67,7 @@ if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_MACOS_MVK -DVK_EXAMPLE_XCODE_GENERATED") set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static - volk::volk SPIRV-Tools-opt Jolt::Jolt fsr2 + volk::volk SPIRV-Tools-opt unofficial::joltphysics::Jolt fsr2 GPUOpen::VulkanMemoryAllocator Vulkan::Vulkan Vulkan::Headers unofficial::spirv-reflect glslang::SPIRV ${LUA_LIBRARIES} sol2) endif() @@ -92,7 +92,7 @@ if(UNIX AND NOT APPLE AND NOT ANDROID) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static fsr2 - volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator Jolt::Jolt + volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator unofficial::joltphysics::Jolt unofficial::spirv-reflect SPIRV-Tools-opt glslang::SPIRV ${LUA_LIBRARIES} sol2) endif() diff --git a/src/engine/physics/Player.cpp b/src/engine/physics/Player.cpp index f411a7ec9..e7b1473be 100644 --- a/src/engine/physics/Player.cpp +++ b/src/engine/physics/Player.cpp @@ -21,8 +21,8 @@ namespace Atlas::Physics { settings.mMaxConstraintIterations = 10; settings.mShapeOffset = VecToJPHVec(shapeOffset); settings.mShape = shape->ref; - settings.mInnerBodyShape = shape->ref; - settings.mInnerBodyLayer = Layers::Movable; + //settings.mInnerBodyShape = shape->ref; + //settings.mInnerBodyLayer = Layers::Movable; if (shape->type == ShapeType::Capsule) { auto shapeSettings = static_cast(shape->settings.get()); @@ -148,7 +148,7 @@ namespace Atlas::Physics { auto gravityVector = -GetUp() * glm::length(world->GetGravity()); - character->SetEnhancedInternalEdgeRemoval(true); + //character->SetEnhancedInternalEdgeRemoval(true); JPH::CharacterVirtual::ExtendedUpdateSettings settings; diff --git a/vcpkg.json b/vcpkg.json index 4c8eb135d..3df880319 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -84,7 +84,7 @@ }, { "name": "joltphysics", - "version": "5.1.0" + "version": "5.0.0#1" }, { "name": "lua", From 18fa9891808605a37c64b37e1485824c648399d7 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 31 Aug 2024 18:22:16 +0200 Subject: [PATCH 14/66] Reverted some bloom changes --- data/shader/bloom/bloomDownsample.csh | 12 ++--- data/shader/rtgi/temporal.csh | 2 +- data/shader/ssgi/ssgi.csh | 68 ++++++++++++++++++--------- 3 files changed, 52 insertions(+), 30 deletions(-) diff --git a/data/shader/bloom/bloomDownsample.csh b/data/shader/bloom/bloomDownsample.csh index a222f93c0..5a66ed68a 100644 --- a/data/shader/bloom/bloomDownsample.csh +++ b/data/shader/bloom/bloomDownsample.csh @@ -3,6 +3,8 @@ layout (local_size_x = 16, local_size_y = 16) in; #include <../common/utility.hsh> #include <../common/flatten.hsh> +//#define NO_SHARED + layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; layout (set = 3, binding = 1) uniform sampler2D textureIn; @@ -84,24 +86,22 @@ vec3 Sample(vec2 texCoord) { float weights[4] = { (1 - x) * (1 - y), x * (1 - y), (1 - x) * y, x * y }; - bool invalidIdx = false; - vec3 color = vec3(0.0); for (int i = 0; i < 4; i++) { ivec2 offsetPixel = ivec2(pixel) + pixelOffsets[i]; offsetPixel -= groupOffset; + offsetPixel = clamp(offsetPixel, ivec2(0), unflattenedSharedDataSize - ivec2(1)); int sharedMemoryIdx = Flatten2D(offsetPixel, unflattenedSharedDataSize); - if (sharedMemoryIdx < 0 || sharedMemoryIdx >= sharedDataSize) - invalidIdx = true; color += weights[i] * sharedMemory[sharedMemoryIdx]; } - return invalidIdx ? vec3(10000.0, 0.0, 0.0) : color; + return color; #endif } vec3 SampleShared(ivec2 texel) { + // This is offcenter bool invalidIdx = false; const ivec2 localOffset = 2 * ivec2(gl_LocalInvocationID); @@ -127,7 +127,7 @@ void main() { if (coord.x < size.x && coord.y < size.y) { -#ifdef NO_SHARED +#if 1 // Lower mip tex coord vec2 texCoord = (coord + 0.5) / size; // Upper mip texel size diff --git a/data/shader/rtgi/temporal.csh b/data/shader/rtgi/temporal.csh index 8c9864bb5..78838d8e3 100644 --- a/data/shader/rtgi/temporal.csh +++ b/data/shader/rtgi/temporal.csh @@ -401,7 +401,7 @@ void main() { vec2 velocity = texelFetch(velocityTexture, velocityPixel, 0).rg; vec2 uv = (vec2(pixel) + vec2(0.5)) * invResolution + velocity; - vec2 historyPixel = vec2(pixel) + (velocity * resolution) + 0.5; + vec2 historyPixel = vec2(pixel) + (velocity * resolution) ; bool valid = true; vec4 history; diff --git a/data/shader/ssgi/ssgi.csh b/data/shader/ssgi/ssgi.csh index 203d73866..9b54d7149 100644 --- a/data/shader/ssgi/ssgi.csh +++ b/data/shader/ssgi/ssgi.csh @@ -76,25 +76,22 @@ void main() { vec3 viewPos = ConvertDepthToViewSpace(depth, texCoord); vec3 worldPos = vec3(globalData.ivMatrix * vec4(viewPos, 1.0)); vec3 viewVec = vec3(globalData.ivMatrix * vec4(viewPos, 0.0)); - vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(DecodeNormal(textureLod(normalTexture, texCoord, 0).rg), 0.0))); + vec3 viewNorm = normalize(DecodeNormal(textureLod(normalTexture, texCoord, 0).rg)); + vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(viewNorm, 0.0))); uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; Material material = UnpackMaterial(materialIdx); - float roughness = texelFetch(roughnessMetallicAoTexture, pixel, 0).r; - material.roughness *= material.roughnessMap ? roughness : 1.0; - vec3 irradiance = vec3(0.0); float hits = 0.0; if (depth < 1.0) { - float alpha = sqr(material.roughness); - vec3 V = normalize(-viewVec); vec3 N = worldNorm; Surface surface = CreateSurface(V, N, vec3(1.0), material); + int totalCount = 0; for (uint j = 0; j < uniforms.rayCount; j++) { int sampleIdx = int(uniforms.frameSeed * uniforms.rayCount + j); @@ -107,7 +104,9 @@ void main() { Ray ray; float pdf = 1.0; - BRDFSample brdfSample = SampleDiffuseBRDF(surface, blueNoiseVec.xy); + float NdotL; + ImportanceSampleCosDir(N, blueNoiseVec.xy, + ray.direction, NdotL, pdf); ray.hitID = -1; ray.hitDistance = 0.0; @@ -117,10 +116,11 @@ void main() { float stepSize = rayLength / float(uniforms.sampleCount); - ray.direction = brdfSample.L; ray.origin = worldPos + surface.N * 0.1 + ray.direction * blueNoiseVec.z * stepSize; - bool hit = false; + vec3 rayIrradiance = vec3(0.0); + + float hit = 0.0; for (uint i = 0; i < uniforms.sampleCount; i++) { vec3 rayPos = vec3(globalData.vMatrix * vec4(ray.origin + float(i) * ray.direction * stepSize, 1.0)); @@ -136,33 +136,55 @@ void main() { float stepDepth = texelFetch(depthTexture, stepPixel, 0).r; vec3 stepPos = ConvertDepthToViewSpace(stepDepth, uvPos); - float stepLinearDepth = -stepPos.z; - float rayDepth = -rayPos.z; + float stepLinearDepth = abs(stepPos.z); + float rayDepth = abs(rayPos.z); float depthDelta = rayDepth - stepLinearDepth; - vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(DecodeNormal(texelFetch(normalTexture, stepPixel, 0).rg), 0.0))); + vec3 stepViewNorm = normalize(DecodeNormal(texelFetch(normalTexture, stepPixel, 0).rg)); + vec3 stepWorldNorm = normalize(vec3(globalData.ivMatrix * vec4(stepViewNorm, 0.0))); + + vec3 rayDir = normalize(stepPos - viewPos); + + /* + if (rayDepth < stepLinearDepth) { + float NdotV = dot(stepViewNorm, -rayDir); + float NdotL = dot(-worldNorm, surface.N); + if (NdotV > 0.0) { + ivec2 lightPixel = uniforms.downsampled2x > 0 ? stepPixel * 2 + pixelOffset : stepPixel; + vec3 hitRadiance = texelFetch(directLightTexture, lightPixel, 0).rgb; + rayIrradiance += hitRadiance * max(dot(viewNorm, rayDir), 0.0) / pdf / PI; + totalCount += 1; + } + } + */ // Check if we are now behind the depth buffer, use that hit as the source of radiance - if (stepLinearDepth < rayDepth && abs(depthDelta) < rayLength) { - float NdotV = dot(worldNorm, -ray.direction) * 0.5 + 0.5; - float NdotL = dot(-worldNorm, surface.N) * 0.5 + 0.5; - if (true) { + if (rayDepth >= stepLinearDepth) { + float NdotV = dot(stepViewNorm, -rayDir); + if (NdotV > 0.0 && abs(depthDelta) < stepSize) { ivec2 lightPixel = uniforms.downsampled2x > 0 ? stepPixel * 2 + pixelOffset : stepPixel; - vec3 rayIrradiance = texelFetch(directLightTexture, lightPixel, 0).rgb; - float dist = distance(viewPos, stepPos); - irradiance += rayIrradiance * max(NdotL, 0.0) * NdotV * surface.NdotL / max(0.1, dist); + vec3 hitRadiance = texelFetch(directLightTexture, lightPixel, 0).rgb; + rayIrradiance += hitRadiance * NdotV * max(dot(viewNorm, rayDir), 0.0) / pdf / PI; + totalCount += 1; + } - hit = true; - break; + if (abs(depthDelta) < float(i + 1) * stepSize) { + //hit = max(0.0, 1.0 - ((distance(stepPos, rayPos)) / rayLength)); + hit = 1.0; + break; + } + //hit = max(0.0, 1.0 - ((distance(stepPos, rayPos)) / rayLength)); } } - hits += hit ? 1.0 : 0.0; + irradiance += (rayIrradiance / max(1.0, float(totalCount))); + + hits += hit; } - irradiance /= float(uniforms.rayCount); + irradiance /= (float(uniforms.rayCount)); float irradianceMax = max(max(max(irradiance.r, max(irradiance.g, irradiance.b)), uniforms.radianceLimit), 0.01); From 303d580b54433a4fc93d7ca549743ed81e1e67e2 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 1 Sep 2024 16:53:53 +0200 Subject: [PATCH 15/66] A number of improvements --- data/shader/deferred/geometry.vsh | 2 +- data/shader/postprocessing.fsh | 12 +++++----- data/shader/reflection/rtreflection.csh | 9 ++++--- data/shader/rtgi/rtgi.csh | 9 ++++--- data/shader/rtgi/temporal.csh | 6 ++--- data/shader/volumetric/volumetric.csh | 15 ++++++++++-- libs/ImguiExtension/panels/RTGIPanel.cpp | 3 ++- .../ImguiExtension/panels/ReflectionPanel.cpp | 1 + src/editor/App.cpp | 24 +++++++++++++++++++ src/editor/Serialization.cpp | 2 ++ src/editor/ui/panels/ResourceSelectionPanel.h | 4 ++++ src/editor/ui/panels/ViewportPanel.cpp | 12 ++++++++++ src/editor/ui/panels/ViewportPanel.h | 3 +++ .../ui/windows/ContentBrowserWindow.cpp | 16 ++++++++++++- src/editor/ui/windows/SceneWindow.cpp | 9 +++++++ src/editor/ui/windows/SceneWindow.h | 1 + src/engine/lighting/RTGI.h | 2 ++ src/engine/lighting/Reflection.h | 2 ++ src/engine/renderer/PostProcessRenderer.cpp | 8 +++---- src/engine/renderer/RTGIRenderer.cpp | 3 ++- src/engine/renderer/RTGIRenderer.h | 4 ++++ src/engine/renderer/RTReflectionRenderer.cpp | 3 ++- src/engine/renderer/RTReflectionRenderer.h | 6 ++++- src/engine/renderer/VolumetricRenderer.cpp | 13 ++++++++++ src/engine/renderer/VolumetricRenderer.h | 3 +++ src/engine/scene/Entity.h | 12 ++++++++++ .../scripting/bindings/SceneBindings.cpp | 2 ++ 27 files changed, 159 insertions(+), 27 deletions(-) diff --git a/data/shader/deferred/geometry.vsh b/data/shader/deferred/geometry.vsh index 37a2f8be9..2e50637a2 100644 --- a/data/shader/deferred/geometry.vsh +++ b/data/shader/deferred/geometry.vsh @@ -123,7 +123,7 @@ void main() { #if defined(NORMAL_MAP) || defined(HEIGHT_MAP) vec3 normal = normalize(normalVS); - float correctionFactor = vTangent.w * (PushConstants.invertUVs > 0 ? -1.0 : 1.0); + float correctionFactor = vTangent.w * (PushConstants.invertUVs > 0 ? 1.0 : -1.0); vec3 tangent = normalize(mat3(mvMatrix) * vTangent.xyz); vec3 bitangent = normalize(correctionFactor * diff --git a/data/shader/postprocessing.fsh b/data/shader/postprocessing.fsh index 6fe34ad85..db9f71b3a 100644 --- a/data/shader/postprocessing.fsh +++ b/data/shader/postprocessing.fsh @@ -88,11 +88,11 @@ void main() { vec3 color = vec3(0.0); #ifdef CHROMATIC_ABERRATION - vec2 uvRedChannel = (positionVS - positionVS * 0.005f * Uniforms.aberrationStrength - * Uniforms.aberrationReversed) * 0.5f + 0.5f; - vec2 uvGreenChannel = (positionVS - positionVS * 0.0025f * Uniforms.aberrationStrength) * 0.5f + 0.5f; - vec2 uvBlueChannel = (positionVS - positionVS * 0.005f * Uniforms.aberrationStrength - * (1.0f - Uniforms.aberrationReversed)) * 0.5f + 0.5f; + vec2 uvRedChannel = (positionVS - positionVS * 0.005 * Uniforms.aberrationStrength + * Uniforms.aberrationReversed) * 0.5 + 0.5; + vec2 uvGreenChannel = (positionVS - positionVS * 0.0025 * Uniforms.aberrationStrength) * 0.5 + 0.5; + vec2 uvBlueChannel = (positionVS - positionVS * 0.005 * Uniforms.aberrationStrength + * (1.0f - Uniforms.aberrationReversed)) * 0.5 + 0.5; color.r = textureLod(hdrTexture, uvRedChannel, 0.0).r; color.g = textureLod(hdrTexture, uvGreenChannel, 0.0).g; @@ -101,7 +101,7 @@ void main() { #ifdef BLOOM color.r += Uniforms.bloomStrength * textureLod(bloomTexture, uvRedChannel, 0.0).r; color.g += Uniforms.bloomStrength * textureLod(bloomTexture, uvGreenChannel, 0.0).g; - color.b += uniforms.bloomStrength * textureLod(bloomTexture, uvBlueChannel, 0.0).b; + color.b += Uniforms.bloomStrength * textureLod(bloomTexture, uvBlueChannel, 0.0).b; #endif #else color = textureLod(hdrTexture, texCoord, 0.0).rgb; diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index c4109dfac..a568e27a1 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -46,9 +46,13 @@ layout(std140, set = 3, binding = 9) uniform UniformBuffer { float radianceLimit; uint frameSeed; float bias; + int lightSampleCount; int textureLevel; float roughnessCutoff; int halfRes; + int padding0; + int padding1; + int padding2; ivec2 resolution; Shadow shadow; } uniforms; @@ -181,14 +185,13 @@ vec3 EvaluateHit(inout Ray ray) { radiance += surface.material.emissiveColor; - int directSampleCount = 4; float curSeed = float(uniforms.frameSeed) / 255.0; // Evaluate direct light - for (int i = 0; i < directSampleCount; i++) { + for (int i = 0; i < uniforms.lightSampleCount; i++) { radiance += EvaluateDirectLight(surface, curSeed); } - radiance /= float(directSampleCount); + radiance /= float(uniforms.lightSampleCount); // Evaluate indirect lighting #ifdef DDGI diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index a8a410b95..3363949c1 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -46,9 +46,13 @@ layout(std140, set = 3, binding = 9) uniform UniformBuffer { float radianceLimit; uint frameSeed; float bias; + int lightSampleCount; int textureLevel; float roughnessCutoff; int halfRes; + int padding0; + int padding1; + int padding2; ivec2 resolution; Shadow shadow; } uniforms; @@ -170,14 +174,13 @@ vec3 EvaluateHit(inout Ray ray) { radiance += surface.material.emissiveColor; - int directSampleCount = 4; float curSeed = float(uniforms.frameSeed) / 255.0; // Evaluate direct light - for (int i = 0; i < directSampleCount; i++) { + for (int i = 0; i < uniforms.lightSampleCount; i++) { radiance += EvaluateDirectLight(surface, curSeed); } - radiance /= float(directSampleCount); + radiance /= float(uniforms.lightSampleCount); // Evaluate indirect lighting #ifdef DDGI diff --git a/data/shader/rtgi/temporal.csh b/data/shader/rtgi/temporal.csh index 8c9864bb5..d67fad1ed 100644 --- a/data/shader/rtgi/temporal.csh +++ b/data/shader/rtgi/temporal.csh @@ -197,7 +197,7 @@ bool SampleHistory(ivec2 pixel, vec2 historyPixel, out vec4 history, out vec4 hi offsetPixel = clamp(offsetPixel, ivec2(0), ivec2(resolution) - ivec2(1)); vec3 historyNormal = DecodeNormal(texelFetch(historyNormalTexture, offsetPixel, 0).rg); - float normalWeight = GetEdgePreservingNormalWeight(normal, historyNormal, 4.0); + float normalWeight = GetEdgePreservingNormalWeight(normal, historyNormal, 1.0); float historyDepth = ConvertDepthToViewSpaceDepth(texelFetch(historyDepthTexture, offsetPixel, 0).r); float depthWeight = min(1.0 , exp(-abs(linearDepth - historyDepth) * depthPhi)); @@ -223,7 +223,7 @@ bool SampleHistory(ivec2 pixel, vec2 historyPixel, out vec4 history, out vec4 hi offsetPixel = clamp(offsetPixel, ivec2(0), ivec2(resolution) - ivec2(1)); vec3 historyNormal = DecodeNormal(texelFetch(historyNormalTexture, offsetPixel, 0).rg); - float normalWeight = GetEdgePreservingNormalWeight(normal, historyNormal, 4.0); + float normalWeight = GetEdgePreservingNormalWeight(normal, historyNormal, 1.0); float historyDepth = ConvertDepthToViewSpaceDepth(texelFetch(historyDepthTexture, offsetPixel, 0).r); float depthWeight = min(1.0 , exp(-abs(linearDepth - historyDepth) * depthPhi)); @@ -401,7 +401,7 @@ void main() { vec2 velocity = texelFetch(velocityTexture, velocityPixel, 0).rg; vec2 uv = (vec2(pixel) + vec2(0.5)) * invResolution + velocity; - vec2 historyPixel = vec2(pixel) + (velocity * resolution) + 0.5; + vec2 historyPixel = vec2(pixel) + (velocity * resolution); bool valid = true; vec4 history; diff --git a/data/shader/volumetric/volumetric.csh b/data/shader/volumetric/volumetric.csh index d9c47d7d7..d0cd98a6a 100644 --- a/data/shader/volumetric/volumetric.csh +++ b/data/shader/volumetric/volumetric.csh @@ -12,6 +12,7 @@ layout (local_size_x = 8, local_size_y = 8) in; #include <../common/utility.hsh> #include <../common/random.hsh> #include <../clouds/shadow.hsh> +#include <../common/bluenoise.hsh> #include @@ -22,6 +23,8 @@ layout(set = 3, binding = 3) uniform sampler2D cloudMap; layout(set = 3, binding = 4) uniform sampler2D oceanDepthTexture; layout(set = 3, binding = 5) uniform usampler2D oceanStencilTexture; layout(set = 3, binding = 6) uniform sampler2D volumetricCloudTexture; +layout(set = 3, binding = 8) uniform sampler2D scramblingRankingTexture; +layout(set = 3, binding = 9) uniform sampler2D sobolSequenceTexture; layout(std140, set = 3, binding = 7) uniform UniformBuffer { int sampleCount; @@ -86,9 +89,14 @@ vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { vec4 extinction = vec4(1.0); vec4 extinctionWithClouds = vec4(1.0); - vec2 interleavedTexCoords = (0.5 * texCoords + 0.5) * resolution; + vec2 interleavedTexCoords = (0.5 * texCoords + 0.5) * resolution * 4.0; float noiseOffset = GetInterleavedGradientNoise(interleavedTexCoords); + + ivec2 pixel = ivec2(gl_GlobalInvocationID); + int sampleIdx = int(globalData.frameCount) % 16; + //noiseOffset = SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture); + vec3 currentPosition = stepVector * (noiseOffset + startDepth); int cascadeIndex = 0; @@ -125,6 +133,9 @@ vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { lastCascadeIndex = cascadeIndex; + float positionLength = dist; + float positionRatio = positionLength / uniforms.light.shadow.distance; + vec3 shadowPosition = positionRatio <= 1.0 ? currentPosition : currentPosition / positionRatio; vec4 cascadeSpace = cascadeMatrix * vec4(currentPosition, 1.0); cascadeSpace.xyz /= cascadeSpace.w; @@ -142,7 +153,7 @@ vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { #endif #endif - //shadowValue = distance > uniforms.light.shadow.distance ? 1.0 : shadowValue; + //shadowValue = dist > uniforms.light.shadow.distance ? 1.0 : shadowValue; vec3 worldPosition = vec3(globalData.ivMatrix * vec4(currentPosition, 1.0)); #ifdef CLOUDS diff --git a/libs/ImguiExtension/panels/RTGIPanel.cpp b/libs/ImguiExtension/panels/RTGIPanel.cpp index 647457c22..87c3369a7 100644 --- a/libs/ImguiExtension/panels/RTGIPanel.cpp +++ b/libs/ImguiExtension/panels/RTGIPanel.cpp @@ -26,7 +26,8 @@ namespace Atlas::ImguiExtension { ImGui::SetTooltip("Limits the amount of incoming radiance. Is internally scale by the camera exposure."); } ImGui::SliderFloat("Bias", &rtgi->bias, 0.0f, 1.0f); - ImGui::SliderInt("Texture level##Reflection", &rtgi->textureLevel, 0, 10); + ImGui::SliderInt("Texture level##RTGI", &rtgi->textureLevel, 0, 10); + ImGui::SliderInt("Light sample count##RTGI", &rtgi->lightSampleCount, 0, 10); ImGui::Text("Denoiser"); ImGui::SliderFloat("Spatial filter strength", &rtgi->spatialFilterStrength, 0.0f, 10.0f); ImGui::SliderFloat("Temporal weight", &rtgi->temporalWeight, 0.0f, 1.0f); diff --git a/libs/ImguiExtension/panels/ReflectionPanel.cpp b/libs/ImguiExtension/panels/ReflectionPanel.cpp index b103876c3..f9b1fec8e 100644 --- a/libs/ImguiExtension/panels/ReflectionPanel.cpp +++ b/libs/ImguiExtension/panels/ReflectionPanel.cpp @@ -27,6 +27,7 @@ namespace Atlas::ImguiExtension { ImGui::SliderFloat("Bias", &reflection->bias, 0.0f, 1.0f); ImGui::SliderFloat("Roughness cuttoff", &reflection->roughnessCutoff, 0.0f, 1.0f); ImGui::SliderInt("Texture level##Reflection", &reflection->textureLevel, 0, 10); + ImGui::SliderInt("Light sample count##Reflection", &reflection->lightSampleCount, 0, 10); ImGui::Text("Denoiser"); ImGui::SliderFloat("Spatial filter strength", &reflection->spatialFilterStrength, 0.0f, 10.0f); ImGui::SliderFloat("Temporal weight", &reflection->temporalWeight, 0.0f, 1.0f); diff --git a/src/editor/App.cpp b/src/editor/App.cpp index 94d8f6796..f3493f385 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -372,6 +372,30 @@ namespace Atlas::Editor { auto set = Singletons::imguiWrapper->GetTextureDescriptorSet(&activeSceneWindow->viewportPanel.viewportTexture); ImGui::Image(set, renderArea); + if (activeSceneWindow->perfOverlayMaximized) { + ImGui::SetCursorPos(ImVec2(0.0f, 0.0f)); + auto gpuProfilerData = Graphics::Profiler::GetQueriesAverage(32, Graphics::Profiler::OrderBy::MAX_TIME); + + std::string perfString; + int32_t slowestThreadIdx = 0; + double slowestTime = 0.0; + for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { + const auto& threadData = gpuProfilerData[i]; + double threadTime = 0.0; + for (const auto& query : threadData.queries) { + threadTime += query.timer.elapsedTime; + } + if (threadTime > slowestTime) { + slowestTime = threadTime; + slowestThreadIdx = i; + } + } + + ImGui::SetWindowFontScale(1.5f); + ImGui::Text("Frame time: %.3fms, GPU time: %.3f", Clock::GetAverage() * 1000.0f, float(slowestTime / 1000000.0)); + ImGui::SetWindowFontScale(1.0f); + } + ImGui::PopStyleVar(); ImGui::PopStyleVar(); ImGui::PopStyleVar(); diff --git a/src/editor/Serialization.cpp b/src/editor/Serialization.cpp index c357f42e7..30840adb9 100644 --- a/src/editor/Serialization.cpp +++ b/src/editor/Serialization.cpp @@ -90,6 +90,7 @@ namespace Atlas::Editor { { "cameraRotationSpeed", sceneWindow->cameraRotationSpeed }, { "depthTestBoundingVolumes", sceneWindow->depthTestBoundingVolumes }, { "playMaximized", sceneWindow->playMaximized }, + { "perfOverlayMaximized", sceneWindow->perfOverlayMaximized }, { "camera", camera } }; @@ -126,6 +127,7 @@ namespace Atlas::Editor { try_get_json(j, "cameraRotationSpeed", sceneWindow->cameraRotationSpeed); try_get_json(j, "depthTestBoundingVolumes", sceneWindow->depthTestBoundingVolumes); try_get_json(j, "playMaximized", sceneWindow->playMaximized); + try_get_json(j, "perfOverlayMaximized", sceneWindow->perfOverlayMaximized); try_get_json(j, "camera", camera); sceneWindow->cameraEntity = sceneWindow->scene->CreateEntity(); diff --git a/src/editor/ui/panels/ResourceSelectionPanel.h b/src/editor/ui/panels/ResourceSelectionPanel.h index f58773f66..4aaccf88b 100644 --- a/src/editor/ui/panels/ResourceSelectionPanel.h +++ b/src/editor/ui/panels/ResourceSelectionPanel.h @@ -33,6 +33,8 @@ namespace Atlas::Editor::UI { auto buttonName = resourceHandle.IsValid() ? resourceHandle.GetResource()->GetFileName() : "Drop resource here"; + ImGui::PushID(resourceHandle.GetID()); + popup.SetID(resourceHandle.GetID()); if (ImGui::Button(buttonName.c_str(), { resourceButtonSize, 0 })) popup.Open(); @@ -67,6 +69,8 @@ namespace Atlas::Editor::UI { auto resources = ResourceManager::GetResources(); handle = popup.Render(resources); + ImGui::PopID(); + if (handle.IsValid()) { resourceHandle = handle; resourceChanged = true; diff --git a/src/editor/ui/panels/ViewportPanel.cpp b/src/editor/ui/panels/ViewportPanel.cpp index fb02307d2..f35b87939 100644 --- a/src/editor/ui/panels/ViewportPanel.cpp +++ b/src/editor/ui/panels/ViewportPanel.cpp @@ -152,6 +152,14 @@ namespace Atlas::Editor::UI { mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, rtData->geometryNormalTexture.get(), 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); } + if (visualization == GBufferMaterialIdx) { + mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, rtData->materialIdxTexture.get(), + 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f / 10000.0f, false, true); + } + if (visualization == GBufferStencil) { + mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, rtData->stencilTexture.get(), + 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f / 255.0f, false, true); + } if (visualization == GBufferDepth) { mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, rtData->depthTexture.get(), 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); @@ -164,6 +172,10 @@ namespace Atlas::Editor::UI { mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, &renderTarget->reflectionTexture, 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); } + else if (visualization == Volumetrics) { + mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, &renderTarget->volumetricTexture, + 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); + } else if (visualization == Clouds) { mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, &renderTarget->volumetricCloudsTexture, 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); diff --git a/src/editor/ui/panels/ViewportPanel.h b/src/editor/ui/panels/ViewportPanel.h index cf1d7fdea..bec126fdf 100644 --- a/src/editor/ui/panels/ViewportPanel.h +++ b/src/editor/ui/panels/ViewportPanel.h @@ -13,8 +13,11 @@ namespace Atlas::Editor::UI { GBufferRoughnessMetalnessAo, GBufferNormals, GBufferGeometryNormals, + GBufferMaterialIdx, + GBufferStencil, GBufferDepth, GBufferVelocity, + Volumetrics, Clouds, Reflections, SSS, diff --git a/src/editor/ui/windows/ContentBrowserWindow.cpp b/src/editor/ui/windows/ContentBrowserWindow.cpp index 6b0f015e3..392c577d6 100644 --- a/src/editor/ui/windows/ContentBrowserWindow.cpp +++ b/src/editor/ui/windows/ContentBrowserWindow.cpp @@ -338,7 +338,21 @@ namespace Atlas::Editor::UI { if (ImGui::MenuItem("Open externally")) OpenExternally(std::filesystem::absolute(path).string(), isDirectory); - if (ImGui::MenuItem("Rename")) { + // We shouldn't allow the user to delete the root entity + if (ImGui::MenuItem("Duplicate")) { + int32_t counter = 0; + auto dupFilePath = path; + do { + dupFilePath = path; + dupFilePath.replace_extension(""); + auto replacement = dupFilePath.filename().string() + "(" + std::to_string(++counter) + ")"; + dupFilePath.replace_filename(replacement); + dupFilePath.replace_extension(path.extension()); + } while (std::filesystem::exists(dupFilePath)); + std::filesystem::copy(path, dupFilePath); + } + + if (ImGui::MenuItem("Rename") && !isDirectory) { renamePopupVisible = true; auto dirEntryFilename = path.filename(); renameString = dirEntryFilename.replace_extension("").string(); diff --git a/src/editor/ui/windows/SceneWindow.cpp b/src/editor/ui/windows/SceneWindow.cpp index d98d3e1d2..9b25bc623 100644 --- a/src/editor/ui/windows/SceneWindow.cpp +++ b/src/editor/ui/windows/SceneWindow.cpp @@ -342,6 +342,7 @@ namespace Atlas::Editor::UI { auto& camera = cameraEntity.GetComponent(); + ImGui::Separator(); ImGui::Text("Editor camera"); ImGui::DragFloat("Exposure", &camera.exposure, 0.1f, 0.01f, 180.0f); @@ -350,6 +351,7 @@ namespace Atlas::Editor::UI { ImGui::DragFloat("Near plane", &camera.nearPlane, 0.01f, 0.01f, 10.0f); ImGui::DragFloat("Far plane", &camera.farPlane, 1.0f, 1.0f, 20000.0f); + ImGui::Separator(); ImGui::Text("Rendering scale"); ImGui::DragFloat("Resolution scale##Rendering", &resolutionScale, 0.01f, 0.1f, 1.0f); @@ -357,10 +359,14 @@ namespace Atlas::Editor::UI { if (Singletons::renderTarget->GetScalingFactor() != resolutionScale) Singletons::renderTarget->SetScalingFactor(resolutionScale); + ImGui::Separator(); ImGui::Text("Path traces samples"); ImGui::DragInt("Sample count", &Singletons::mainRenderer->pathTracingRenderer.realTimeSamplesPerFrame, 1, 1, 16); + ImGui::Separator(); + ImGui::Text("Playing"); ImGui::Checkbox("Play maximized", &playMaximized); + ImGui::Checkbox("Show performance overlay", &perfOverlayMaximized); ImGui::EndPopup(); } @@ -393,9 +399,12 @@ namespace Atlas::Editor::UI { menuItem("Normals", ViewportVisualization::GBufferNormals); menuItem("Geometry normals", ViewportVisualization::GBufferGeometryNormals); menuItem("Velocity", ViewportVisualization::GBufferVelocity); + menuItem("Material index", ViewportVisualization::GBufferMaterialIdx); + menuItem("Stencil", ViewportVisualization::GBufferStencil); ImGui::EndMenu(); } + menuItem("Volumetrics", ViewportVisualization::Volumetrics); menuItem("Clouds", ViewportVisualization::Clouds); menuItem("Reflections", ViewportVisualization::Reflections); menuItem("SSS", ViewportVisualization::SSS); diff --git a/src/editor/ui/windows/SceneWindow.h b/src/editor/ui/windows/SceneWindow.h index 907158189..d02287efb 100644 --- a/src/editor/ui/windows/SceneWindow.h +++ b/src/editor/ui/windows/SceneWindow.h @@ -66,6 +66,7 @@ namespace Atlas::Editor::UI { bool hasPlayer = false; bool isPlaying = false; bool playMaximized = false; + bool perfOverlayMaximized = false; bool isActiveWindow = false; bool lockSelection = false; diff --git a/src/engine/lighting/RTGI.h b/src/engine/lighting/RTGI.h index e5490286a..b05863fa9 100644 --- a/src/engine/lighting/RTGI.h +++ b/src/engine/lighting/RTGI.h @@ -13,6 +13,8 @@ namespace Atlas { RTGI() = default; int32_t textureLevel = 4; + int32_t lightSampleCount = 2; + float radianceLimit = 5.0f; float bias = 0.15f; float spatialFilterStrength = 5.0f; diff --git a/src/engine/lighting/Reflection.h b/src/engine/lighting/Reflection.h index 1636f7313..7ce3c8e34 100644 --- a/src/engine/lighting/Reflection.h +++ b/src/engine/lighting/Reflection.h @@ -13,6 +13,8 @@ namespace Atlas { Reflection() = default; int32_t textureLevel = 3; + int32_t lightSampleCount = 2; + float radianceLimit = 10.0f; float roughnessCutoff = 0.9f; float bias = 0.15f; diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index 13115434d..ec5ac1cc0 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -37,10 +37,6 @@ namespace Atlas { ivec2 resolution = ivec2(target->GetWidth(), target->GetHeight()); - if (bloom.enable) { - GenerateBloom(bloom, &target->hdrTexture, &target->bloomTexture, commandList); - } - ivec2 groupCount = resolution / 8; groupCount.x += ((groupCount.x * 8 == resolution.x) ? 0 : 1); groupCount.y += ((groupCount.y * 8 == resolution.y) ? 0 : 1); @@ -129,6 +125,10 @@ namespace Atlas { Graphics::Profiler::EndQuery(); } + if (bloom.enable) { + GenerateBloom(bloom, &target->hdrTexture, &target->bloomTexture, commandList); + } + { Graphics::Profiler::BeginQuery("Main"); diff --git a/src/engine/renderer/RTGIRenderer.cpp b/src/engine/renderer/RTGIRenderer.cpp index 6fa3324ad..7677c5438 100644 --- a/src/engine/renderer/RTGIRenderer.cpp +++ b/src/engine/renderer/RTGIRenderer.cpp @@ -134,7 +134,8 @@ namespace Atlas { RTUniforms uniforms; uniforms.radianceLimit = rtgi->radianceLimit / glm::max(mainCamera.exposure, 0.00001f); uniforms.bias = rtgi->bias; - uniforms.frameSeed = frameCount++; + uniforms.frameSeed = frameCount++; + uniforms.lightSampleCount = rtgi->lightSampleCount; uniforms.textureLevel = rtgi->textureLevel; uniforms.halfRes = target->GetGIResolution() == HALF_RES ? 1 : 0; uniforms.resolution = res; diff --git a/src/engine/renderer/RTGIRenderer.h b/src/engine/renderer/RTGIRenderer.h index 8fc4a7a4b..2c02034e1 100644 --- a/src/engine/renderer/RTGIRenderer.h +++ b/src/engine/renderer/RTGIRenderer.h @@ -23,9 +23,13 @@ namespace Atlas { float radianceLimit; uint32_t frameSeed; float bias; + int32_t lightSampleCount; int32_t textureLevel; float roughnessCutoff; int32_t halfRes; + int32_t padding0; + int32_t padding1; + int32_t padding2; ivec2 resolution; Shadow shadow; }; diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index 317e47c2e..6b863f998 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -129,7 +129,8 @@ namespace Atlas { uniforms.radianceLimit = reflection->radianceLimit; uniforms.bias = reflection->bias; uniforms.roughnessCutoff = reflection->roughnessCutoff; - uniforms.frameSeed = frameCount++; + uniforms.frameSeed = frameCount++; + uniforms.lightSampleCount = reflection->lightSampleCount; uniforms.textureLevel = reflection->textureLevel; uniforms.halfRes = target->GetReflectionResolution() == HALF_RES ? 1 : 0; uniforms.resolution = rayRes; diff --git a/src/engine/renderer/RTReflectionRenderer.h b/src/engine/renderer/RTReflectionRenderer.h index 38ed51e00..3801f69b1 100644 --- a/src/engine/renderer/RTReflectionRenderer.h +++ b/src/engine/renderer/RTReflectionRenderer.h @@ -23,10 +23,14 @@ namespace Atlas { float radianceLimit; uint32_t frameSeed; float bias; + int32_t lightSampleCount; int32_t textureLevel; float roughnessCutoff; int32_t halfRes; - ivec2 resolution; + int32_t padding0; + int32_t padding1; + int32_t padding2; + ivec2 resolution; Shadow shadow; }; diff --git a/src/engine/renderer/VolumetricRenderer.cpp b/src/engine/renderer/VolumetricRenderer.cpp index b7301ba65..b9617130d 100644 --- a/src/engine/renderer/VolumetricRenderer.cpp +++ b/src/engine/renderer/VolumetricRenderer.cpp @@ -12,6 +12,16 @@ namespace Atlas { const int32_t filterSize = 4; blurFilter.CalculateBoxFilter(filterSize); + auto noiseImage = Loader::ImageLoader::LoadImage("scrambling_ranking.png", false, 4); + scramblingRankingTexture = Texture::Texture2D(noiseImage->width, noiseImage->height, + VK_FORMAT_R8G8B8A8_UNORM); + scramblingRankingTexture.SetData(noiseImage->GetData()); + + noiseImage = Loader::ImageLoader::LoadImage("sobol.png"); + sobolSequenceTexture = Texture::Texture2D(noiseImage->width, noiseImage->height, + VK_FORMAT_R8G8B8A8_UNORM); + sobolSequenceTexture.SetData(noiseImage->GetData()); + volumetricPipelineConfig = PipelineConfig("volumetric/volumetric.csh"); horizontalBlurPipelineConfig = PipelineConfig("bilateralBlur.csh", @@ -162,6 +172,9 @@ namespace Atlas { volumetricUniformBuffer.SetData(&uniforms, 0); commandList->BindBuffer(volumetricUniformBuffer.Get(), 3, 7); + commandList->BindImage(scramblingRankingTexture.image, scramblingRankingTexture.sampler, 3, 8); + commandList->BindImage(sobolSequenceTexture.image, sobolSequenceTexture.sampler, 3, 9); + volumetricPipelineConfig.ManageMacro("SHADOWS", light.shadow != nullptr); volumetricPipelineConfig.ManageMacro("CLOUDS", cloudsEnabled); volumetricPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowsEnabled); diff --git a/src/engine/renderer/VolumetricRenderer.h b/src/engine/renderer/VolumetricRenderer.h index 50b7ea54b..a7e6647b9 100644 --- a/src/engine/renderer/VolumetricRenderer.h +++ b/src/engine/renderer/VolumetricRenderer.h @@ -53,6 +53,9 @@ namespace Atlas { PipelineConfig resolvePipelineConfig; + Texture::Texture2D scramblingRankingTexture; + Texture::Texture2D sobolSequenceTexture; + Buffer::UniformBuffer volumetricUniformBuffer; Buffer::UniformBuffer blurWeightsUniformBuffer; Buffer::UniformBuffer resolveUniformBuffer; diff --git a/src/engine/scene/Entity.h b/src/engine/scene/Entity.h index 5201cc27b..366157489 100644 --- a/src/engine/scene/Entity.h +++ b/src/engine/scene/Entity.h @@ -81,6 +81,18 @@ namespace Atlas { } + inline uint64_t GetID() const { + + return uint64_t(entity); + + } + + inline uint32_t GetVersion() const { + + return entityManager->Version(entity); + + } + inline Scene* GetScene() const { return static_cast(entityManager->userData); diff --git a/src/engine/scripting/bindings/SceneBindings.cpp b/src/engine/scripting/bindings/SceneBindings.cpp index 07b8c8de1..d0bb3529c 100644 --- a/src/engine/scripting/bindings/SceneBindings.cpp +++ b/src/engine/scripting/bindings/SceneBindings.cpp @@ -41,6 +41,8 @@ namespace Atlas::Scripting::Bindings { auto entityType = ns->new_usertype("Entity", "IsValid", &Scene::Entity::IsValid, + "GetID", &Scene::Entity::GetID, + "GetVersion", &Scene::Entity::GetVersion, // Add components "AddAudioComponent", &Scene::Entity::AddComponent&, float, bool>, "AddAudioVolumeComponent", &Scene::Entity::AddComponent&, Volume::AABB&, float>, From e934c5835690b81d6a0d90ca78d0aaa0794f582b Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 3 Sep 2024 19:47:37 +0200 Subject: [PATCH 16/66] Ouput stacktrace on validation error --- src/engine/graphics/Instance.cpp | 8 ++++++++ src/tests/App.cpp | 2 ++ src/tests/App.h | 1 + src/tests/Main.cpp | 1 + 4 files changed, 12 insertions(+) diff --git a/src/engine/graphics/Instance.cpp b/src/engine/graphics/Instance.cpp index 1cd1ef07e..813e28808 100644 --- a/src/engine/graphics/Instance.cpp +++ b/src/engine/graphics/Instance.cpp @@ -8,6 +8,10 @@ #include #include +#if !defined(__clang__) && defined(AE_BUILDTYPE_DEBUG) +#include +#endif + namespace Atlas { namespace Graphics { @@ -315,6 +319,10 @@ namespace Atlas { case Log::Type::TYPE_ERROR: Log::Error(pCallbackData->pMessage, logSeverity); break; } +#if !defined(__clang__) && defined(AE_BUILDTYPE_DEBUG) + output.append("\nStack trace:\n" + std::stacktrace::current()); +#endif + #ifndef AE_BUILDTYPE_RELEASE if (logSeverity == Log::Severity::SEVERITY_HIGH) throw std::runtime_error(output); diff --git a/src/tests/App.cpp b/src/tests/App.cpp index 5d1234b24..375a97e03 100644 --- a/src/tests/App.cpp +++ b/src/tests/App.cpp @@ -56,6 +56,8 @@ void App::LoadContent(AppConfiguration config) { Atlas::PipelineManager::EnableHotReload(); + scene->postProcessing.fsr2 = config.fsr; + if (config.light) { auto directionalLightEntity = scene->CreateEntity(); auto& directionalLight = directionalLightEntity.AddComponent(LightType::DirectionalLight); diff --git a/src/tests/App.h b/src/tests/App.h index e2c7693b4..0b76b65b0 100644 --- a/src/tests/App.h +++ b/src/tests/App.h @@ -25,6 +25,7 @@ struct AppConfiguration { bool volumetric = true; bool ocean = true; bool light = true; + bool fsr = true; bool resize = false; bool recreateSwapchain = false; bool minimizeWindow = false; diff --git a/src/tests/Main.cpp b/src/tests/Main.cpp index a87249f10..089940848 100644 --- a/src/tests/Main.cpp +++ b/src/tests/Main.cpp @@ -103,6 +103,7 @@ auto testingValues = testing::Values( AppConfiguration { .volumetric = false }, AppConfiguration { .sharpen = false }, AppConfiguration { .light = false }, + AppConfiguration { .fsr = false }, AppConfiguration { .recreateSwapchain = true }, AppConfiguration { .resize = true }, AppConfiguration { .exampleRenderer = true }, From 0922510fdb2a32f0b94edd0f4e3983a122d54374 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Wed, 4 Sep 2024 00:46:12 +0200 Subject: [PATCH 17/66] Fix some of the build issues --- CMakeLists.txt | 6 ++-- README.md | 2 +- data/shader/bloom/bloomDownsample.csh | 3 +- .../panels/components/MeshComponentPanel.cpp | 3 +- src/engine/buffer/Buffer.cpp | 13 ++++++++ src/engine/buffer/Buffer.h | 7 +++++ src/engine/graphics/Instance.cpp | 2 +- src/engine/jobsystem/Job.h | 2 ++ src/engine/jobsystem/JobSemaphore.h | 21 +++++++++++++ src/engine/jobsystem/JobSystem.cpp | 13 +++++++- src/engine/jobsystem/JobSystem.h | 3 ++ src/engine/jobsystem/PriorityPool.cpp | 13 -------- src/engine/jobsystem/PriorityPool.h | 15 +++++++-- src/engine/mesh/Mesh.cpp | 26 ++++++++++++++++ src/engine/mesh/Mesh.h | 3 ++ src/engine/mesh/MeshSerializer.cpp | 5 +++ src/engine/raytracing/RayTracingWorld.cpp | 31 ++++++++++++++----- src/engine/raytracing/RayTracingWorld.h | 2 ++ src/engine/scene/Scene.cpp | 4 +++ src/engine/scene/SceneRenderState.h | 2 ++ .../scripting/bindings/GraphicsBindings.cpp | 28 ++++++++++++++--- 21 files changed, 169 insertions(+), 35 deletions(-) create mode 100644 src/engine/jobsystem/JobSemaphore.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b49ff4599..acdbf29e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ endif(COMMAND cmake_policy) cmake_minimum_required(VERSION 3.24) -project(AtlasEngine VERSION 0.2.0) +project(AtlasEngine VERSION 0.2.1) # Only 64 bit is supported ################################################################### @@ -48,13 +48,13 @@ if (ATLAS_EDITOR) set (ATLAS_IMGUI ON) endif() -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) if (CYGWIN OR MINGW) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -O3 -std=gnu++20" ) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -O3 -std=gnu++23" ) endif() if (ANDROID) diff --git a/README.md b/README.md index 80ba5b16e..6b004cecd 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This is a cross platform toy engine developed in my spare time that is available >The current version (0.2.0) contains many API changes and is still an active WIP ## Requirements - Vulkan SDK -- C++20 compatible compiler +- C++23 compatible compiler - CMake - Vcpkg ## Set up diff --git a/data/shader/bloom/bloomDownsample.csh b/data/shader/bloom/bloomDownsample.csh index 5a66ed68a..a1812a9a3 100644 --- a/data/shader/bloom/bloomDownsample.csh +++ b/data/shader/bloom/bloomDownsample.csh @@ -124,8 +124,7 @@ void main() { ivec2 size = imageSize(textureOut); ivec2 coord = ivec2(gl_GlobalInvocationID); - if (coord.x < size.x && - coord.y < size.y) { + if (coord.x < size.x && coord.y < size.y) { #if 1 // Lower mip tex coord diff --git a/src/editor/ui/panels/components/MeshComponentPanel.cpp b/src/editor/ui/panels/components/MeshComponentPanel.cpp index c96a94726..e63dd511d 100644 --- a/src/editor/ui/panels/components/MeshComponentPanel.cpp +++ b/src/editor/ui/panels/components/MeshComponentPanel.cpp @@ -26,9 +26,9 @@ namespace Atlas::Editor::UI { ImGui::Combo("Mobility", &mobilityItem, mobilityItems, IM_ARRAYSIZE(mobilityItems)); mesh->mobility = static_cast(mobilityItem); - ImGui::Checkbox("Invert UVs", &mesh->invertUVs); ImGui::Checkbox("Cull backfaces", &mesh->cullBackFaces); + ImGui::Checkbox("Ray trace", &mesh->rayTrace); ImGui::Checkbox("Is vegetation", &mesh->vegetation); ImGui::Checkbox("Cast shadow", &mesh->castShadow); @@ -38,6 +38,7 @@ namespace Atlas::Editor::UI { ImGui::Text("Culling settings"); ImGui::DragFloat("Distance culling", &mesh->distanceCulling, 1.0f); ImGui::DragFloat("Shadow distance culling", &mesh->shadowDistanceCulling, 1.0f); + ImGui::DragFloat("Ray trace distance culling", &mesh->rayTraceDistanceCulling, 1.0f); ImGui::Separator(); ImGui::Text("Wind settings"); diff --git a/src/engine/buffer/Buffer.cpp b/src/engine/buffer/Buffer.cpp index 267900c58..f17290f21 100644 --- a/src/engine/buffer/Buffer.cpp +++ b/src/engine/buffer/Buffer.cpp @@ -161,6 +161,19 @@ namespace Atlas { } + void Buffer::Reset() { + + sizeInBytes = 0; + + if (multiBuffered) { + multiBuffer.reset(); + } + else { + buffer.reset(); + } + + } + void Buffer::Reallocate(void *data) { auto device = Graphics::GraphicsDevice::DefaultDevice; diff --git a/src/engine/buffer/Buffer.h b/src/engine/buffer/Buffer.h index 98b288a33..9a7bdadc7 100644 --- a/src/engine/buffer/Buffer.h +++ b/src/engine/buffer/Buffer.h @@ -147,6 +147,13 @@ namespace Atlas { */ size_t GetAlignedOffset(size_t elementIndex); + /** + * Returns the aligned offset for dynamic uniform buffer binding + * @param elementIndex The offset in elements + * @return The offset in bytes + */ + void Reset(); + protected: void Reallocate(void* data); diff --git a/src/engine/graphics/Instance.cpp b/src/engine/graphics/Instance.cpp index 813e28808..1c882c069 100644 --- a/src/engine/graphics/Instance.cpp +++ b/src/engine/graphics/Instance.cpp @@ -320,7 +320,7 @@ namespace Atlas { } #if !defined(__clang__) && defined(AE_BUILDTYPE_DEBUG) - output.append("\nStack trace:\n" + std::stacktrace::current()); + output.append("\nStack trace:\n" + std::to_string(std::stacktrace::current())); #endif #ifndef AE_BUILDTYPE_RELEASE diff --git a/src/engine/jobsystem/Job.h b/src/engine/jobsystem/Job.h index b0eb8f043..22548694c 100644 --- a/src/engine/jobsystem/Job.h +++ b/src/engine/jobsystem/Job.h @@ -17,6 +17,8 @@ namespace Atlas { struct JobData { int32_t idx = 0; int32_t workerIdx = 0; + JobPriority priority; + void* userData = nullptr; }; diff --git a/src/engine/jobsystem/JobSemaphore.h b/src/engine/jobsystem/JobSemaphore.h new file mode 100644 index 000000000..9de3401cd --- /dev/null +++ b/src/engine/jobsystem/JobSemaphore.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace Atlas { + + class JobSemaphore { + + public: + inline void Reset() { counter.store(0); } + + inline void Release() { counter.fetch_add(1); } + + inline bool TryAquire() { return counter.load() > 0; } + + private: + std::atomic_int counter = 0; + + }; + +} \ No newline at end of file diff --git a/src/engine/jobsystem/JobSystem.cpp b/src/engine/jobsystem/JobSystem.cpp index 078f8da07..61e5cb429 100644 --- a/src/engine/jobsystem/JobSystem.cpp +++ b/src/engine/jobsystem/JobSystem.cpp @@ -59,7 +59,7 @@ namespace Atlas { Job job = { .priority = group.priority, .counter = &group.counter, - .function = func, + .function = std::move(func), .userData = userData }; @@ -118,6 +118,17 @@ namespace Atlas { } + void JobSystem::Wait(JobSemaphore& semaphore, JobPriority priority) { + + auto& priorityPool = priorityPools[static_cast(priority)]; + + while (!semaphore.TryAquire()) { + auto& worker = priorityPool.GetNextWorker(); + priorityPool.Work(worker.workerId); + } + + } + void JobSystem::Wait(JobGroup& group) { if (!group.HasFinished()) { diff --git a/src/engine/jobsystem/JobSystem.h b/src/engine/jobsystem/JobSystem.h index a61155697..a841f6e0d 100644 --- a/src/engine/jobsystem/JobSystem.h +++ b/src/engine/jobsystem/JobSystem.h @@ -10,6 +10,7 @@ #include "Job.h" #include "JobGroup.h" +#include "JobSemaphore.h" #include "PriorityPool.h" namespace Atlas { @@ -33,6 +34,8 @@ namespace Atlas { static void ExecuteMultiple(JobGroup& group, int32_t count, std::function func, void* userData = nullptr); + static void Wait(JobSemaphore& semaphore, JobPriority priority); + static void Wait(JobGroup& group); static void WaitSpin(JobGroup& group); diff --git a/src/engine/jobsystem/PriorityPool.cpp b/src/engine/jobsystem/PriorityPool.cpp index 53681afea..87567d5b1 100644 --- a/src/engine/jobsystem/PriorityPool.cpp +++ b/src/engine/jobsystem/PriorityPool.cpp @@ -39,19 +39,6 @@ namespace Atlas { } - void PriorityPool::Work(int32_t workerId) { - - auto& worker = workers[workerId]; - worker.Work(); - - for (int32_t i = 1; i < workerCount; i++) { - auto stealIdx = (-i + workerId + workerCount) % workerCount; - auto& stealFrom = workers[stealIdx]; - stealFrom.Work(); - } - - } - Worker& PriorityPool::GetNextWorker() { auto counter = workerCounter++; diff --git a/src/engine/jobsystem/PriorityPool.h b/src/engine/jobsystem/PriorityPool.h index 51c9efd6d..56cc0181b 100644 --- a/src/engine/jobsystem/PriorityPool.h +++ b/src/engine/jobsystem/PriorityPool.h @@ -15,12 +15,23 @@ namespace Atlas { void Shutdown(); - void Work(int32_t workerId); - Worker& GetNextWorker(); std::vector& GetAllWorkers(); + inline void Work(int32_t workerId) { + + auto& worker = workers[workerId]; + worker.Work(); + + for (int32_t i = 1; i < workerCount; i++) { + auto stealIdx = (-i + workerId + workerCount) % workerCount; + auto& stealFrom = workers[stealIdx]; + stealFrom.Work(); + } + + } + JobPriority priority; int32_t workerCount; std::atomic_uint32_t spinCounter = 0; diff --git a/src/engine/mesh/Mesh.cpp b/src/engine/mesh/Mesh.cpp index 1826e8c1c..147b4122e 100644 --- a/src/engine/mesh/Mesh.cpp +++ b/src/engine/mesh/Mesh.cpp @@ -146,6 +146,32 @@ namespace Atlas { } + void Mesh::ClearBVH() { + + isBvhBuilt = false; + + auto device = Graphics::GraphicsDevice::DefaultDevice; + bool hardwareRayTracing = device->support.hardwareRayTracing; + bool bindless = device->support.bindless; + + AE_ASSERT(data.indexCount > 0 && "There is no data in this mesh"); + + if (data.indexCount == 0 || !bindless) return; + + data.gpuTriangles.clear(); + data.gpuBvhNodes.shrink_to_fit(); + + triangleBuffer.Reset(); + if (!hardwareRayTracing) { + blasNodeBuffer.Reset(); + bvhTriangleBuffer.Reset(); + } + else { + triangleOffsetBuffer.Reset(); + } + + } + bool Mesh::IsBVHBuilt() const { return isBvhBuilt; diff --git a/src/engine/mesh/Mesh.h b/src/engine/mesh/Mesh.h index 35a496fae..ca380072c 100644 --- a/src/engine/mesh/Mesh.h +++ b/src/engine/mesh/Mesh.h @@ -64,6 +64,7 @@ namespace Atlas { */ void BuildBVH(bool parallelBuild = true); + void ClearBVH(); bool IsBVHBuilt() const; @@ -93,6 +94,7 @@ namespace Atlas { bool cullBackFaces = true; bool depthTest = true; + bool rayTrace = true; bool castShadow = true; @@ -105,6 +107,7 @@ namespace Atlas { float distanceCulling = 10000.0f; float shadowDistanceCulling = 10000.0f; + float rayTraceDistanceCulling = 10000.0f; float impostorDistance = 300.0f; float impostorShadowDistance = 100.0f; diff --git a/src/engine/mesh/MeshSerializer.cpp b/src/engine/mesh/MeshSerializer.cpp index b422aa906..b07a5189c 100644 --- a/src/engine/mesh/MeshSerializer.cpp +++ b/src/engine/mesh/MeshSerializer.cpp @@ -14,6 +14,7 @@ namespace Atlas::Mesh { {"mobility", mobility}, {"usage", usage}, {"cullBackFaces", p.cullBackFaces}, + {"rayTrace", p.rayTrace}, {"castShadow", p.castShadow}, {"vegetation", p.vegetation}, {"windNoiseTextureLod", p.windNoiseTextureLod}, @@ -22,6 +23,7 @@ namespace Atlas::Mesh { {"allowedShadowCascades", p.allowedShadowCascades}, {"distanceCulling", p.distanceCulling}, {"shadowDistanceCulling", p.shadowDistanceCulling}, + {"rayTraceDistanceCulling", p.rayTraceDistanceCulling}, {"impostorDistance", p.impostorDistance}, {"impostorShadowDistance", p.impostorShadowDistance}, {"invertUVs", p.invertUVs}, @@ -51,6 +53,9 @@ namespace Atlas::Mesh { j.at("invertUVs").get_to(p.invertUVs); j.at("data").get_to(p.data); + try_get_json(j, "rayTrace", p.rayTrace); + try_get_json(j, "rayTraceDistanceCulling", p.rayTraceDistanceCulling); + p.mobility = static_cast(mobility); p.usage = static_cast(usage); diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index 1949c0126..539c9b721 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace Atlas { namespace RayTracing { @@ -36,18 +38,18 @@ namespace Atlas { if (!device->swapChain->isComplete) return; if (!subset.Any()) return; - auto sceneState = &scene->renderState; + auto renderState = &scene->renderState; blases.clear(); auto meshes = scene->GetMeshes(); int32_t meshCount = 0; - JobSystem::Wait(sceneState->bindlessMeshMapUpdateJob); + JobSystem::Wait(renderState->bindlessMeshMapUpdateJob); for (auto& mesh : meshes) { // Only need to check for this, since that means that the BVH was built and the mesh is loaded - if (!sceneState->meshIdToBindlessIdx.contains(mesh.GetID())) + if (!renderState->meshIdToBindlessIdx.contains(mesh.GetID())) continue; if (!meshInfos.contains(mesh.GetID())) { @@ -56,7 +58,8 @@ namespace Atlas { } auto &meshInfo = meshInfos[mesh.GetID()]; - meshInfo.offset = int32_t(sceneState->meshIdToBindlessIdx[mesh.GetID()]); + meshInfo.offset = int32_t(renderState->meshIdToBindlessIdx[mesh.GetID()]); + meshInfo.cullingDistanceSqr = mesh->rayTraceDistanceCulling * mesh->rayTraceDistanceCulling; // Some extra path for hardware raytracing, don't want to do work twice if (hardwareRayTracing) { @@ -86,19 +89,33 @@ namespace Atlas { actorAABBs.clear(); lastMatrices.clear(); - JobSystem::Wait(sceneState->bindlessTextureMapUpdateJob); + JobSystem::Wait(renderState->bindlessTextureMapUpdateJob); UpdateMaterials(); + JobSystem::Wait(renderState->mainCameraSignal, JobPriority::High); + + vec3 cameraLocation; + auto hasCamera = scene->HasMainCamera(); + if (hasCamera) { + auto& camera = scene->GetMainCamera(); + cameraLocation = camera.GetLocation(); + } + for (auto entity : subset) { const auto& [meshComponent, transformComponent] = subset.Get(entity); - if (!sceneState->meshIdToBindlessIdx.contains(meshComponent.mesh.GetID())) + if (!renderState->meshIdToBindlessIdx.contains(meshComponent.mesh.GetID())) continue; - actorAABBs.push_back(meshComponent.aabb); auto &meshInfo = meshInfos[meshComponent.mesh.GetID()]; + auto distSqd = glm::distance2( + vec3(transformComponent.globalMatrix[3]), + cameraLocation); + if (hasCamera && distSqd > meshInfo.cullingDistanceSqr) + continue; + actorAABBs.push_back(meshComponent.aabb); auto inverseMatrix = mat3x4(glm::transpose(transformComponent.inverseGlobalMatrix)); uint32_t mask = InstanceCullMasks::MaskAll; diff --git a/src/engine/raytracing/RayTracingWorld.h b/src/engine/raytracing/RayTracingWorld.h index bbc65e2fe..7b12f65d7 100644 --- a/src/engine/raytracing/RayTracingWorld.h +++ b/src/engine/raytracing/RayTracingWorld.h @@ -53,6 +53,8 @@ namespace Atlas { int32_t offset = 0; int32_t materialOffset = 0; + float cullingDistanceSqr = 0.0f; + int32_t idx = 0; std::vector triangleLights; diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 85c571195..e6cb7c688 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -285,6 +285,8 @@ namespace Atlas { lightComponent.Update(transformComponent); } + renderState.mainCameraSignal.Reset(); + #ifdef AE_BINDLESS auto rayTracingSubset = GetSubset(); JobSystem::Execute(renderState.rayTracingWorldUpdateJob, [this, rayTracingSubset](JobData&) { @@ -350,6 +352,8 @@ namespace Atlas { } } + renderState.mainCameraSignal.Release(); + AE_ASSERT(mainCameraEntity.IsValid() && "Couldn't find main camera component"); if (!mainCameraEntity.IsValid()) diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index 914f6a903..cbdb04d8a 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -63,6 +63,8 @@ namespace Atlas::Scene { std::unordered_map meshIdToBindlessIdx; std::vector lightEntities; + JobSemaphore mainCameraSignal; + JobGroup materialUpdateJob{ JobPriority::High }; JobGroup rayTracingWorldUpdateJob{ JobPriority::High }; JobGroup bindlessMeshMapUpdateJob{ JobPriority::High }; diff --git a/src/engine/scripting/bindings/GraphicsBindings.cpp b/src/engine/scripting/bindings/GraphicsBindings.cpp index 20f1944f5..4cc34949e 100644 --- a/src/engine/scripting/bindings/GraphicsBindings.cpp +++ b/src/engine/scripting/bindings/GraphicsBindings.cpp @@ -12,27 +12,47 @@ namespace Atlas::Scripting::Bindings { ns->new_usertype("Texture2D", "width", &Texture::Texture2D::width, "height", &Texture::Texture2D::height, - "channels", &Texture::Texture2D::channels + "channels", &Texture::Texture2D::channels, + "IsValid", &Texture::Texture2D::IsValid, + "Reset", &Texture::Texture2D::Reset, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData ); ns->new_usertype("Texture2DArray", "width", &Texture::Texture2DArray::width, "height", &Texture::Texture2DArray::height, "depth", &Texture::Texture2DArray::depth, - "channels", &Texture::Texture2DArray::channels + "channels", &Texture::Texture2DArray::channels, + "IsValid", &Texture::Texture2D::IsValid, + "Reset", &Texture::Texture2D::Reset, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData ); ns->new_usertype("Texture3D", "width", &Texture::Texture3D::width, "height", &Texture::Texture3D::height, "depth", &Texture::Texture3D::depth, - "channels", &Texture::Texture3D::channels + "channels", &Texture::Texture3D::channels, + "IsValid", &Texture::Texture2D::IsValid, + "Reset", &Texture::Texture2D::Reset, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData ); ns->new_usertype("Cubemap", "width", &Texture::Cubemap::width, "height", &Texture::Cubemap::height, - "channels", &Texture::Cubemap::channels + "channels", &Texture::Cubemap::channels, + "IsValid", &Texture::Texture2D::IsValid, + "Reset", &Texture::Texture2D::Reset, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData, + "GetData", &Texture::Texture2D::GetData ); } From 8eee3bd18778530a2d51b72b71152892b8076142 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 5 Sep 2024 00:25:47 +0200 Subject: [PATCH 18/66] Fixed more issues --- .github/workflows/build.yml | 2 +- data/shader/deferred/indirect.csh | 5 +++ src/demo/App.cpp | 18 +-------- src/editor/App.cpp | 26 ------------ src/editor/DataCreator.cpp | 1 + src/engine/Engine.cpp | 2 + src/engine/jobsystem/JobSemaphore.h | 2 +- src/engine/jobsystem/JobSystem.cpp | 4 +- src/engine/jobsystem/JobSystem.h | 2 +- src/engine/loader/ModelImporter.cpp | 40 +++++++++++++++---- src/engine/loader/ModelImporter.h | 2 + src/engine/mesh/Mesh.cpp | 3 +- src/engine/raytracing/RayTracingManager.cpp | 37 +++++++++++++++++ src/engine/raytracing/RayTracingManager.h | 18 +++++++++ src/engine/renderer/IndirectLightRenderer.cpp | 1 + src/engine/renderer/MainRenderer.cpp | 3 ++ src/engine/scene/SceneRenderState.cpp | 3 ++ src/engine/scene/SceneRenderState.h | 2 +- .../scripting/bindings/GraphicsBindings.cpp | 22 +++++----- .../scripting/bindings/MeshBindings.cpp | 9 ++++- .../scripting/bindings/ResourceBindings.h | 3 +- src/tests/App.cpp | 22 ---------- 22 files changed, 135 insertions(+), 92 deletions(-) create mode 100644 src/engine/raytracing/RayTracingManager.cpp create mode 100644 src/engine/raytracing/RayTracingManager.h diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65ba92def..7919775a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -175,7 +175,7 @@ jobs: !**/CMakeFiles linux-build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 name: Build on Linux # Run both builds in parallel and don't cancel if one fails strategy: diff --git a/data/shader/deferred/indirect.csh b/data/shader/deferred/indirect.csh index eeb5aec3f..b1a1b5ffe 100644 --- a/data/shader/deferred/indirect.csh +++ b/data/shader/deferred/indirect.csh @@ -235,8 +235,13 @@ void main() { #else #ifdef DDGI vec3 prefilteredDiffuse = textureLod(diffuseProbe, worldNormal, 0).rgb; +#ifdef DDGI_SCROLL vec4 prefilteredDiffuseLocal = ddgiData.volumeEnabled > 0 ? GetLocalIrradianceInterpolated(worldPosition, worldView, worldNormal, geometryWorldNormal, prefilteredDiffuse) : vec4(0.0, 0.0, 0.0, 1.0); +#else + vec4 prefilteredDiffuseLocal = ddgiData.volumeEnabled > 0 ? + GetLocalIrradiance(worldPosition, worldView, worldNormal, geometryWorldNormal) : vec4(0.0, 0.0, 0.0, 1.0); +#endif prefilteredDiffuseLocal = IsInsideVolume(worldPosition) ? prefilteredDiffuseLocal : vec4(0.0, 0.0, 0.0, 1.0); prefilteredDiffuse = prefilteredDiffuseLocal.rgb + prefilteredDiffuse * prefilteredDiffuseLocal.a; vec3 indirectDiffuse = prefilteredDiffuse * EvaluateIndirectDiffuseBRDF(surface) * ddgiData.volumeStrength; diff --git a/src/demo/App.cpp b/src/demo/App.cpp index c0f5b32ad..7c4a4cbbc 100644 --- a/src/demo/App.cpp +++ b/src/demo/App.cpp @@ -904,6 +904,7 @@ bool App::LoadScene() { else if (sceneSelection == FOREST) { auto otherScene = Atlas::Loader::ModelImporter::ImportScene("forest/forest.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5); otherScene->Timestep(1.0f); + otherScene->Update(); CopyActors(otherScene); @@ -921,6 +922,7 @@ bool App::LoadScene() { else if (sceneSelection == EMERALDSQUARE) { auto otherScene = Atlas::Loader::ModelImporter::ImportScene("emeraldsquare/square.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5); otherScene->Timestep(1.0f); + otherScene->Update(); CopyActors(otherScene); @@ -1082,22 +1084,6 @@ void App::CheckLoadScene() { graphicsDevice->WaitForPreviousFrameSubmission(); - static Atlas::JobGroup buildBvhGroup; - - auto buildRTStructure = [&](Atlas::JobData) { - auto sceneMeshes = scene->GetMeshes(); - - for (const auto& mesh : sceneMeshes) { - - if (mesh->IsBVHBuilt()) continue; - - Atlas::JobSystem::Execute(buildBvhGroup, [mesh](Atlas::JobData&) { mesh->BuildBVH(); }); - - } - }; - - Atlas::JobSystem::Execute(buildBvhGroup, buildRTStructure); - auto sceneAABB = Atlas::Volume::AABB(glm::vec3(std::numeric_limits::max()), glm::vec3(-std::numeric_limits::max())); diff --git a/src/editor/App.cpp b/src/editor/App.cpp index f3493f385..13770525a 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -199,32 +199,6 @@ namespace Atlas::Editor { } ImGuizmo::Enable(activeSceneWindow->needGuizmoEnabled); - - graphicsDevice->WaitForPreviousFrameSubmission(); - - -#ifdef AE_BINDLESS - // This crashes when we start with path tracing and do the bvh build async - // Launch BVH builds asynchronously - auto buildRTStructure = [&](JobData) { - auto sceneMeshes = ResourceManager::GetResources(); - - for (const auto& mesh : sceneMeshes) { - if (!mesh.IsLoaded()) - continue; - if (mesh->IsBVHBuilt()) - continue; - JobSystem::Execute(bvhBuilderGroup, [mesh](JobData&) { - mesh->BuildBVH(false); - }); - } - }; - - if (bvhBuilderGroup.HasFinished()) { - JobSystem::Execute(bvhBuilderGroup, buildRTStructure); - return; - } -#endif } diff --git a/src/editor/DataCreator.cpp b/src/editor/DataCreator.cpp index e39ffa5fd..a92b4718d 100644 --- a/src/editor/DataCreator.cpp +++ b/src/editor/DataCreator.cpp @@ -131,6 +131,7 @@ namespace Atlas::Editor { scene->postProcessing.fsr2 = true; scene->Timestep(1.0f); + scene->Update(); min = glm::vec3(std::numeric_limits::max()); max = glm::vec3(-std::numeric_limits::max()); diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 8b22c8185..939017d17 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -9,6 +9,7 @@ #include "texture/Texture.h" #include "input/KeyboardMap.h" #include "events/EventManager.h" +#include "raytracing/RayTracingManager.h" #include "jobsystem/JobSystem.h" #include "graphics/ShaderCompiler.h" @@ -121,6 +122,7 @@ namespace Atlas { PipelineManager::Update(); Audio::AudioManager::Update(); Physics::ShapesManager::Update(); + RayTracing::RayTracingManager::Update(); } diff --git a/src/engine/jobsystem/JobSemaphore.h b/src/engine/jobsystem/JobSemaphore.h index 9de3401cd..c6a5c6e45 100644 --- a/src/engine/jobsystem/JobSemaphore.h +++ b/src/engine/jobsystem/JobSemaphore.h @@ -4,7 +4,7 @@ namespace Atlas { - class JobSemaphore { + class JobSignal { public: inline void Reset() { counter.store(0); } diff --git a/src/engine/jobsystem/JobSystem.cpp b/src/engine/jobsystem/JobSystem.cpp index 61e5cb429..308088c08 100644 --- a/src/engine/jobsystem/JobSystem.cpp +++ b/src/engine/jobsystem/JobSystem.cpp @@ -118,11 +118,11 @@ namespace Atlas { } - void JobSystem::Wait(JobSemaphore& semaphore, JobPriority priority) { + void JobSystem::Wait(JobSignal& signal, JobPriority priority) { auto& priorityPool = priorityPools[static_cast(priority)]; - while (!semaphore.TryAquire()) { + while (!signal.TryAquire()) { auto& worker = priorityPool.GetNextWorker(); priorityPool.Work(worker.workerId); } diff --git a/src/engine/jobsystem/JobSystem.h b/src/engine/jobsystem/JobSystem.h index a841f6e0d..6b450a717 100644 --- a/src/engine/jobsystem/JobSystem.h +++ b/src/engine/jobsystem/JobSystem.h @@ -34,7 +34,7 @@ namespace Atlas { static void ExecuteMultiple(JobGroup& group, int32_t count, std::function func, void* userData = nullptr); - static void Wait(JobSemaphore& semaphore, JobPriority priority); + static void Wait(JobSignal& signal, JobPriority priority); static void Wait(JobGroup& group); diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index d5ffeb3bd..8312b338d 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -699,8 +699,10 @@ namespace Atlas { image->ExpandToChannelCount(4, 255); images.Add(MaterialImageType::BaseColor, path, image); - if (!images.Contains(MaterialImageType::Opacity, path) && opacityImage != nullptr) - images.Add(MaterialImageType::Opacity, path, opacityImage); + if (!images.Contains(MaterialImageType::Opacity, path) && opacityImage != nullptr) { + if (IsImageValid(opacityImage)) + images.Add(MaterialImageType::Opacity, path, opacityImage); + } } } if (material->GetTextureCount(aiTextureType_OPACITY) > 0) { @@ -709,7 +711,8 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (!images.Contains(MaterialImageType::Opacity, path)) { auto image = ImageLoader::LoadImage(path, false, 1, maxTextureResolution); - images.Add(MaterialImageType::Opacity, path, image); + if (IsImageValid(image)) + images.Add(MaterialImageType::Opacity, path, image); } } if ((material->GetTextureCount(aiTextureType_NORMALS) > 0 || @@ -734,7 +737,8 @@ namespace Atlas { } image->ExpandToChannelCount(4, 255); - images.Add(MaterialImageType::Normal, path, image); + if (IsImageValid(image)) + images.Add(MaterialImageType::Normal, path, image); if (!images.Contains(MaterialImageType::Displacement, path) && displacementImage != nullptr) images.Add(MaterialImageType::Displacement, path, displacementImage); } @@ -754,9 +758,11 @@ namespace Atlas { image = image->GetChannelImage(1, 1); } - images.Add(MaterialImageType::Roughness, path, image); + if (IsImageValid(image)) + images.Add(MaterialImageType::Roughness, path, image); if (!images.Contains(MaterialImageType::Metallic, path) && metallicImage != nullptr) - images.Add(MaterialImageType::Metallic, path, metallicImage); + if (IsImageValid(metallicImage)) + images.Add(MaterialImageType::Metallic, path, metallicImage); } } if (material->GetTextureCount(aiTextureType_METALNESS) > 0) { @@ -765,7 +771,8 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (!images.Contains(MaterialImageType::Metallic, path)) { auto image = ImageLoader::LoadImage(path, false, 1, maxTextureResolution); - images.Add(MaterialImageType::Metallic, path, image); + if (IsImageValid(image)) + images.Add(MaterialImageType::Metallic, path, image); } } if (material->GetTextureCount(aiTextureType_SPECULAR) > 0) { @@ -774,7 +781,8 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (!images.Contains(MaterialImageType::Metallic, path)) { auto image = ImageLoader::LoadImage(path, false, 1, maxTextureResolution); - images.Add(MaterialImageType::Metallic, path, image); + if (IsImageValid(image)) + images.Add(MaterialImageType::Metallic, path, image); } } if (material->GetTextureCount(aiTextureType_HEIGHT) > 0 && !state.isObj && hasTangents) { @@ -878,6 +886,22 @@ namespace Atlas { } + bool ModelImporter::IsImageValid(Ref>& image) { + + auto& data = image->GetData(); + + if (data.empty()) + return false; + + bool invalidImage = true; + for (int32_t i = image->channels; i < data.size(); i += image->channels) { + for (int32_t j = 0; j < image->channels; j++) + invalidImage &= data[(i - image->channels) + j] == data[i + j]; + } + + return !invalidImage; + } + } } \ No newline at end of file diff --git a/src/engine/loader/ModelImporter.h b/src/engine/loader/ModelImporter.h index cfd7707ae..2910e7cdf 100644 --- a/src/engine/loader/ModelImporter.h +++ b/src/engine/loader/ModelImporter.h @@ -139,6 +139,8 @@ namespace Atlas { static std::string GetMaterialImageImportPath(const ImporterState& state, MaterialImageType type, const std::string& filename); + static bool IsImageValid(Ref>& image); + template static Ref> ApplySobelFilter(const Ref>& image, const float strength = 1.0f) { diff --git a/src/engine/mesh/Mesh.cpp b/src/engine/mesh/Mesh.cpp index 147b4122e..6d8814b86 100644 --- a/src/engine/mesh/Mesh.cpp +++ b/src/engine/mesh/Mesh.cpp @@ -148,6 +148,7 @@ namespace Atlas { void Mesh::ClearBVH() { + // This whole operation can only be done when no ray tracing jobs or bindless updates are running isBvhBuilt = false; auto device = Graphics::GraphicsDevice::DefaultDevice; @@ -159,7 +160,7 @@ namespace Atlas { if (data.indexCount == 0 || !bindless) return; data.gpuTriangles.clear(); - data.gpuBvhNodes.shrink_to_fit(); + data.gpuTriangles.shrink_to_fit(); triangleBuffer.Reset(); if (!hardwareRayTracing) { diff --git a/src/engine/raytracing/RayTracingManager.cpp b/src/engine/raytracing/RayTracingManager.cpp new file mode 100644 index 000000000..a21150ebe --- /dev/null +++ b/src/engine/raytracing/RayTracingManager.cpp @@ -0,0 +1,37 @@ +#include "RayTracingManager.h" + +#include "graphics/GraphicsDevice.h" +#include "resource/ResourceManager.h" +#include "mesh/Mesh.h" + +namespace Atlas::RayTracing { + + JobGroup RayTracingManager::bvhUpdateGroup; + + void RayTracingManager::Update() { + +#ifdef AE_BINDLESS + // This crashes when we start with path tracing and do the bvh build async + // Launch BVH builds asynchronously + auto buildRTStructure = [&](JobData) { + auto sceneMeshes = ResourceManager::GetResources(); + + for (const auto& mesh : sceneMeshes) { + if (!mesh.IsLoaded()) + continue; + if (mesh->IsBVHBuilt() || !mesh->rayTrace) + continue; + JobSystem::Execute(bvhUpdateGroup, [mesh](JobData&) { + mesh->BuildBVH(false); + }); + } + }; + + if (bvhUpdateGroup.HasFinished()) { + JobSystem::Execute(bvhUpdateGroup, buildRTStructure); + } +#endif + + } + +} \ No newline at end of file diff --git a/src/engine/raytracing/RayTracingManager.h b/src/engine/raytracing/RayTracingManager.h new file mode 100644 index 000000000..6c902a631 --- /dev/null +++ b/src/engine/raytracing/RayTracingManager.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../System.h" +#include "jobsystem/JobGroup.h" + +namespace Atlas::RayTracing { + + class RayTracingManager { + + public: + static void Update(); + + private: + static JobGroup bvhUpdateGroup; + + }; + +} \ No newline at end of file diff --git a/src/engine/renderer/IndirectLightRenderer.cpp b/src/engine/renderer/IndirectLightRenderer.cpp index d19c38e2e..b7edbf123 100644 --- a/src/engine/renderer/IndirectLightRenderer.cpp +++ b/src/engine/renderer/IndirectLightRenderer.cpp @@ -36,6 +36,7 @@ namespace Atlas { pipelineConfig.ManageMacro("RTGI", rtgiEnabled); pipelineConfig.ManageMacro("DDGI", ddgiEnabled); + pipelineConfig.ManageMacro("DDGI_SCROLL", ddgiEnabled && volume->scroll); pipelineConfig.ManageMacro("DDGI_VISIBILITY", ddgiVisibility); pipelineConfig.ManageMacro("REFLECTION", reflectionEnabled); pipelineConfig.ManageMacro("AO", aoEnabled); diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index d5a508d7d..024acaefd 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -496,6 +496,9 @@ namespace Atlas { device->SubmitCommandList(commandList); + renderState->WaitForAsyncWorkCompletion(); + renderState->renderList.Clear(); + } void MainRenderer::RenderPrimitiveBatch(Ref viewport, Ref target, diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index f6b63bbc7..eda00c066 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -482,6 +482,9 @@ namespace Atlas::Scene { void SceneRenderState::WaitForAsyncWorkCompletion() { + // Assume scene work was done + mainCameraSignal.Release(); + JobSystem::Wait(bindlessMeshMapUpdateJob); JobSystem::Wait(bindlessTextureMapUpdateJob); JobSystem::Wait(bindlessOtherTextureMapUpdateJob); diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index cbdb04d8a..522c8b829 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -63,7 +63,7 @@ namespace Atlas::Scene { std::unordered_map meshIdToBindlessIdx; std::vector lightEntities; - JobSemaphore mainCameraSignal; + JobSignal mainCameraSignal; JobGroup materialUpdateJob{ JobPriority::High }; JobGroup rayTracingWorldUpdateJob{ JobPriority::High }; diff --git a/src/engine/scripting/bindings/GraphicsBindings.cpp b/src/engine/scripting/bindings/GraphicsBindings.cpp index 4cc34949e..aa7a4b6fc 100644 --- a/src/engine/scripting/bindings/GraphicsBindings.cpp +++ b/src/engine/scripting/bindings/GraphicsBindings.cpp @@ -15,9 +15,9 @@ namespace Atlas::Scripting::Bindings { "channels", &Texture::Texture2D::channels, "IsValid", &Texture::Texture2D::IsValid, "Reset", &Texture::Texture2D::Reset, - "GetData", &Texture::Texture2D::GetData, - "GetData", &Texture::Texture2D::GetData, - "GetData", &Texture::Texture2D::GetData + "GetDataUInt8", &Texture::Texture2D::GetData, + "GetDataFloat16", &Texture::Texture2D::GetData, + "GetDataFloat32", &Texture::Texture2D::GetData ); ns->new_usertype("Texture2DArray", @@ -27,9 +27,9 @@ namespace Atlas::Scripting::Bindings { "channels", &Texture::Texture2DArray::channels, "IsValid", &Texture::Texture2D::IsValid, "Reset", &Texture::Texture2D::Reset, - "GetData", &Texture::Texture2D::GetData, - "GetData", &Texture::Texture2D::GetData, - "GetData", &Texture::Texture2D::GetData + "GetDataUInt8", &Texture::Texture2D::GetData, + "GetDataFloat16", &Texture::Texture2D::GetData, + "GetDataFloat32", &Texture::Texture2D::GetData ); ns->new_usertype("Texture3D", @@ -39,8 +39,8 @@ namespace Atlas::Scripting::Bindings { "channels", &Texture::Texture3D::channels, "IsValid", &Texture::Texture2D::IsValid, "Reset", &Texture::Texture2D::Reset, - "GetData", &Texture::Texture2D::GetData, - "GetData", &Texture::Texture2D::GetData, + "GetDataUInt8", &Texture::Texture2D::GetData, + "GetDataFloat16", &Texture::Texture2D::GetData, "GetData", &Texture::Texture2D::GetData ); @@ -50,9 +50,9 @@ namespace Atlas::Scripting::Bindings { "channels", &Texture::Cubemap::channels, "IsValid", &Texture::Texture2D::IsValid, "Reset", &Texture::Texture2D::Reset, - "GetData", &Texture::Texture2D::GetData, - "GetData", &Texture::Texture2D::GetData, - "GetData", &Texture::Texture2D::GetData + "GetDataUInt8", &Texture::Texture2D::GetData, + "GetDataFloat16", &Texture::Texture2D::GetData, + "GetDataFloat32", &Texture::Texture2D::GetData ); } diff --git a/src/engine/scripting/bindings/MeshBindings.cpp b/src/engine/scripting/bindings/MeshBindings.cpp index 092eaf512..0d03afd8f 100644 --- a/src/engine/scripting/bindings/MeshBindings.cpp +++ b/src/engine/scripting/bindings/MeshBindings.cpp @@ -73,7 +73,14 @@ namespace Atlas::Scripting::Bindings { "displacementScale", &Material::displacementScale, "tiling", &Material::tiling, "twoSided", &Material::twoSided, - "vertexColors", &Material::vertexColors + "vertexColors", &Material::vertexColors, + "baseColorMap", &Material::baseColorMap, + "opacityMap", &Material::opacityMap, + "normalMap", &Material::normalMap, + "roughnessMap", &Material::roughnessMap, + "metalnessMap", &Material::metalnessMap, + "aoMap", &Material::aoMap, + "displacementMap", &Material::displacementMap ); } diff --git a/src/engine/scripting/bindings/ResourceBindings.h b/src/engine/scripting/bindings/ResourceBindings.h index 0225addbc..304d415af 100644 --- a/src/engine/scripting/bindings/ResourceBindings.h +++ b/src/engine/scripting/bindings/ResourceBindings.h @@ -15,7 +15,8 @@ namespace Atlas::Scripting::Bindings { "IsValid", &ResourceHandle::IsValid, "IsLoaded", &ResourceHandle::IsLoaded, "WaitForLoad", &ResourceHandle::WaitForLoad, - "GetID", &ResourceHandle::GetID + "GetID", &ResourceHandle::GetID, + "Reset", &ResourceHandle::Reset ); type.set_function("GetResource", sol::resolve>&(void)>(&ResourceHandle::GetResource)); diff --git a/src/tests/App.cpp b/src/tests/App.cpp index 375a97e03..9bce3d9ca 100644 --- a/src/tests/App.cpp +++ b/src/tests/App.cpp @@ -362,28 +362,6 @@ void App::CheckLoadScene() { if (!scene->IsFullyLoaded() || loadingComplete) return; - static Atlas::JobGroup buildBvhGroup; - static bool groupStarted = false; - - auto buildRTStructure = [&](Atlas::JobData) { - auto sceneMeshes = scene->GetMeshes(); - - for (const auto& mesh : sceneMeshes) { - - Atlas::JobSystem::Execute(buildBvhGroup, [mesh](Atlas::JobData&) { mesh->BuildBVH(); }); - - } - }; - - if (!groupStarted) { - Atlas::JobSystem::Execute(buildBvhGroup, buildRTStructure); - groupStarted = true; - return; - } - - if (!buildBvhGroup.HasFinished()) - return; - auto sceneAABB = Atlas::Volume::AABB(glm::vec3(std::numeric_limits::max()), glm::vec3(-std::numeric_limits::max())); From f5ee730044b57259e955e9c7f25e3ec965a074f0 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 5 Sep 2024 23:15:09 +0200 Subject: [PATCH 19/66] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7919775a1..7c247b608 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -225,7 +225,7 @@ jobs: # Add additional scripting steps here run: | sudo apt-get update - sudo apt-get install libgl1-mesa-dev + sudo apt-get install libgl1-mesa-dev autoconf automake libtool pkg-config cd ${{ github.workspace }} ${{ github.workspace }}/vcpkg/vcpkg install --clean-after-build --triplet=x64-linux rm -r vcpkg_installed From 91e7f94947e3f303695f042fce76e58bfda8000b Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 14:38:05 +0200 Subject: [PATCH 20/66] Fix MacOS build issue --- libs/fsr2/ffx-fsr2-api/ffx_fsr2.cpp | 12 ++++++------ src/editor/ContentDiscovery.cpp | 1 + src/editor/ui/popups/ResourceSelectionPopup.h | 2 ++ src/engine/ecs/Storage.cpp | 2 ++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libs/fsr2/ffx-fsr2-api/ffx_fsr2.cpp b/libs/fsr2/ffx-fsr2-api/ffx_fsr2.cpp index 220900983..b1705035f 100644 --- a/libs/fsr2/ffx-fsr2-api/ffx_fsr2.cpp +++ b/libs/fsr2/ffx-fsr2-api/ffx_fsr2.cpp @@ -338,12 +338,12 @@ static FfxErrorCode patchResourceBindings(FfxPipelineState* inoutPipeline) for (uint32_t srvIndex = 0; srvIndex < inoutPipeline->srvCount; ++srvIndex) { int32_t mapIndex = 0; - for (mapIndex = 0; mapIndex < std::size(srvResourceBindingTable); ++mapIndex) + for (mapIndex = 0; mapIndex < std::ranges::size(srvResourceBindingTable); ++mapIndex) { if (0 == wcscmp(srvResourceBindingTable[mapIndex].name, inoutPipeline->srvResourceBindings[srvIndex].name)) break; } - if (mapIndex == std::size(srvResourceBindingTable)) + if (mapIndex == std::ranges::size(srvResourceBindingTable)) return FFX_ERROR_INVALID_ARGUMENT; inoutPipeline->srvResourceBindings[srvIndex].resourceIdentifier = srvResourceBindingTable[mapIndex].index; @@ -352,12 +352,12 @@ static FfxErrorCode patchResourceBindings(FfxPipelineState* inoutPipeline) for (uint32_t uavIndex = 0; uavIndex < inoutPipeline->uavCount; ++uavIndex) { int32_t mapIndex = 0; - for (mapIndex = 0; mapIndex < std::size(uavResourceBindingTable); ++mapIndex) + for (mapIndex = 0; mapIndex < std::ranges::size(uavResourceBindingTable); ++mapIndex) { if (0 == wcscmp(uavResourceBindingTable[mapIndex].name, inoutPipeline->uavResourceBindings[uavIndex].name)) break; } - if (mapIndex == std::size(uavResourceBindingTable)) + if (mapIndex == std::ranges::size(uavResourceBindingTable)) return FFX_ERROR_INVALID_ARGUMENT; inoutPipeline->uavResourceBindings[uavIndex].resourceIdentifier = uavResourceBindingTable[mapIndex].index; @@ -366,12 +366,12 @@ static FfxErrorCode patchResourceBindings(FfxPipelineState* inoutPipeline) for (uint32_t cbIndex = 0; cbIndex < inoutPipeline->constCount; ++cbIndex) { int32_t mapIndex = 0; - for (mapIndex = 0; mapIndex < std::size(cbResourceBindingTable); ++mapIndex) + for (mapIndex = 0; mapIndex < std::ranges::size(cbResourceBindingTable); ++mapIndex) { if (0 == wcscmp(cbResourceBindingTable[mapIndex].name, inoutPipeline->cbResourceBindings[cbIndex].name)) break; } - if (mapIndex == std::size(cbResourceBindingTable)) + if (mapIndex == std::ranges::size(cbResourceBindingTable)) return FFX_ERROR_INVALID_ARGUMENT; inoutPipeline->cbResourceBindings[cbIndex].resourceIdentifier = cbResourceBindingTable[mapIndex].index; diff --git a/src/editor/ContentDiscovery.cpp b/src/editor/ContentDiscovery.cpp index e31528388..8f5527b4e 100644 --- a/src/editor/ContentDiscovery.cpp +++ b/src/editor/ContentDiscovery.cpp @@ -5,6 +5,7 @@ #include "Log.h" #include +#include namespace Atlas::Editor { diff --git a/src/editor/ui/popups/ResourceSelectionPopup.h b/src/editor/ui/popups/ResourceSelectionPopup.h index f9f359698..13e798fb1 100644 --- a/src/editor/ui/popups/ResourceSelectionPopup.h +++ b/src/editor/ui/popups/ResourceSelectionPopup.h @@ -7,6 +7,8 @@ #include #include +#include + namespace Atlas::Editor::UI { class ResourceSelectionPopup : public Popup { diff --git a/src/engine/ecs/Storage.cpp b/src/engine/ecs/Storage.cpp index 562a29e42..5cccddac0 100644 --- a/src/engine/ecs/Storage.cpp +++ b/src/engine/ecs/Storage.cpp @@ -1,5 +1,7 @@ #include "Storage.h" +#include + namespace Atlas { namespace ECS { From a99d85705d2cc7f74b5a799f8bb605807463f3f4 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 15:08:58 +0200 Subject: [PATCH 21/66] Trying to fix it finally --- .github/workflows/build.yml | 5 +++-- src/engine/Clock.cpp | 1 + src/engine/Engine.cpp | 2 +- src/engine/common/Image.h | 2 +- src/engine/lighting/IrradianceVolume.cpp | 2 ++ src/engine/tools/TerrainTool.cpp | 1 + 6 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c247b608..5b2d825c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -224,8 +224,9 @@ jobs: shell: bash # Add additional scripting steps here run: | - sudo apt-get update - sudo apt-get install libgl1-mesa-dev autoconf automake libtool pkg-config + sudo apt update + sudo apt upgrade + sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config cd ${{ github.workspace }} ${{ github.workspace }}/vcpkg/vcpkg install --clean-after-build --triplet=x64-linux rm -r vcpkg_installed diff --git a/src/engine/Clock.cpp b/src/engine/Clock.cpp index b965f2d52..4320a75e0 100644 --- a/src/engine/Clock.cpp +++ b/src/engine/Clock.cpp @@ -1,6 +1,7 @@ #include "Clock.h" #include +#include #include diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 939017d17..ca1dcf567 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -53,7 +53,7 @@ namespace Atlas { #ifdef AE_BUILDTYPE_DEBUG .enableValidationLayers = true, #else - .enableValidationLayers = false, + .enableValidationLayers = true, #endif .validationLayerSeverity = config.validationLayerSeverity, #ifndef AE_HEADLESS diff --git a/src/engine/common/Image.h b/src/engine/common/Image.h index 736818ab7..942c4a337 100644 --- a/src/engine/common/Image.h +++ b/src/engine/common/Image.h @@ -7,7 +7,7 @@ #include #include - +#include namespace Atlas { diff --git a/src/engine/lighting/IrradianceVolume.cpp b/src/engine/lighting/IrradianceVolume.cpp index 3ca0bf70e..621926e94 100644 --- a/src/engine/lighting/IrradianceVolume.cpp +++ b/src/engine/lighting/IrradianceVolume.cpp @@ -1,5 +1,7 @@ #include "IrradianceVolume.h" +#include + namespace Atlas { namespace Lighting { diff --git a/src/engine/tools/TerrainTool.cpp b/src/engine/tools/TerrainTool.cpp index 7634c340c..fb97d33f3 100644 --- a/src/engine/tools/TerrainTool.cpp +++ b/src/engine/tools/TerrainTool.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace Atlas { From 6a8822422774df84ecd2154f445e24c85ac7f690 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 15:48:21 +0200 Subject: [PATCH 22/66] Try to fix Linux build --- .github/workflows/build.yml | 5 ++--- src/engine/CMakeLists.txt | 16 ++++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b2d825c4..2ee7e7d01 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -175,7 +175,7 @@ jobs: !**/CMakeFiles linux-build: - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest name: Build on Linux # Run both builds in parallel and don't cancel if one fails strategy: @@ -225,8 +225,7 @@ jobs: # Add additional scripting steps here run: | sudo apt update - sudo apt upgrade - sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config + sudo apt install libgl1-mesa-dev gcc-14 g++-14 -y cd ${{ github.workspace }} ${{ github.workspace }}/vcpkg/vcpkg install --clean-after-build --triplet=x64-linux rm -r vcpkg_installed diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index 2688a2547..7e2c5e229 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -84,16 +84,20 @@ if(UNIX AND NOT APPLE AND NOT ANDROID) set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_OS_LINUX) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") - set (CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -ldl") - - set(CMAKE_SKIP_BUILD_RPATH FALSE) - set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - set(CMAKE_INSTALL_RPATH "./") - set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -ldl") set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static fsr2 volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator unofficial::joltphysics::Jolt unofficial::spirv-reflect SPIRV-Tools-opt glslang::SPIRV ${LUA_LIBRARIES} sol2) + + if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 14.0) + message("USe gcc14!") + set(ATLAS_ENGINE_LIBS ${ATLAS_ENGINE_LIBS} stdc++exp) + elseif(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 12.0) + message("USe gcc12!") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --enable-libstdcxx-backtrace=yes") + set(ATLAS_ENGINE_LIBS ${ATLAS_ENGINE_LIBS} stdc++_libbacktrace) + endif() endif() # Due to lua bindings we need more addressable functions (but not for clang) From 7064aef2eb07390b12e4095711afc542610b5d19 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 16:09:46 +0200 Subject: [PATCH 23/66] Still trying to fix Linux build issue --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ee7e7d01..873895f62 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -175,7 +175,7 @@ jobs: !**/CMakeFiles linux-build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 name: Build on Linux # Run both builds in parallel and don't cancel if one fails strategy: @@ -225,7 +225,8 @@ jobs: # Add additional scripting steps here run: | sudo apt update - sudo apt install libgl1-mesa-dev gcc-14 g++-14 -y + sudo apt upgrade + sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev -y cd ${{ github.workspace }} ${{ github.workspace }}/vcpkg/vcpkg install --clean-after-build --triplet=x64-linux rm -r vcpkg_installed From df29112917497a0c457621d734eca2f294c296e6 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 16:48:24 +0200 Subject: [PATCH 24/66] More --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 873895f62..45c4234a0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -226,7 +226,9 @@ jobs: run: | sudo apt update sudo apt upgrade - sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev -y + sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev g++-14 gcc-14 -y + gcc -v + g++ -v cd ${{ github.workspace }} ${{ github.workspace }}/vcpkg/vcpkg install --clean-after-build --triplet=x64-linux rm -r vcpkg_installed From ac7d5cb4c85891a611cbd62192792bffd16dfb05 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 17:03:26 +0200 Subject: [PATCH 25/66] Try even more --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 45c4234a0..11351fc1e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -227,6 +227,8 @@ jobs: sudo apt update sudo apt upgrade sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev g++-14 gcc-14 -y + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++14 14 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc14 14 gcc -v g++ -v cd ${{ github.workspace }} From 233b4b07aa94e23f5f2c729566cbd9fe7af068ee Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 17:06:52 +0200 Subject: [PATCH 26/66] More tests --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11351fc1e..2823e93a9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -227,6 +227,7 @@ jobs: sudo apt update sudo apt upgrade sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev g++-14 gcc-14 -y + sudo update-alternatives --config g++ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++14 14 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc14 14 gcc -v From f2c0502cbbad41982614cb705a85b033be745f79 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 17:12:11 +0200 Subject: [PATCH 27/66] Remove upgrade --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2823e93a9..d3d421034 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -225,7 +225,6 @@ jobs: # Add additional scripting steps here run: | sudo apt update - sudo apt upgrade sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev g++-14 gcc-14 -y sudo update-alternatives --config g++ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++14 14 From 6409b765d3ceafbec6085cfd490028dd0bc2c83f Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 17:22:52 +0200 Subject: [PATCH 28/66] Try some more --- .github/workflows/build.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d3d421034..d2fed15c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -226,9 +226,8 @@ jobs: run: | sudo apt update sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev g++-14 gcc-14 -y - sudo update-alternatives --config g++ - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++14 14 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc14 14 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 14 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 14 gcc -v g++ -v cd ${{ github.workspace }} From 56332e3206b6d2365575443ac692c0a2ff0435bb Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 17:47:49 +0200 Subject: [PATCH 29/66] Again --- .github/workflows/build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d2fed15c3..d2ff531ab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -226,13 +226,11 @@ jobs: run: | sudo apt update sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev g++-14 gcc-14 -y - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 14 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 14 - gcc -v - g++ -v cd ${{ github.workspace }} ${{ github.workspace }}/vcpkg/vcpkg install --clean-after-build --triplet=x64-linux rm -r vcpkg_installed + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 14 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 14 - name: Build swiftshader uses: ashutoshvarma/action-cmake-build@master From 2e01bc029c865393f10b9706af93aa92c41f03b3 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 18:42:38 +0200 Subject: [PATCH 30/66] Try with newer Jolt version --- .github/workflows/build.yml | 4 ++-- CMakeLists.txt | 2 +- src/engine/CMakeLists.txt | 6 +++--- vcpkg.json | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d2ff531ab..76e652ecc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -226,11 +226,11 @@ jobs: run: | sudo apt update sudo apt install libgl1-mesa-dev autoconf automake libtool pkg-config libltdl-dev g++-14 gcc-14 -y + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 14 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 14 cd ${{ github.workspace }} ${{ github.workspace }}/vcpkg/vcpkg install --clean-after-build --triplet=x64-linux rm -r vcpkg_installed - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 14 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 14 - name: Build swiftshader uses: ashutoshvarma/action-cmake-build@master diff --git a/CMakeLists.txt b/CMakeLists.txt index acdbf29e7..4960b74c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,7 @@ find_package(VulkanMemoryAllocator CONFIG REQUIRED) find_package(glslang CONFIG REQUIRED) find_package(SPIRV-Tools-opt CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) -find_package(unofficial-joltphysics CONFIG REQUIRED) +find_package(Jolt CONFIG REQUIRED) find_package(Lua REQUIRED) find_package(sol2 CONFIG REQUIRED) diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index 7e2c5e229..6d51a7c6c 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -53,7 +53,7 @@ if(WIN32) set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SPIRV-Tools-opt volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator - unofficial::spirv-reflect glslang::SPIRV unofficial::joltphysics::Jolt + unofficial::spirv-reflect glslang::SPIRV Jolt::Jolt ${LUA_LIBRARIES} sol2 fsr2) endif() @@ -67,7 +67,7 @@ if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_MACOS_MVK -DVK_EXAMPLE_XCODE_GENERATED") set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static - volk::volk SPIRV-Tools-opt unofficial::joltphysics::Jolt fsr2 + volk::volk SPIRV-Tools-opt Jolt::Jolt fsr2 GPUOpen::VulkanMemoryAllocator Vulkan::Vulkan Vulkan::Headers unofficial::spirv-reflect glslang::SPIRV ${LUA_LIBRARIES} sol2) endif() @@ -87,7 +87,7 @@ if(UNIX AND NOT APPLE AND NOT ANDROID) set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -ldl") set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static fsr2 - volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator unofficial::joltphysics::Jolt + volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator Jolt::Jolt unofficial::spirv-reflect SPIRV-Tools-opt glslang::SPIRV ${LUA_LIBRARIES} sol2) if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 14.0) diff --git a/vcpkg.json b/vcpkg.json index 3df880319..68dd576d1 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -84,7 +84,7 @@ }, { "name": "joltphysics", - "version": "5.0.0#1" + "version": "5.1.0#0" }, { "name": "lua", From 0c21cc2fb3b5eb33933eb7d20183dfe9c7d1ec45 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 7 Sep 2024 21:05:15 +0200 Subject: [PATCH 31/66] Turn validation layers off --- src/engine/Engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index ca1dcf567..939017d17 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -53,7 +53,7 @@ namespace Atlas { #ifdef AE_BUILDTYPE_DEBUG .enableValidationLayers = true, #else - .enableValidationLayers = true, + .enableValidationLayers = false, #endif .validationLayerSeverity = config.validationLayerSeverity, #ifndef AE_HEADLESS From 6a4bb70efb9369fbd537ab76e3889f93304137c4 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 10 Sep 2024 16:26:52 +0200 Subject: [PATCH 32/66] Path tracing uses normal render target now + bloom and point light fixes --- data/shader/bloom/bloomDownsample.csh | 70 ++--- data/shader/bloom/bloomUpsample.csh | 12 +- data/shader/deferred/direct.csh | 2 +- data/shader/globals.hsh | 1 + data/shader/pathtracer/rayGen.csh | 23 +- data/shader/pathtracer/rayHit.csh | 4 +- data/shader/pathtracer/temporal.csh | 27 +- data/shader/postprocessing.fsh | 4 +- data/shader/raytracer/direct.hsh | 2 +- data/shader/reflection/rtreflection.csh | 102 +++---- data/shader/rtgi/rtgi.csh | 70 ++--- libs/ImguiExtension/CMakeLists.txt | 2 +- .../panels/PostProcessingPanel.cpp | 9 + libs/ImguiExtension/panels/RTGIPanel.cpp | 3 +- .../ImguiExtension/panels/ReflectionPanel.cpp | 1 + src/demo/App.cpp | 9 +- src/demo/App.h | 1 - src/editor/App.cpp | 1 - src/editor/CMakeLists.txt | 2 +- src/editor/Singletons.cpp | 2 - src/editor/Singletons.h | 2 - src/editor/ui/panels/ViewportPanel.cpp | 24 +- src/engine/lighting/RTGI.h | 3 +- src/engine/lighting/Reflection.h | 1 + src/engine/loader/ModelImporter.cpp | 30 +- src/engine/postprocessing/Vignette.h | 8 +- src/engine/renderer/FSR2Renderer.cpp | 2 +- src/engine/renderer/MainRenderer.cpp | 77 ++++-- src/engine/renderer/MainRenderer.h | 2 +- src/engine/renderer/PathTracingRenderer.cpp | 88 +++--- src/engine/renderer/PathTracingRenderer.h | 2 +- src/engine/renderer/PostProcessRenderer.cpp | 112 +------- src/engine/renderer/PostProcessRenderer.h | 4 - src/engine/renderer/RTGIRenderer.cpp | 1 + src/engine/renderer/RTGIRenderer.h | 2 +- src/engine/renderer/RTReflectionRenderer.cpp | 1 + src/engine/renderer/RTReflectionRenderer.h | 2 +- src/engine/renderer/Renderer.h | 1 - src/engine/renderer/TemporalAARenderer.cpp | 65 ----- src/engine/renderer/TemporalAARenderer.h | 7 - src/engine/renderer/helper/CommonStructures.h | 1 + .../renderer/target/PathTraceRenderTarget.cpp | 121 -------- .../renderer/target/PathTraceRenderTarget.h | 61 ----- src/engine/renderer/target/RenderTarget.cpp | 258 +++++++++++------- src/engine/renderer/target/RenderTarget.h | 14 + src/engine/scene/SceneRenderState.cpp | 2 + .../scene/components/CameraComponent.cpp | 6 + src/engine/scene/components/CameraComponent.h | 2 + .../scene/components/LightComponent.cpp | 19 +- src/engine/scene/components/LightComponent.h | 4 +- src/tests/App.cpp | 8 +- src/tests/App.h | 1 - 52 files changed, 528 insertions(+), 750 deletions(-) delete mode 100644 src/engine/renderer/target/PathTraceRenderTarget.cpp delete mode 100644 src/engine/renderer/target/PathTraceRenderTarget.h diff --git a/data/shader/bloom/bloomDownsample.csh b/data/shader/bloom/bloomDownsample.csh index a1812a9a3..254c9dc15 100644 --- a/data/shader/bloom/bloomDownsample.csh +++ b/data/shader/bloom/bloomDownsample.csh @@ -81,8 +81,8 @@ vec3 Sample(vec2 texCoord) { vec2 pixel = texCoord * textureSize(textureIn, pushConstants.mipLevel); pixel -= 0.5; - float x = fract(pixel.x); - float y = fract(pixel.y); + float x = fract(pixel.x); + float y = fract(pixel.y); float weights[4] = { (1 - x) * (1 - y), x * (1 - y), (1 - x) * y, x * y }; @@ -99,24 +99,6 @@ vec3 Sample(vec2 texCoord) { } -vec3 SampleShared(ivec2 texel) { - - // This is offcenter - bool invalidIdx = false; - - const ivec2 localOffset = 2 * ivec2(gl_LocalInvocationID); - vec3 color = vec3(0.0); - for (int i = 0; i < 4; i++) { - ivec2 offsetPixel = localOffset + texel + pixelOffsets[i]; - int sharedMemoryIdx = Flatten2D(offsetPixel, unflattenedSharedDataSize); - if (sharedMemoryIdx < 0 || sharedMemoryIdx >= sharedDataSize) - invalidIdx = true; - color += 0.25 * sharedMemory[sharedMemoryIdx]; - } - return invalidIdx ? vec3(10000.0, 0.0, 0.0) : color; - -} - void main() { LoadGroupSharedData(); @@ -126,7 +108,6 @@ void main() { if (coord.x < size.x && coord.y < size.y) { -#if 1 // Lower mip tex coord vec2 texCoord = (coord + 0.5) / size; // Upper mip texel size @@ -149,34 +130,29 @@ void main() { vec3 inner10 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); vec3 inner01 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); vec3 inner11 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); -#else - // We always sample at pixel border, not centers - vec3 outer00 = SampleShared(ivec2(0, 0)); - vec3 outer10 = SampleShared(ivec2(2, 0)); - vec3 outer20 = SampleShared(ivec2(4, 0)); - - vec3 outer01 = SampleShared(ivec2(0, 2)); - vec3 outer11 = SampleShared(ivec2(2, 2)); - vec3 outer21 = SampleShared(ivec2(4, 2)); - - vec3 outer02 = SampleShared(ivec2(0, 4)); - vec3 outer12 = SampleShared(ivec2(2, 4)); - vec3 outer22 = SampleShared(ivec2(4, 4)); - - vec3 inner00 = SampleShared(ivec2(1, 1)); - vec3 inner10 = SampleShared(ivec2(3, 1)); - vec3 inner01 = SampleShared(ivec2(1, 3)); - vec3 inner11 = SampleShared(ivec2(3, 3)); -#endif - vec3 filtered = vec3(0.0); + vec3 outerGroup0 = 0.125 * (outer00 + outer10 + outer01 + outer11) * 0.25; + vec3 outerGroup1 = 0.125 * (outer10 + outer20 + outer11 + outer21) * 0.25; + vec3 outerGroup2 = 0.125 * (outer01 + outer11 + outer02 + outer12) * 0.25; + vec3 outerGroup3 = 0.125 * (outer11 + outer21 + outer12 + outer22) * 0.25; + vec3 innerGroup = 0.5 * (inner00 + inner10 + inner01 + inner11) * 0.25; + + if (pushConstants.mipLevel == 0) { + float outerGroup0Weight = (1.0 / (1.0 + Luma(outerGroup0))); + float outerGroup1Weight = (1.0 / (1.0 + Luma(outerGroup1))); + float outerGroup2Weight = (1.0 / (1.0 + Luma(outerGroup2))); + float outerGroup3Weight = (1.0 / (1.0 + Luma(outerGroup3))); + float innerGroupWeight = (1.0 / (1.0 + Luma(innerGroup))); + + outerGroup0 *= outerGroup0Weight; + outerGroup1 *= outerGroup1Weight; + outerGroup2 *= outerGroup2Weight; + outerGroup3 *= outerGroup3Weight; + innerGroup *= innerGroupWeight; + } + + vec3 filtered = outerGroup0 + outerGroup1 + outerGroup2 + outerGroup3 + innerGroup; - filtered += 0.125 * (outer00 + outer10 + outer01 + outer11) * 0.25; - filtered += 0.125 * (outer10 + outer20 + outer11 + outer21) * 0.25; - filtered += 0.125 * (outer01 + outer11 + outer02 + outer12) * 0.25; - filtered += 0.125 * (outer11 + outer21 + outer12 + outer22) * 0.25; - filtered += 0.5 * (inner00 + inner10 + inner01 + inner11) * 0.25; - imageStore(textureOut, coord, vec4(filtered, 1.0)); } diff --git a/data/shader/bloom/bloomUpsample.csh b/data/shader/bloom/bloomUpsample.csh index 4e99fc60d..ee399301d 100644 --- a/data/shader/bloom/bloomUpsample.csh +++ b/data/shader/bloom/bloomUpsample.csh @@ -4,6 +4,7 @@ layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; layout (set = 3, binding = 1) uniform sampler2D textureIn; layout(push_constant) uniform constants { + int additive; int mipLevel; float filterSize; } pushConstants; @@ -25,7 +26,9 @@ void main() { // Lower mip tex coord vec2 texCoord = (coord + 0.5) / size; // Upper mip texel size - vec2 texelSize = vec2(pushConstants.filterSize); + vec2 texelSize = 1.0 / textureSize(textureIn, pushConstants.mipLevel); + vec2 filterSize = vec2(pushConstants.filterSize); + texelSize = max(filterSize, filterSize); // We always sample at pixel border, not centers vec3 filter00 = Sample(texCoord + vec2(-texelSize.x, -texelSize.y)); @@ -47,7 +50,12 @@ void main() { filtered += 1.0 * (filter00 + filter20 + filter02 + filter22); filtered /= 16.0; - imageStore(textureOut, coord, vec4(filtered + filter11, 1.0)); + if (pushConstants.additive > 0) { + imageStore(textureOut, coord, vec4(filtered + filter11, 1.0)); + } + else { + imageStore(textureOut, coord, vec4(filtered, 1.0)); + } } diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 0cdc82be1..a7d9d3a64 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -99,7 +99,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai vec3 pointToLight = light.location.xyz - surface.P; float sqrDistance = dot(pointToLight, pointToLight); float dist = sqrt(sqrDistance); - lightMultiplier = pow(max(light.radius - dist, 0.0001) / light.radius, light.attenuation); + lightMultiplier = saturate(1.0 - pow(dist / light.radius, 4.0)) / sqrDistance; surface.L = pointToLight / dist; } diff --git a/data/shader/globals.hsh b/data/shader/globals.hsh index 54fa3acbf..a276ae625 100644 --- a/data/shader/globals.hsh +++ b/data/shader/globals.hsh @@ -18,6 +18,7 @@ layout(set = 1, binding = 31, std140) uniform GlobalBuffer { mat4 pvMatrixCurrent; mat4 ipvMatrixLast; mat4 ipvMatrixCurrent; + mat4 vMatrixLast; vec2 jitterLast; vec2 jitterCurrent; vec4 cameraLocation; diff --git a/data/shader/pathtracer/rayGen.csh b/data/shader/pathtracer/rayGen.csh index eaa857fa5..149546f46 100644 --- a/data/shader/pathtracer/rayGen.csh +++ b/data/shader/pathtracer/rayGen.csh @@ -4,6 +4,7 @@ #include <../raytracer/buffers.hsh> #include <../raytracer/tracing.hsh> #include <../common/random.hsh> +#include <../common/convert.hsh> #include <../common/flatten.hsh> layout (local_size_x = 8, local_size_y = 8) in; @@ -28,6 +29,11 @@ void main() { int(gl_GlobalInvocationID.y) < Uniforms.tileSize.y) { ivec2 pixel = ivec2(gl_GlobalInvocationID.xy) + Uniforms.pixelOffset; + + Ray ray; + + ray.ID = Flatten2D(pixel, Uniforms.resolution) * int(gl_NumWorkGroups.z) + int(gl_WorkGroupID.z); + ray.hitID = 0; // Apply a subpixel jitter to get supersampling float jitterX = random(vec2(float(Uniforms.sampleCount), 0.0)); @@ -35,20 +41,17 @@ void main() { #ifndef REALTIME vec2 coord = (vec2(pixel) + vec2(jitterX, jitterY)) / vec2(float(Uniforms.resolution.x), float(Uniforms.resolution.y)); -#else - vec2 coord = globalData.jitterCurrent * 0.25 + (vec2(pixel) + vec2(0.5)) / - vec2(float(Uniforms.resolution.x), float(Uniforms.resolution.y)); -#endif - - Ray ray; - - ray.ID = Flatten2D(pixel, Uniforms.resolution) * int(gl_NumWorkGroups.z) + int(gl_WorkGroupID.z); - ray.direction = normalize(Uniforms.origin.xyz + Uniforms.right.xyz * coord.x + Uniforms.bottom.xyz * coord.y - globalData.cameraLocation.xyz); ray.origin = globalData.cameraLocation.xyz; +#else + vec2 texCoord = (vec2(pixel) + 0.5) / vec2(Uniforms.resolution); + vec3 nearPosition = vec3(globalData.ivMatrix * vec4(ConvertDepthToViewSpace(0.0, texCoord), 1.0)); + vec3 farPosition = vec3(globalData.ivMatrix * vec4(ConvertDepthToViewSpace(1.0, texCoord), 1.0)); - ray.hitID = 0; + ray.origin = nearPosition; + ray.direction = normalize(farPosition - nearPosition); +#endif // Calculate number of potential overlapping pixels at the borders of a tile ivec2 overlappingPixels = Uniforms.tileSize % ivec2(gl_WorkGroupSize); diff --git a/data/shader/pathtracer/rayHit.csh b/data/shader/pathtracer/rayHit.csh index 674b7a69c..72bd6c77e 100644 --- a/data/shader/pathtracer/rayHit.csh +++ b/data/shader/pathtracer/rayHit.csh @@ -102,7 +102,7 @@ void main() { vec4 viewSpacePos = globalData.vMatrix * vec4(position, 1.0); vec4 projPositionCurrent = globalData.pMatrix * viewSpacePos; - vec4 projPositionLast = globalData.pvMatrixLast * vec4(lastPos, 1.0); + vec4 projPositionLast = globalData.pMatrix * globalData.vMatrixLast * vec4(lastPos, 1.0); vec2 ndcCurrent = projPositionCurrent.xy / projPositionCurrent.w; vec2 ndcLast = projPositionLast.xy / projPositionLast.w; @@ -110,7 +110,7 @@ void main() { vec2 velocity = (ndcLast - ndcCurrent) * 0.5; imageStore(velocityImage, pixel, vec4(velocity, 0.0, 0.0)); - imageStore(depthImage, pixel, vec4(ray.hitID >= 0 ? viewSpacePos.z : INF, 0.0, 0.0, 0.0)); + imageStore(depthImage, pixel, vec4(ray.hitID >= 0 ? projPositionCurrent.z / projPositionCurrent.w : INF, 0.0, 0.0, 0.0)); imageStore(materialIdxImage, pixel, uvec4(materialId, 0.0, 0.0, 0.0)); imageStore(normalImage, pixel, vec4(EncodeNormal(geometryNormal), 0.0, 0.0)); } diff --git a/data/shader/pathtracer/temporal.csh b/data/shader/pathtracer/temporal.csh index a7a2883b5..a2740d559 100644 --- a/data/shader/pathtracer/temporal.csh +++ b/data/shader/pathtracer/temporal.csh @@ -11,7 +11,7 @@ layout (local_size_x = 16, local_size_y = 16) in; -layout (set = 3, binding = 0, rgba8) writeonly uniform image2D resolveImage; +layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D outputImage; layout (set = 3, binding = 1, r32ui) readonly uniform uimage2DArray frameAccumImage; layout (set = 3, binding = 2) uniform sampler2D inAccumImage; layout (set = 3, binding = 3, rgba32f) writeonly uniform image2D outAccumImage; @@ -34,8 +34,8 @@ layout(push_constant) uniform constants { float maxRadiance; } pushConstants; -vec2 invResolution = 1.0 / vec2(imageSize(resolveImage)); -vec2 resolution = vec2(imageSize(resolveImage)); +vec2 invResolution = 1.0 / vec2(imageSize(outAccumImage)); +vec2 resolution = vec2(imageSize(outAccumImage)); const int kernelRadius = 5; @@ -106,7 +106,7 @@ void LoadGroupSharedData() { texel = clamp(texel, ivec2(0), ivec2(resolution) - ivec2(1)); sharedRadianceDepth[i].rgb = FetchTexel(texel); - sharedRadianceDepth[i].a = texelFetch(depthTexture, texel, 0).r; + sharedRadianceDepth[i].a = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, texel, 0).r); } barrier(); @@ -140,7 +140,7 @@ ivec2 FindNearest3x3(ivec2 pixel) { for (int i = 0; i < 9; i++) { ivec2 offsetPixel = clamp(pixel + offsets[i], ivec2(0), ivec2(resolution) - ivec2(1)); - float currDepth = texelFetch(depthTexture, offsetPixel, 0).r; + float currDepth = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, offsetPixel, 0).r); if (currDepth < depth) { depth = currDepth; offset = offsets[i]; @@ -182,7 +182,7 @@ float IsHistoryPixelValid(ivec2 pixel, float linearDepth, uint materialIdx, vec3 confidence *= historyMaterialIdx != materialIdx ? 0.0 : 1.0; float depthPhi = 16.0 / abs(linearDepth); - float historyDepth = texelFetch(historyDepthTexture, pixel, 0).r; + float historyDepth = ConvertDepthToViewSpaceDepth(texelFetch(historyDepthTexture, pixel, 0).r); float historyLinearDepth = historyDepth; confidence *= min(1.0 , exp(-abs(linearDepth - historyLinearDepth) * depthPhi)); @@ -203,7 +203,7 @@ bool SampleHistory(ivec2 pixel, vec2 historyPixel, vec2 velocity, out vec4 histo uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; vec3 normal = DecodeNormal(texelFetch(normalTexture, pixel, 0).rg); - float depth = texelFetch(depthTexture, pixel, 0).r; + float depth = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, pixel, 0).r); float linearDepth = depth; float depthPhi = 16.0 / abs(linearDepth); @@ -258,7 +258,7 @@ bool SampleHistory(ivec2 pixel, vec2 historyPixel, vec2 velocity, out vec4 histo vec4 GetCatmullRomSample(ivec2 pixel, inout float weight, float linearDepth, uint materialIdx, vec3 normal) { - pixel = clamp(pixel, ivec2(0), ivec2(imageSize(resolveImage) - 1)); + pixel = clamp(pixel, ivec2(0), ivec2(imageSize(outAccumImage) - 1)); weight *= IsHistoryPixelValid(pixel, linearDepth, materialIdx, normal); @@ -275,7 +275,7 @@ bool SampleCatmullRom(ivec2 pixel, vec2 uv, out vec4 history) { uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; vec3 normal = DecodeNormal(texelFetch(normalTexture, pixel, 0).rg); - float depth = texelFetch(depthTexture, pixel, 0).r; + float depth = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, pixel, 0).r); vec2 position = uv * resolution; @@ -333,7 +333,7 @@ void ComputeVarianceMinMax(out vec3 mean, out vec3 std) { const int radius = kernelRadius; ivec2 pixel = ivec2(gl_GlobalInvocationID); - float depth = texelFetch(depthTexture, pixel, 0).r; + float depth = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, pixel, 0).r); float linearDepth = depth; float totalWeight = 0.0; @@ -364,11 +364,11 @@ void main() { LoadGroupSharedData(); ivec2 pixel = ivec2(gl_GlobalInvocationID); - if (pixel.x > imageSize(resolveImage).x || - pixel.y > imageSize(resolveImage).y) + if (pixel.x > imageSize(outAccumImage).x || + pixel.y > imageSize(outAccumImage).y) return; - uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; + uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; ivec2 offset = FindNearest3x3(pixel); @@ -427,6 +427,7 @@ void main() { vec3 resolve = mix(currentRadiance, historyRadiance, factor); imageStore(outAccumImage, pixel, vec4(resolve, historyLength + 1.0)); + imageStore(outputImage, pixel, vec4(resolve, 1.0)); //imageStore(outAccumImage, pixel, vec4(vec3(valid ? 1.0 : 0.0), historyLength + 1.0)); //imageStore(outAccumImage, pixel, vec4(vec3(historyLength / 10.0), historyLength + 1.0)); diff --git a/data/shader/postprocessing.fsh b/data/shader/postprocessing.fsh index db9f71b3a..d2c278179 100644 --- a/data/shader/postprocessing.fsh +++ b/data/shader/postprocessing.fsh @@ -162,10 +162,10 @@ void main() { color = ((color - 0.5) * max(Uniforms.contrast, 0.0)) + 0.5; #ifdef VIGNETTE - float vignetteFactor = max(1.0 - max(pow(length(fPosition) - Uniforms.vignetteOffset, + float vignetteFactor = max(1.0 - max(pow(length(positionVS) - Uniforms.vignetteOffset, Uniforms.vignettePower), 0.0) * Uniforms.vignetteStrength, 0.0); - color = mix(Uniforms.vignetteColor.rgb, color, Uniforms.vignetteFactor); + color = mix(Uniforms.vignetteColor.rgb, color, vignetteFactor); #endif outColor = vec4(color, 1.0); diff --git a/data/shader/raytracer/direct.hsh b/data/shader/raytracer/direct.hsh index 54253cd41..a781d3e42 100644 --- a/data/shader/raytracer/direct.hsh +++ b/data/shader/raytracer/direct.hsh @@ -95,7 +95,7 @@ void SampleLight(Light light, inout Surface surface, float seed0, float seed1, vec3 pointToLight = light.P - surface.P; float sqrDistance = dot(pointToLight, pointToLight); dist = sqrt(sqrDistance); - solidAngle = pow(max(light.radius - dist, 0.0001) / light.radius, light.attenuation); + solidAngle = saturate(1.0 - pow(dist / light.radius, 4.0)) / sqrDistance; surface.L = pointToLight / dist; UpdateSurface(surface); diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index a568e27a1..3c7ddcc27 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -46,13 +46,13 @@ layout(std140, set = 3, binding = 9) uniform UniformBuffer { float radianceLimit; uint frameSeed; float bias; + int sampleCount; int lightSampleCount; int textureLevel; float roughnessCutoff; int halfRes; int padding0; int padding1; - int padding2; ivec2 resolution; Shadow shadow; } uniforms; @@ -89,12 +89,6 @@ void main() { vec3 viewVec = vec3(globalData.ivMatrix * vec4(viewPos, 0.0)); vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(DecodeNormal(textureLod(normalTexture, texCoord, 0).rg), 0.0))); - int sampleIdx = int(uniforms.frameSeed); - vec2 blueNoiseVec = vec2( - SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture), - SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) - ); - uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; Material material = UnpackMaterial(materialIdx); @@ -105,60 +99,72 @@ void main() { if (material.roughness <= 1.0 && depth < 1.0) { - float alpha = sqr(material.roughness); + const int sampleCount = uniforms.sampleCount; - vec3 V = normalize(-viewVec); - vec3 N = worldNorm; + for (int i = 0; i < sampleCount; i++) { + int sampleIdx = int(uniforms.frameSeed) * sampleCount + i; + vec2 blueNoiseVec = vec2( + SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture), + SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) + ); - Surface surface = CreateSurface(V, N, vec3(1.0), material); + float alpha = sqr(material.roughness); - Ray ray; - blueNoiseVec.y *= (1.0 - uniforms.bias); + vec3 V = normalize(-viewVec); + vec3 N = worldNorm; - float pdf = 1.0; - BRDFSample brdfSample; - if (material.roughness > 0.01) { - ImportanceSampleGGXVNDF(blueNoiseVec, N, V, alpha, - ray.direction, pdf); - } - else { - ray.direction = normalize(reflect(-V, N)); - } + Surface surface = CreateSurface(V, N, vec3(1.0), material); - bool isRayValid = !isnan(ray.direction.x) || !isnan(ray.direction.y) || - !isnan(ray.direction.z) || dot(N, ray.direction) >= 0.0; + Ray ray; + blueNoiseVec.y *= (1.0 - uniforms.bias); - if (isRayValid) { - // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore - float viewOffset = max(1.0, length(viewPos)) * 0.1; - ray.origin = worldPos + ray.direction * EPSILON * 0.1 * viewOffset + worldNorm * EPSILON * viewOffset * 0.1; + float pdf = 1.0; + BRDFSample brdfSample; + if (material.roughness > 0.01) { + ImportanceSampleGGXVNDF(blueNoiseVec, N, V, alpha, + ray.direction, pdf); + } + else { + ray.direction = normalize(reflect(-V, N)); + } - ray.hitID = -1; - ray.hitDistance = 0.0; + bool isRayValid = !isnan(ray.direction.x) || !isnan(ray.direction.y) || + !isnan(ray.direction.z) || dot(N, ray.direction) >= 0.0; - vec3 radiance = vec3(0.0); + if (isRayValid) { + // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore + float viewOffset = max(1.0, length(viewPos)) * 0.1; + ray.origin = worldPos + ray.direction * EPSILON * 0.1 * viewOffset + worldNorm * EPSILON * viewOffset * 0.1; - if (material.roughness <= uniforms.roughnessCutoff) { - #ifdef OPACITY_CHECK - HitClosestTransparency(ray, INSTANCE_MASK_ALL, 0.0, INF); - #else - HitClosest(ray, INSTANCE_MASK_ALL, 0.0, INF); - #endif + ray.hitID = -1; + ray.hitDistance = 0.0; - radiance = EvaluateHit(ray); - } - else { - #ifdef DDGI - radiance = GetLocalIrradiance(worldPos, V, N).rgb; - radiance = IsInsideVolume(worldPos) ? radiance : vec3(0.0); - #endif - } + vec3 radiance = vec3(0.0); - float radianceMax = max(max(max(radiance.r, - max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01); - reflection = radiance * (uniforms.radianceLimit / radianceMax); + if (material.roughness <= uniforms.roughnessCutoff) { +#ifdef OPACITY_CHECK + HitClosestTransparency(ray, INSTANCE_MASK_ALL, 0.0, INF); +#else + HitClosest(ray, INSTANCE_MASK_ALL, 0.0, INF); +#endif + + radiance = EvaluateHit(ray); + } + else { +#ifdef DDGI + radiance = GetLocalIrradiance(worldPos, V, N).rgb; + radiance = IsInsideVolume(worldPos) ? radiance : vec3(0.0); +#endif + } + + float radianceMax = max(max(max(radiance.r, + max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01); + reflection += radiance * (uniforms.radianceLimit / radianceMax); + } } + reflection /= float(sampleCount); + } imageStore(rtrImage, pixel, vec4(reflection, 1.0)); diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index 3363949c1..5606582f2 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -46,13 +46,13 @@ layout(std140, set = 3, binding = 9) uniform UniformBuffer { float radianceLimit; uint frameSeed; float bias; + int sampleCount; int lightSampleCount; int textureLevel; float roughnessCutoff; int halfRes; int padding0; int padding1; - int padding2; ivec2 resolution; Shadow shadow; } uniforms; @@ -89,12 +89,6 @@ void main() { vec3 viewVec = vec3(globalData.ivMatrix * vec4(viewPos, 0.0)); vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(DecodeNormal(textureLod(normalTexture, texCoord, 0).rg), 0.0))); - int sampleIdx = int(uniforms.frameSeed); - vec2 blueNoiseVec = vec2( - SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture), - SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) - ); - uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; Material material = UnpackMaterial(materialIdx); @@ -105,49 +99,59 @@ void main() { if (depth < 1.0) { - float alpha = sqr(material.roughness); + const int sampleCount = uniforms.sampleCount; + + for (int i = 0; i < sampleCount; i++) { + int sampleIdx = int(uniforms.frameSeed) * sampleCount + i; + vec2 blueNoiseVec = vec2( + SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture), + SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) + ); - vec3 V = normalize(-viewVec); - vec3 N = worldNorm; + vec3 V = normalize(-viewVec); + vec3 N = worldNorm; - Surface surface = CreateSurface(V, N, vec3(1.0), material); + Surface surface = CreateSurface(V, N, vec3(1.0), material); - blueNoiseVec.x *= (1.0 - uniforms.bias); + blueNoiseVec.x *= (1.0 - uniforms.bias); - Ray ray; + Ray ray; - float pdf = 1.0; - BRDFSample brdfSample; - float NdotL; - ImportanceSampleCosDir(N, blueNoiseVec, - ray.direction, NdotL, pdf); + float pdf = 1.0; + BRDFSample brdfSample; + float NdotL; + ImportanceSampleCosDir(N, blueNoiseVec, + ray.direction, NdotL, pdf); - bool isRayValid = !isnan(ray.direction.x) || !isnan(ray.direction.y) || - !isnan(ray.direction.z) || dot(N, ray.direction) > 0.0; + bool isRayValid = !isnan(ray.direction.x) || !isnan(ray.direction.y) || + !isnan(ray.direction.z) || dot(N, ray.direction) > 0.0; - if (isRayValid) { + if (isRayValid) { - // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore - float viewOffset = max(1.0, length(viewPos)); - ray.origin = worldPos + ray.direction * EPSILON * viewOffset * 0.01 + worldNorm * EPSILON * 0.01 * viewOffset; + // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore + float viewOffset = max(1.0, length(viewPos)); + ray.origin = worldPos + ray.direction * EPSILON * viewOffset * 0.01 + worldNorm * EPSILON * 0.01 * viewOffset; - ray.hitID = -1; - ray.hitDistance = 0.0; + ray.hitID = -1; + ray.hitDistance = 0.0; - vec3 radiance = vec3(0.0); + vec3 radiance = vec3(0.0); #ifdef OPACITY_CHECK - HitClosestTransparency(ray, INSTANCE_MASK_ALL, 0.0, INF); + HitClosestTransparency(ray, INSTANCE_MASK_ALL, 0.0, INF); #else - HitClosest(ray, INSTANCE_MASK_ALL, 0.0, INF); + HitClosest(ray, INSTANCE_MASK_ALL, 0.0, INF); #endif - radiance = EvaluateHit(ray); + radiance = EvaluateHit(ray); - float radianceMax = max(max(max(radiance.r, - max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01); - reflection = radiance * (uniforms.radianceLimit / radianceMax); + float radianceMax = max(max(max(radiance.r, + max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01); + reflection += radiance * (uniforms.radianceLimit / radianceMax); + } } + reflection /= float(sampleCount); + } imageStore(rtrImage, pixel, vec4(reflection, 1.0)); diff --git a/libs/ImguiExtension/CMakeLists.txt b/libs/ImguiExtension/CMakeLists.txt index 16e8521de..5ad3fbfea 100644 --- a/libs/ImguiExtension/CMakeLists.txt +++ b/libs/ImguiExtension/CMakeLists.txt @@ -29,4 +29,4 @@ find_package(imgui CONFIG REQUIRED) # after the engine is added add_library(${PROJECT_NAME} STATIC ${IMGUI_SOURCE_FILES}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${ATLAS_ENGINE_COMPILE_DEFINITIONS}) -target_link_libraries(${PROJECT_NAME} imgui::imgui volk::volk volk::volk_headers SDL2::SDL2 GPUOpen::VulkanMemoryAllocator) \ No newline at end of file +target_link_libraries(${PROJECT_NAME} imgui::imgui volk::volk volk::volk_headers SDL2::SDL2 GPUOpen::VulkanMemoryAllocator Jolt::Jolt) \ No newline at end of file diff --git a/libs/ImguiExtension/panels/PostProcessingPanel.cpp b/libs/ImguiExtension/panels/PostProcessingPanel.cpp index 1797d52cb..25094a544 100644 --- a/libs/ImguiExtension/panels/PostProcessingPanel.cpp +++ b/libs/ImguiExtension/panels/PostProcessingPanel.cpp @@ -28,9 +28,18 @@ namespace Atlas::ImguiExtension { ImGui::Checkbox("Enable##Chromatic aberration", &postProcessing.chromaticAberration.enable); ImGui::Checkbox("Colors reversed", &postProcessing.chromaticAberration.colorsReversed); ImGui::SliderFloat("Strength##Chromatic abberation", &postProcessing.chromaticAberration.strength, 0.0f, 4.0f); + ImGui::Separator(); ImGui::Text("Film grain"); ImGui::Checkbox("Enable##Film grain", &postProcessing.filmGrain.enable); ImGui::SliderFloat("Strength##Film grain", &postProcessing.filmGrain.strength, 0.0f, 1.0f); + ImGui::Separator(); + ImGui::Text("Vignette"); + ImGui::Checkbox("Enable##Vignette", &postProcessing.vignette.enable); + ImGui::ColorEdit3("Color##Vignette", glm::value_ptr(postProcessing.vignette.color)); + ImGui::SliderFloat("Strength##Vignette", &postProcessing.vignette.strength, 0.0f, 1.0f); + ImGui::SliderFloat("Power##Vignette", &postProcessing.vignette.power, 0.0f, 10.0f); + ImGui::SliderFloat("Offset##Vignette", &postProcessing.vignette.offset, -1.0f, 1.0f); + ImGui::Separator(); ImGui::Text("Bloom"); ImGui::Checkbox("Enable##Bloom", &postProcessing.bloom.enable); ImGui::DragFloat("Strength##Bloom", &postProcessing.bloom.strength, 0.001f, 0.0f, 1.0f); diff --git a/libs/ImguiExtension/panels/RTGIPanel.cpp b/libs/ImguiExtension/panels/RTGIPanel.cpp index 87c3369a7..2b7b657bc 100644 --- a/libs/ImguiExtension/panels/RTGIPanel.cpp +++ b/libs/ImguiExtension/panels/RTGIPanel.cpp @@ -27,7 +27,8 @@ namespace Atlas::ImguiExtension { } ImGui::SliderFloat("Bias", &rtgi->bias, 0.0f, 1.0f); ImGui::SliderInt("Texture level##RTGI", &rtgi->textureLevel, 0, 10); - ImGui::SliderInt("Light sample count##RTGI", &rtgi->lightSampleCount, 0, 10); + ImGui::SliderInt("Sample count##RTGI", &rtgi->sampleCount, 1, 10); + ImGui::SliderInt("Light sample count##RTGI", &rtgi->lightSampleCount, 1, 10); ImGui::Text("Denoiser"); ImGui::SliderFloat("Spatial filter strength", &rtgi->spatialFilterStrength, 0.0f, 10.0f); ImGui::SliderFloat("Temporal weight", &rtgi->temporalWeight, 0.0f, 1.0f); diff --git a/libs/ImguiExtension/panels/ReflectionPanel.cpp b/libs/ImguiExtension/panels/ReflectionPanel.cpp index f9b1fec8e..5b0b4f7bb 100644 --- a/libs/ImguiExtension/panels/ReflectionPanel.cpp +++ b/libs/ImguiExtension/panels/ReflectionPanel.cpp @@ -27,6 +27,7 @@ namespace Atlas::ImguiExtension { ImGui::SliderFloat("Bias", &reflection->bias, 0.0f, 1.0f); ImGui::SliderFloat("Roughness cuttoff", &reflection->roughnessCutoff, 0.0f, 1.0f); ImGui::SliderInt("Texture level##Reflection", &reflection->textureLevel, 0, 10); + ImGui::SliderInt("Sample count##Reflection", &reflection->sampleCount, 1, 10); ImGui::SliderInt("Light sample count##Reflection", &reflection->lightSampleCount, 0, 10); ImGui::Text("Denoiser"); ImGui::SliderFloat("Spatial filter strength", &reflection->spatialFilterStrength, 0.0f, 10.0f); diff --git a/src/demo/App.cpp b/src/demo/App.cpp index 7c4a4cbbc..49a1b107b 100644 --- a/src/demo/App.cpp +++ b/src/demo/App.cpp @@ -17,7 +17,6 @@ using namespace Atlas::ImguiExtension; void App::LoadContent() { renderTarget = Atlas::CreateRef(1920, 1080); - pathTraceTarget = Atlas::CreateRef(1920, 1080); viewport = Atlas::CreateRef(0, 0, renderTarget->GetWidth(), renderTarget->GetHeight()); @@ -264,7 +263,7 @@ void App::Render(float deltaTime) { static bool firstFrame = true; static bool animateLight = false; - static bool pathTrace = false; + static bool pathTrace = true; static bool debugAo = false; static bool debugReflection = false; static bool debugClouds = false; @@ -298,9 +297,10 @@ void App::Render(float deltaTime) { if (animateLight) directionalLight.properties.directional.direction = glm::vec3(0.0f, -1.0f, sin(Atlas::Clock::Get() / 10.0f)); + viewport->Set(0, 0, renderTarget->GetWidth(), renderTarget->GetHeight()); + if (pathTrace) { - viewport->Set(0, 0, pathTraceTarget->GetWidth(), pathTraceTarget->GetHeight()); - mainRenderer->PathTraceScene(viewport, pathTraceTarget, scene); + mainRenderer->PathTraceScene(viewport, renderTarget, scene); } else { mainRenderer->RenderScene(viewport, renderTarget, scene); @@ -1214,7 +1214,6 @@ void App::CheckLoadScene() { void App::SetResolution(int32_t width, int32_t height) { renderTarget->Resize(width, height); - pathTraceTarget->Resize(width, height); } diff --git a/src/demo/App.h b/src/demo/App.h index 7478acea7..502d8df59 100644 --- a/src/demo/App.h +++ b/src/demo/App.h @@ -59,7 +59,6 @@ class App : public Atlas::EngineInstance { SceneSelection sceneSelection = SPONZA; - Ref pathTraceTarget; Ref renderTarget; Ref viewport; diff --git a/src/editor/App.cpp b/src/editor/App.cpp index 13770525a..0fa0a3cd9 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -50,7 +50,6 @@ namespace Atlas::Editor { Singletons::icons = CreateRef(); Singletons::blockingOperation = CreateRef(); Singletons::renderTarget = CreateRef(1280, 720); - Singletons::pathTraceRenderTarget = CreateRef(1280, 720); Singletons::mainRenderer = mainRenderer; mouseHandler = Input::MouseHandler(1.5f, 8.0f); diff --git a/src/editor/CMakeLists.txt b/src/editor/CMakeLists.txt index 9b61053d4..0cd703bfa 100644 --- a/src/editor/CMakeLists.txt +++ b/src/editor/CMakeLists.txt @@ -46,4 +46,4 @@ add_executable(${PROJECT_NAME} ${EDITOR_SOURCE_FILES} ${ATLAS_ENGINE_MAIN_FILE}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${ATLAS_ENGINE_COMPILE_DEFINITIONS}) # We want to use both ImGui and the AtlasEngine. For ImGui, the ATLAS_IMGUI option # needs to be turned on. -target_link_libraries (${PROJECT_NAME} AtlasEngine ImguiExtension unofficial::imguizmo::imguizmo) \ No newline at end of file +target_link_libraries (${PROJECT_NAME} AtlasEngine ImguiExtension unofficial::imguizmo::imguizmo Jolt::Jolt) \ No newline at end of file diff --git a/src/editor/Singletons.cpp b/src/editor/Singletons.cpp index cc03a9bca..9612f4d84 100644 --- a/src/editor/Singletons.cpp +++ b/src/editor/Singletons.cpp @@ -4,7 +4,6 @@ namespace Atlas::Editor { Ref Singletons::imguiWrapper; Ref Singletons::renderTarget; - Ref Singletons::pathTraceRenderTarget; Ref Singletons::mainRenderer; Ref Singletons::icons; Ref Singletons::config; @@ -14,7 +13,6 @@ namespace Atlas::Editor { imguiWrapper.reset(); renderTarget.reset(); - pathTraceRenderTarget.reset(); mainRenderer.reset(); icons.reset(); config.reset(); diff --git a/src/editor/Singletons.h b/src/editor/Singletons.h index f178bc519..6500e3258 100644 --- a/src/editor/Singletons.h +++ b/src/editor/Singletons.h @@ -2,7 +2,6 @@ #include "ImguiExtension/ImguiWrapper.h" #include "renderer/target/RenderTarget.h" -#include "renderer/target/PathTraceRenderTarget.h" #include "renderer/MainRenderer.h" #include "Icons.h" #include "Config.h" @@ -17,7 +16,6 @@ namespace Atlas::Editor { static Ref imguiWrapper; static Ref renderTarget; - static Ref pathTraceRenderTarget; static Ref mainRenderer; static Ref icons; static Ref config; diff --git a/src/editor/ui/panels/ViewportPanel.cpp b/src/editor/ui/panels/ViewportPanel.cpp index f35b87939..8a26613d6 100644 --- a/src/editor/ui/panels/ViewportPanel.cpp +++ b/src/editor/ui/panels/ViewportPanel.cpp @@ -91,25 +91,17 @@ namespace Atlas::Editor::UI { if (scene != nullptr && validSize && isActive && !Singletons::blockingOperation->block) { auto& config = Singletons::config; + auto& renderTarget = Singletons::renderTarget; - if (config->pathTrace) { - auto& pathTraceRenderTarget = Singletons::pathTraceRenderTarget; - - if (pathTraceRenderTarget->GetWidth() != viewportTexture.width || - pathTraceRenderTarget->GetHeight() != viewportTexture.height) { - pathTraceRenderTarget->Resize(viewportTexture.width, viewportTexture.height); - } - - Singletons::mainRenderer->PathTraceScene(viewport, pathTraceRenderTarget, scene, &viewportTexture); + if (renderTarget->GetWidth() != viewportTexture.width || + renderTarget->GetHeight() != viewportTexture.height) { + renderTarget->Resize(viewportTexture.width, viewportTexture.height); } - else { - auto& renderTarget = Singletons::renderTarget; - - if (renderTarget->GetWidth() != viewportTexture.width || - renderTarget->GetHeight() != viewportTexture.height) { - renderTarget->Resize(viewportTexture.width, viewportTexture.height); - } + if (config->pathTrace) { + Singletons::mainRenderer->PathTraceScene(viewport, renderTarget, scene, &viewportTexture); + } + else { Singletons::mainRenderer->RenderScene(viewport, renderTarget, scene, primitiveBatchWrapper.primitiveBatch, &viewportTexture); diff --git a/src/engine/lighting/RTGI.h b/src/engine/lighting/RTGI.h index b05863fa9..2cf802b6a 100644 --- a/src/engine/lighting/RTGI.h +++ b/src/engine/lighting/RTGI.h @@ -13,7 +13,8 @@ namespace Atlas { RTGI() = default; int32_t textureLevel = 4; - int32_t lightSampleCount = 2; + int32_t sampleCount = 2; + int32_t lightSampleCount = 1; float radianceLimit = 5.0f; float bias = 0.15f; diff --git a/src/engine/lighting/Reflection.h b/src/engine/lighting/Reflection.h index 7ce3c8e34..e053b9e86 100644 --- a/src/engine/lighting/Reflection.h +++ b/src/engine/lighting/Reflection.h @@ -13,6 +13,7 @@ namespace Atlas { Reflection() = default; int32_t textureLevel = 3; + int32_t sampleCount = 1; int32_t lightSampleCount = 2; float radianceLimit = 10.0f; diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index 8312b338d..d407309c3 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -399,6 +399,12 @@ namespace Atlas { auto scene = CreateRef(filename, min, max, depth); + std::map lightMap; + for (uint32_t i = 0; i < state.scene->mNumLights; i++) { + auto light = state.scene->mLights[i]; + lightMap[light->mName.C_Str()] = light; + } + auto rootEntity = scene->CreateEntity(); rootEntity.AddComponent("Root"); auto& rootHierarchy = rootEntity.AddComponent(); @@ -423,6 +429,20 @@ namespace Atlas { parentEntity.GetComponent().AddChild(entity); } + if (lightMap.contains(node->mName.C_Str())) { + auto light = lightMap[node->mName.C_Str()]; + + if (light->mType == aiLightSource_POINT) { + auto& lightComp = parentEntity.AddComponent(LightType::PointLight, LightMobility::StationaryLight); + lightComp.color = Common::ColorConverter::ConvertLinearToSRGB(vec3(light->mColorDiffuse.r, light->mColorDiffuse.g, light->mColorDiffuse.b)); + lightComp.intensity = std::max(lightComp.color.r, std::max(lightComp.color.g, lightComp.color.b)); + lightComp.color /= std::max(lightComp.intensity, 1e-9f); + lightComp.properties.point.position = vec3(light->mPosition.x, light->mPosition.y, light->mPosition.z); + lightComp.properties.point.radius = glm::sqrt(100.0f * light->mAttenuationQuadratic); + lightComp.AddPointShadow(3.0f, 1024); + } + } + for (uint32_t i = 0; i < node->mNumChildren; i++) { auto nodeEntity = scene->CreatePrefab(node->mChildren[i]->mName.C_Str(), nodeTransform); auto const& hierarchy = nodeEntity.GetComponent(); @@ -486,10 +506,12 @@ namespace Atlas { auto imagesToSave = ImagesToTextures(state); - JobSystem::ExecuteMultiple(group, int32_t(imagesToSave.size()), [&](const JobData& data) { - ImageLoader::SaveImage(imagesToSave[data.idx], imagesToSave[data.idx]->fileName); - }); - JobSystem::Wait(group); + if (saveToDisk) { + JobSystem::ExecuteMultiple(group, int32_t(imagesToSave.size()), [&](const JobData& data) { + ImageLoader::SaveImage(imagesToSave[data.idx], imagesToSave[data.idx]->fileName); + }); + JobSystem::Wait(group); + } std::vector> materials; for (uint32_t i = 0; i < state.scene->mNumMaterials; i++) { diff --git a/src/engine/postprocessing/Vignette.h b/src/engine/postprocessing/Vignette.h index 14f07d952..f926c0cf6 100644 --- a/src/engine/postprocessing/Vignette.h +++ b/src/engine/postprocessing/Vignette.h @@ -16,11 +16,11 @@ namespace Atlas { bool enable = false; - float offset; - float power; - float strength; + float offset = 0.1f; + float power = 1.0f; + float strength = 0.1f; - vec3 color; + vec3 color = vec3(0.0f); }; diff --git a/src/engine/renderer/FSR2Renderer.cpp b/src/engine/renderer/FSR2Renderer.cpp index ba98a0abf..efa7d6b4b 100644 --- a/src/engine/renderer/FSR2Renderer.cpp +++ b/src/engine/renderer/FSR2Renderer.cpp @@ -841,7 +841,7 @@ namespace Atlas::Renderer { dispatchParameters.color = GetResource(colorImage, L"FSR2_InputColor", FFX_RESOURCE_STATE_COMPUTE_READ); dispatchParameters.depth = GetResource(depthImage, L"FSR2_InputDepth", FFX_RESOURCE_STATE_COMPUTE_READ); dispatchParameters.motionVectors = GetResource(velocityImage, L"FSR2_InputMotionVectors", FFX_RESOURCE_STATE_COMPUTE_READ); - dispatchParameters.reactive = GetResource(reactiveMaskImage, L"FSR2_EmptyInputReactiveMap", FFX_RESOURCE_STATE_COMPUTE_READ); + //dispatchParameters.reactive = GetResource(reactiveMaskImage, L"FSR2_EmptyInputReactiveMap", FFX_RESOURCE_STATE_COMPUTE_READ); //dispatchParameters.exposure = GetTextureResource(&context, nullptr, nullptr, 1, 1, VK_FORMAT_UNDEFINED, L"FSR2_InputExposure", FFX_RESOURCE_STATE_COMPUTE_READ); //dispatchParameters.reactive = GetTextureResource(&context, nullptr, nullptr, 1, 1, VK_FORMAT_UNDEFINED, L"FSR2_EmptyInputReactiveMap", FFX_RESOURCE_STATE_COMPUTE_READ); //dispatchParameters.transparencyAndComposition = GetTextureResource(&context, nullptr, nullptr, 1, 1, VK_FORMAT_UNDEFINED, L"FSR2_EmptyTransparencyAndCompositionMap", FFX_RESOURCE_STATE_COMPUTE_READ); diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 024acaefd..07fd3a983 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -72,6 +72,9 @@ namespace Atlas { if (!device->swapChain->isComplete || !scene->HasMainCamera()) return; + if (target->IsUsedForPathTracing()) + target->UseForPathTracing(false); + auto& camera = scene->GetMainCamera(); auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue); @@ -366,20 +369,18 @@ namespace Atlas { if (primitiveBatch) RenderPrimitiveBatch(viewport, target, primitiveBatch, scene->GetMainCamera(), commandList); - { - if (scene->postProcessing.fsr2) { - gBufferRenderer.GenerateReactiveMask(target, commandList); + if (scene->postProcessing.fsr2) { + gBufferRenderer.GenerateReactiveMask(target, commandList); - fsr2Renderer.Render(target, scene, commandList); - } - else { - taaRenderer.Render(target, scene, commandList); - } + fsr2Renderer.Render(target, scene, commandList); + } + else { + taaRenderer.Render(target, scene, commandList); + } - target->Swap(); + target->Swap(); - postProcessRenderer.Render(target, scene, commandList, texture); - } + postProcessRenderer.Render(target, scene, commandList, texture); Graphics::Profiler::EndQuery(); Graphics::Profiler::EndThread(); @@ -391,25 +392,40 @@ namespace Atlas { } - void MainRenderer::PathTraceScene(Ref viewport, Ref target, + void MainRenderer::PathTraceScene(Ref viewport, Ref target, Ref scene, Texture::Texture2D *texture) { if (!scene->IsRtDataValid() || !device->swapChain->isComplete || !scene->HasMainCamera()) return; - auto renderState = &scene->renderState; + if (!target->IsUsedForPathTracing()) + target->UseForPathTracing(true); - static vec2 lastJitter = vec2(0.0f); + auto renderState = &scene->renderState; auto& camera = scene->GetMainCamera(); auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue); - auto jitter = 2.0f * haltonSequence[haltonIndex] - 1.0f; - jitter.x /= (float)target->GetWidth(); - jitter.y /= (float)target->GetHeight(); + auto& taa = scene->postProcessing.taa; + if (taa.enable || scene->postProcessing.fsr2) { + vec2 jitter = vec2(0.0f); + if (scene->postProcessing.fsr2) { + jitter = fsr2Renderer.GetJitter(target, frameCount); + } + else { + jitter = 2.0f * haltonSequence[haltonIndex] - 1.0f; + jitter.x /= (float)target->GetScaledWidth() * 0.75f; + jitter.y /= (float)target->GetScaledHeight() * 0.75f; + } - camera.Jitter(jitter * 0.0f); + camera.Jitter(jitter * taa.jitterRange); + } + else { + // Even if there is no TAA we need to update the jitter for other techniques + // E.g. the reflections and ambient occlusion use reprojection + camera.Jitter(vec2(0.0f)); + } commandList->BeginCommands(); @@ -423,8 +439,9 @@ namespace Atlas { .ipMatrix = camera.invProjectionMatrix, .pvMatrixLast = camera.GetLastJitteredMatrix(), .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, - .jitterLast = lastJitter, - .jitterCurrent = jitter, + .vMatrixLast = camera.GetLastViewMatrix(), + .jitterLast = camera.GetJitter(), + .jitterCurrent = camera.GetLastJitter(), .cameraLocation = vec4(camera.GetLocation(), 0.0f), .cameraDirection = vec4(camera.direction, 0.0f), .cameraUp = vec4(camera.up, 0.0f), @@ -436,8 +453,6 @@ namespace Atlas { .frameCount = frameCount }; - lastJitter = jitter; - pathTraceGlobalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); @@ -460,7 +475,6 @@ namespace Atlas { commandList->BindBuffers(renderState->bvhTriangleBuffers, 0, 2); } - Graphics::Profiler::EndQuery(); // No probe filtering required @@ -471,7 +485,16 @@ namespace Atlas { pathTracingRenderer.Render(target, scene, ivec2(1, 1), commandList); if (pathTracingRenderer.realTime) { - taaRenderer.Render(target, scene, commandList); + if (scene->postProcessing.fsr2) { + gBufferRenderer.GenerateReactiveMask(target, commandList); + + fsr2Renderer.Render(target, scene, commandList); + } + else { + taaRenderer.Render(target, scene, commandList); + } + + target->Swap(); postProcessRenderer.Render(target, scene, commandList, texture); } @@ -481,7 +504,7 @@ namespace Atlas { if (device->swapChain->isComplete) { commandList->BeginRenderPass(device->swapChain, true); - textureRenderer.RenderTexture2D(commandList, viewport, &target->texture, + textureRenderer.RenderTexture2D(commandList, viewport, &target->outputTexture, 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0f, 1.0f, false, true); commandList->EndRenderPass(); @@ -562,7 +585,6 @@ namespace Atlas { } - commandList->EndRenderPass(); imageBarriers = { @@ -944,6 +966,7 @@ namespace Atlas { .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, .ipvMatrixLast = glm::inverse(camera.GetLastJitteredMatrix()), .ipvMatrixCurrent = glm::inverse(camera.projectionMatrix * camera.viewMatrix), + .vMatrixLast = camera.GetLastViewMatrix(), .jitterLast = camera.GetLastJitter(), .jitterCurrent = camera.GetJitter(), .cameraLocation = vec4(camera.GetLocation(), 0.0f), @@ -969,8 +992,6 @@ namespace Atlas { auto volume = scene->irradianceVolume; if (volume->scroll) { - //auto pos = vec3(0.4f, 12.7f, -43.0f); - //auto pos = glm::vec3(30.0f, 25.0f, 0.0f); auto pos = camera.GetLocation(); auto volumeSize = volume->aabb.GetSize(); diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index b60e2a59c..e1ef0aa9a 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -48,7 +48,7 @@ namespace Atlas { void RenderScene(Ref viewport, Ref target, Ref scene, Ref primitiveBatch = nullptr, Texture::Texture2D* texture = nullptr); - void PathTraceScene(Ref viewport, Ref target, + void PathTraceScene(Ref viewport, Ref target, Ref scene, Texture::Texture2D* texture = nullptr); void RenderPrimitiveBatch(Ref viewport, Ref target, diff --git a/src/engine/renderer/PathTracingRenderer.cpp b/src/engine/renderer/PathTracingRenderer.cpp index f90f21612..df77d5fbb 100644 --- a/src/engine/renderer/PathTracingRenderer.cpp +++ b/src/engine/renderer/PathTracingRenderer.cpp @@ -26,7 +26,7 @@ namespace Atlas { } - void PathTracingRenderer::Render(Ref renderTarget, Ref scene, + void PathTracingRenderer::Render(Ref renderTarget, Ref scene, ivec2 imageSubdivisions, Graphics::CommandList* commandList) { if (!scene->IsRtDataValid()) @@ -35,8 +35,8 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Path tracing"); auto& camera = scene->GetMainCamera(); - auto width = renderTarget->GetWidth(); - auto height = renderTarget->GetHeight(); + auto width = renderTarget->GetScaledWidth(); + auto height = renderTarget->GetScaledHeight(); auto rayCount = realTime ? 2 * width * height * realTimeSamplesPerFrame : 2 * width * height; @@ -56,7 +56,6 @@ namespace Atlas { imageSubdivisions = ivec2(1); sampleCount = 0; frameCount++; - renderTarget->Swap(); } rayGenPipelineConfig.ManageMacro("REALTIME", realTime); @@ -101,44 +100,59 @@ namespace Atlas { std::vector imageBarriers; std::vector bufferBarriers; - imageBarriers.push_back({ renderTarget->texture.image, + imageBarriers.push_back({ renderTarget->outputTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); imageBarriers.push_back({ renderTarget->radianceTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); imageBarriers.push_back({ renderTarget->historyRadianceTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT }); + auto rtData = renderTarget->GetData(FULL_RES); + auto velocityTexture = rtData->velocityTexture; + auto depthTexture = rtData->depthTexture; + auto normalTexture = rtData->normalTexture; + auto materialIdxTexture = rtData->materialIdxTexture; + auto baseColorTexture = rtData->baseColorTexture; + + auto historyRtData = renderTarget->GetHistoryData(FULL_RES); + auto historyDepthTexture = historyRtData->depthTexture; + auto historyNormalTexture = historyRtData->normalTexture; + auto historyMaterialIdxTexture = historyRtData->materialIdxTexture; + if (!realTime) { - commandList->BindImage(renderTarget->texture.image, 3, 1); + commandList->BindImage(renderTarget->outputTexture.image, 3, 1); commandList->BindImage(renderTarget->radianceTexture.image, 3, 3); commandList->BindImage(renderTarget->historyRadianceTexture.image, 3, 2); } else { + imageBarriers.push_back({ renderTarget->lightingTexture.image, + VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); imageBarriers.push_back({ renderTarget->frameAccumTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); imageBarriers.push_back({ renderTarget->radianceTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); - imageBarriers.push_back({ renderTarget->velocityTexture.image, + imageBarriers.push_back({ velocityTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); - imageBarriers.push_back({ renderTarget->depthTexture.image, + imageBarriers.push_back({ depthTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); - imageBarriers.push_back({ renderTarget->normalTexture.image, + imageBarriers.push_back({ normalTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); - imageBarriers.push_back({ renderTarget->materialIdxTexture.image, + imageBarriers.push_back({ materialIdxTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); - imageBarriers.push_back({ renderTarget->albedoTexture.image, + imageBarriers.push_back({ baseColorTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); + commandList->BindImage(renderTarget->lightingTexture.image, 3, 0); commandList->BindImage(renderTarget->frameAccumTexture.image, 3, 1); commandList->BindImage(renderTarget->radianceTexture.image, 3, 3); renderTarget->historyRadianceTexture.Bind(commandList, 3, 2); - commandList->BindImage(renderTarget->velocityTexture.image, 3, 5); - commandList->BindImage(renderTarget->depthTexture.image, 3, 6); - commandList->BindImage(renderTarget->normalTexture.image, 3, 7); - commandList->BindImage(renderTarget->materialIdxTexture.image, 3, 8); - commandList->BindImage(renderTarget->albedoTexture.image, 3, 9); + commandList->BindImage(velocityTexture->image, 3, 5); + commandList->BindImage(depthTexture->image, 3, 6); + commandList->BindImage(normalTexture->image, 3, 7); + commandList->BindImage(materialIdxTexture->image, 3, 8); + commandList->BindImage(baseColorTexture->image, 3, 9); } commandList->PipelineBarrier(imageBarriers, bufferBarriers); @@ -178,7 +192,7 @@ namespace Atlas { commandList->ImageMemoryBarrier(renderTarget->frameAccumTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - commandList->ImageMemoryBarrier(renderTarget->velocityTexture.image, VK_IMAGE_LAYOUT_GENERAL, + commandList->ImageMemoryBarrier(velocityTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); Graphics::Profiler::EndAndBeginQuery("Bounce " + std::to_string(i)); @@ -199,34 +213,32 @@ namespace Atlas { imageBarriers.push_back({ renderTarget->frameAccumTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->velocityTexture.image, + imageBarriers.push_back({ velocityTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->depthTexture.image, + imageBarriers.push_back({ depthTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->normalTexture.image, + imageBarriers.push_back({ normalTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->materialIdxTexture.image, + imageBarriers.push_back({ materialIdxTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->albedoTexture.image, + imageBarriers.push_back({ baseColorTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->historyDepthTexture.image, + imageBarriers.push_back({ historyDepthTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->historyNormalTexture.image, + imageBarriers.push_back({ historyNormalTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ renderTarget->historyMaterialIdxTexture.image, + imageBarriers.push_back({ historyMaterialIdxTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); commandList->PipelineBarrier(imageBarriers, bufferBarriers); - commandList->BindImage(renderTarget->texture.image, 3, 0); - - renderTarget->velocityTexture.Bind(commandList, 3, 4); - renderTarget->depthTexture.Bind(commandList, 3, 5); - renderTarget->normalTexture.Bind(commandList, 3, 6); - renderTarget->materialIdxTexture.Bind(commandList, 3, 7); - renderTarget->historyDepthTexture.Bind(commandList, 3, 9); - renderTarget->historyNormalTexture.Bind(commandList, 3, 10); - renderTarget->historyMaterialIdxTexture.Bind(commandList, 3, 11); + velocityTexture->Bind(commandList, 3, 4); + depthTexture->Bind(commandList, 3, 5); + normalTexture->Bind(commandList, 3, 6); + materialIdxTexture->Bind(commandList, 3, 7); + historyDepthTexture->Bind(commandList, 3, 9); + historyNormalTexture->Bind(commandList, 3, 10); + historyMaterialIdxTexture->Bind(commandList, 3, 11); struct alignas(16) PushConstants { float historyClipMax; @@ -274,13 +286,11 @@ namespace Atlas { if (imageOffset.y == imageSubdivisions.y) { imageOffset.y = 0; sampleCount++; - - // We don't want to swap already here when rendering in realtime - if (!realTime) - renderTarget->Swap(); } - commandList->ImageTransition(renderTarget->texture.image, + commandList->ImageTransition(renderTarget->outputTexture.image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); + commandList->ImageTransition(renderTarget->lightingTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); commandList->ImageTransition(renderTarget->radianceTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); diff --git a/src/engine/renderer/PathTracingRenderer.h b/src/engine/renderer/PathTracingRenderer.h index 8a68b5b57..463f18afa 100644 --- a/src/engine/renderer/PathTracingRenderer.h +++ b/src/engine/renderer/PathTracingRenderer.h @@ -19,7 +19,7 @@ namespace Atlas { void Init(Graphics::GraphicsDevice* device); - void Render(Ref renderTarget, Ref scene, + void Render(Ref renderTarget, Ref scene, ivec2 imageSubdivisions, Graphics::CommandList* commandList); bool UpdateData(Scene::Scene* scene); diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index ec5ac1cc0..cc3a23ec5 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -180,116 +180,6 @@ namespace Atlas { } - void PostProcessRenderer::Render(Ref target, Ref scene, - Graphics::CommandList* commandList, Texture::Texture2D* texture) { - - Graphics::Profiler::BeginQuery("Postprocessing"); - - auto& postProcessing = scene->postProcessing; - - auto& camera = scene->GetMainCamera(); - const auto& chromaticAberration = postProcessing.chromaticAberration; - const auto& vignette = postProcessing.vignette; - const auto& taa = postProcessing.taa; - auto& sharpen = postProcessing.sharpen; - auto& bloom = postProcessing.bloom; - - ivec2 resolution = ivec2(target->GetWidth(), target->GetHeight()); - - if (sharpen.enable && !postProcessing.fsr2) { - Graphics::Profiler::BeginQuery("Sharpen"); - - auto pipeline = PipelineManager::GetPipeline(sharpenPipelineConfig); - - commandList->BindPipeline(pipeline); - - ivec2 groupCount = resolution / 8; - groupCount.x += ((groupCount.x * 8 == resolution.x) ? 0 : 1); - groupCount.y += ((groupCount.y * 8 == resolution.y) ? 0 : 1); - - const auto& image = target->historyPostProcessTexture.image; - - commandList->ImageMemoryBarrier(image, VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - - commandList->BindImage(image, 3, 0); - - if (taa.enable) { - target->postProcessTexture.Bind(commandList, 3, 1); - } - else { - target->radianceTexture.Bind(commandList, 3, 1); - } - - // Reduce the sharpening to bring it more in line with FSR2 sharpening - float sharpenFactor = sharpen.factor * 0.5f; - commandList->PushConstants("constants", &sharpenFactor, sizeof(float)); - - commandList->Dispatch(groupCount.x, groupCount.y, 1); - - commandList->ImageMemoryBarrier(image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - Graphics::Profiler::EndQuery(); - } - - { - Graphics::Profiler::BeginQuery("Main"); - - // We can't return here because of the queries - if (device->swapChain->isComplete) { - PipelineConfig pipelineConfig; - - if (!texture) { - commandList->BeginRenderPass(device->swapChain, true); - pipelineConfig = GetMainPipelineConfig(); - } - else { - commandList->BeginRenderPass(target->outputRenderPass, - target->outputFrameBuffer, true); - pipelineConfig = GetMainPipelineConfig(target->outputFrameBuffer); - } - - pipelineConfig.ManageMacro("FILMIC_TONEMAPPING", postProcessing.filmicTonemapping); - pipelineConfig.ManageMacro("VIGNETTE", postProcessing.vignette.enable); - pipelineConfig.ManageMacro("CHROMATIC_ABERRATION", postProcessing.chromaticAberration.enable); - pipelineConfig.ManageMacro("FILM_GRAIN", postProcessing.filmGrain.enable); - - auto pipeline = PipelineManager::GetPipeline(pipelineConfig); - commandList->BindPipeline(pipeline); - - SetUniforms(camera, scene); - - if (sharpen.enable) { - target->historyPostProcessTexture.Bind(commandList, 3, 0); - } - else { - if (taa.enable) { - target->postProcessTexture.Bind(commandList, 3, 0); - } - else { - target->radianceTexture.Bind(commandList, 3, 0); - } - } - commandList->BindBuffer(uniformBuffer, 3, 4); - - commandList->Draw(6, 1, 0, 0); - - commandList->EndRenderPass(); - - if (texture) { - CopyToTexture(&target->outputTexture, texture, commandList); - } - } - - Graphics::Profiler::EndQuery(); - } - - Graphics::Profiler::EndQuery(); - - } - void PostProcessRenderer::GenerateBloom(PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, Texture::Texture2D* bloomTexture, Graphics::CommandList* commandList) { @@ -359,6 +249,7 @@ namespace Atlas { Graphics::Profiler::EndAndBeginQuery("Upsample"); struct PushConstants { + int additive; int mipLevel; float filterSize = 2.0f; }; @@ -383,6 +274,7 @@ namespace Atlas { groupCount.y += ((groupCount.y * 8 == resolutions[i].y) ? 0 : 1); PushConstants constants { + .additive = i != mipLevels - 2 ? 1 : 0, .mipLevel = i + 1, .filterSize = bloom.filterSize, }; diff --git a/src/engine/renderer/PostProcessRenderer.h b/src/engine/renderer/PostProcessRenderer.h index ff553c97e..885966703 100644 --- a/src/engine/renderer/PostProcessRenderer.h +++ b/src/engine/renderer/PostProcessRenderer.h @@ -2,7 +2,6 @@ #include "../System.h" #include "Renderer.h" -#include "PathTracingRenderer.h" namespace Atlas { @@ -18,9 +17,6 @@ namespace Atlas { void Render(Ref target, Ref scene, Graphics::CommandList* commandList, Texture::Texture2D* texture = nullptr); - void Render(Ref target, Ref scene, - Graphics::CommandList* commandList, Texture::Texture2D* texture = nullptr); - private: struct alignas(16) Uniforms { float exposure; diff --git a/src/engine/renderer/RTGIRenderer.cpp b/src/engine/renderer/RTGIRenderer.cpp index 7677c5438..c0ca05810 100644 --- a/src/engine/renderer/RTGIRenderer.cpp +++ b/src/engine/renderer/RTGIRenderer.cpp @@ -135,6 +135,7 @@ namespace Atlas { uniforms.radianceLimit = rtgi->radianceLimit / glm::max(mainCamera.exposure, 0.00001f); uniforms.bias = rtgi->bias; uniforms.frameSeed = frameCount++; + uniforms.sampleCount = rtgi->sampleCount; uniforms.lightSampleCount = rtgi->lightSampleCount; uniforms.textureLevel = rtgi->textureLevel; uniforms.halfRes = target->GetGIResolution() == HALF_RES ? 1 : 0; diff --git a/src/engine/renderer/RTGIRenderer.h b/src/engine/renderer/RTGIRenderer.h index 2c02034e1..0e06db310 100644 --- a/src/engine/renderer/RTGIRenderer.h +++ b/src/engine/renderer/RTGIRenderer.h @@ -23,13 +23,13 @@ namespace Atlas { float radianceLimit; uint32_t frameSeed; float bias; + int32_t sampleCount; int32_t lightSampleCount; int32_t textureLevel; float roughnessCutoff; int32_t halfRes; int32_t padding0; int32_t padding1; - int32_t padding2; ivec2 resolution; Shadow shadow; }; diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index 6b863f998..e04afe1ac 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -130,6 +130,7 @@ namespace Atlas { uniforms.bias = reflection->bias; uniforms.roughnessCutoff = reflection->roughnessCutoff; uniforms.frameSeed = frameCount++; + uniforms.sampleCount = reflection->sampleCount; uniforms.lightSampleCount = reflection->lightSampleCount; uniforms.textureLevel = reflection->textureLevel; uniforms.halfRes = target->GetReflectionResolution() == HALF_RES ? 1 : 0; diff --git a/src/engine/renderer/RTReflectionRenderer.h b/src/engine/renderer/RTReflectionRenderer.h index 3801f69b1..8c0be4e0e 100644 --- a/src/engine/renderer/RTReflectionRenderer.h +++ b/src/engine/renderer/RTReflectionRenderer.h @@ -23,13 +23,13 @@ namespace Atlas { float radianceLimit; uint32_t frameSeed; float bias; + int32_t sampleCount; int32_t lightSampleCount; int32_t textureLevel; float roughnessCutoff; int32_t halfRes; int32_t padding0; int32_t padding1; - int32_t padding2; ivec2 resolution; Shadow shadow; }; diff --git a/src/engine/renderer/Renderer.h b/src/engine/renderer/Renderer.h index 11f695d7e..ce8a511e8 100644 --- a/src/engine/renderer/Renderer.h +++ b/src/engine/renderer/Renderer.h @@ -2,7 +2,6 @@ #include "../System.h" #include "target/RenderTarget.h" -#include "target/PathTraceRenderTarget.h" #include "../scene/Scene.h" #include "../Viewport.h" #include "../pipeline/PipelineManager.h" diff --git a/src/engine/renderer/TemporalAARenderer.cpp b/src/engine/renderer/TemporalAARenderer.cpp index cdcf0a5ce..44c8e62b6 100644 --- a/src/engine/renderer/TemporalAARenderer.cpp +++ b/src/engine/renderer/TemporalAARenderer.cpp @@ -77,71 +77,6 @@ namespace Atlas { } - void TemporalAARenderer::Render(Ref target, Ref scene, Graphics::CommandList* commandList) { - - pipelineConfig.ManageMacro("PATHTRACE", true); - - const auto output = &target->postProcessTexture; - const auto history = &target->historyPostProcessTexture; - const auto lastVelocity = &target->historyVelocityTexture; - auto const velocity = &target->velocityTexture; - auto const depth = &target->depthTexture; - - std::vector bufferBarriers; - std::vector imageBarriers; - imageBarriers.push_back({ output->image,VK_IMAGE_LAYOUT_GENERAL,VK_ACCESS_SHADER_WRITE_BIT }); - imageBarriers.push_back({ history->image,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,VK_ACCESS_SHADER_READ_BIT }); - imageBarriers.push_back({ lastVelocity->image,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,VK_ACCESS_SHADER_READ_BIT }); - commandList->PipelineBarrier(imageBarriers, bufferBarriers); - - PushConstants constants = { - .resetHistory = false - }; - Render(output, &target->radianceTexture, history, velocity, lastVelocity, depth, - nullptr, constants, commandList); - - commandList->ImageMemoryBarrier(output->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - } - - void TemporalAARenderer::Render(const Texture::Texture2D* outputTexture, const Texture::Texture2D* currentTexture, const Texture::Texture2D* historyTexture, - const Texture::Texture2D* velocityTexture, const Texture::Texture2D* historyVelocityTexture, const Texture::Texture2D* depthTexture, - const Texture::Texture2D* stencilTexture, PushConstants& constants, Graphics::CommandList* commandList) { - - Graphics::Profiler::BeginQuery("TAA"); - - auto pipeline = PipelineManager::GetPipeline(pipelineConfig); - commandList->BindPipeline(pipeline); - - auto res = ivec2(outputTexture->width, outputTexture->height); - - const int32_t groupSize = 8; - ivec2 groupCount = res / groupSize; - groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); - groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - - commandList->BindImage(outputTexture->image, 3, 0); - commandList->BindImage(historyTexture->image, historyTexture->sampler, 3, 1); - commandList->BindImage(currentTexture->image, currentTexture->sampler, 3, 2); - commandList->BindImage(velocityTexture->image, velocityTexture->sampler, 3, 3); - commandList->BindImage(depthTexture->image, depthTexture->sampler, 3, 4); - commandList->BindImage(historyVelocityTexture->image, historyVelocityTexture->sampler, 3, 5); - - if (stencilTexture != nullptr) - commandList->BindImage(stencilTexture->image, stencilTexture->sampler, 3, 6); - - constants.resolution = vec2((float)outputTexture->width, (float)outputTexture->height); - constants.invResolution = 1.0f / vec2((float)outputTexture->width, (float)outputTexture->height); - - commandList->PushConstants("constants", &constants); - - commandList->Dispatch(groupCount.x, groupCount.y, 1); - - Graphics::Profiler::EndQuery(); - - } - } } \ No newline at end of file diff --git a/src/engine/renderer/TemporalAARenderer.h b/src/engine/renderer/TemporalAARenderer.h index ad1d56a1a..cd09d64b6 100644 --- a/src/engine/renderer/TemporalAARenderer.h +++ b/src/engine/renderer/TemporalAARenderer.h @@ -2,7 +2,6 @@ #include "../System.h" #include "Renderer.h" -#include "PathTracingRenderer.h" namespace Atlas { @@ -17,8 +16,6 @@ namespace Atlas { void Render(Ref target, Ref scene, Graphics::CommandList* commandList); - void Render(Ref target, Ref scene, Graphics::CommandList* commandList); - private: struct alignas(16) PushConstants { vec2 resolution; @@ -27,10 +24,6 @@ namespace Atlas { int32_t resetHistory; }; - void Render(const Texture::Texture2D* outputTexture, const Texture::Texture2D* currentTexture, const Texture::Texture2D* historyTexture, - const Texture::Texture2D* velocityTexture, const Texture::Texture2D* historyVelocityTexture, const Texture::Texture2D* depthTexture, - const Texture::Texture2D* stencilTexture, PushConstants& constants, Graphics::CommandList* commandList); - PipelineConfig pipelineConfig; }; diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index ab9b18689..76522fff5 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -103,6 +103,7 @@ namespace Atlas { mat4 pvMatrixCurrent; mat4 ipvMatrixLast; mat4 ipvMatrixCurrent; + mat4 vMatrixLast; vec2 jitterLast; vec2 jitterCurrent; vec4 cameraLocation; diff --git a/src/engine/renderer/target/PathTraceRenderTarget.cpp b/src/engine/renderer/target/PathTraceRenderTarget.cpp deleted file mode 100644 index 731a78328..000000000 --- a/src/engine/renderer/target/PathTraceRenderTarget.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "PathTraceRenderTarget.h" - -namespace Atlas::Renderer { - - PathTracerRenderTarget::PathTracerRenderTarget(int32_t width, int32_t height) : width(width), height(height) { - - auto graphicsDevice = Graphics::GraphicsDevice::DefaultDevice; - - texture = Texture::Texture2D(width, height, VK_FORMAT_R8G8B8A8_UNORM, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - - frameAccumTexture = Texture::Texture2DArray(width, height, 3, VK_FORMAT_R32_UINT); - - albedoTexture = Texture::Texture2D(width, height, VK_FORMAT_R8G8B8A8_UNORM); - - velocityTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16_SFLOAT); - historyVelocityTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16_SFLOAT); - - depthTexture = Texture::Texture2D(width, height, VK_FORMAT_R32_SFLOAT); - historyDepthTexture = Texture::Texture2D(width, height, VK_FORMAT_R32_SFLOAT); - - normalTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16_SFLOAT); - historyNormalTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16_SFLOAT); - - materialIdxTexture = Texture::Texture2D(width, height, VK_FORMAT_R16_UINT); - historyMaterialIdxTexture = Texture::Texture2D(width, height, VK_FORMAT_R16_UINT); - - radianceTexture = Texture::Texture2D(width, height, VK_FORMAT_R32G32B32A32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - historyRadianceTexture = Texture::Texture2D(width, height, VK_FORMAT_R32G32B32A32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - - postProcessTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - historyPostProcessTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - - outputTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - - { - Graphics::RenderPassColorAttachment colorAttachments[] = { - {.imageFormat = outputTexture.format} - }; - for (auto& attachment : colorAttachments) { - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - auto outputPassDesc = Graphics::RenderPassDesc{ - .colorAttachments = {colorAttachments[0]} - }; - outputRenderPass = graphicsDevice->CreateRenderPass(outputPassDesc); - } - - CreateFramebuffers(); - - } - - void PathTracerRenderTarget::Resize(int32_t width, int32_t height) { - this->width = width; - this->height = height; - - texture.Resize(width, height); - - frameAccumTexture.Resize(width, height, 3); - - albedoTexture.Resize(width, height); - - velocityTexture.Resize(width, height); - historyVelocityTexture.Resize(width, height); - - depthTexture.Resize(width, height); - historyDepthTexture.Resize(width, height); - - normalTexture.Resize(width, height); - historyNormalTexture.Resize(width, height); - - materialIdxTexture.Resize(width, height); - historyMaterialIdxTexture.Resize(width, height); - - radianceTexture.Resize(width, height); - historyRadianceTexture.Resize(width, height); - - postProcessTexture.Resize(width, height); - historyPostProcessTexture.Resize(width, height); - - outputTexture.Resize(width, height); - - CreateFramebuffers(); - - } - - void PathTracerRenderTarget::Swap() { - - std::swap(radianceTexture, historyRadianceTexture); - std::swap(velocityTexture, historyVelocityTexture); - std::swap(depthTexture, historyDepthTexture); - std::swap(normalTexture, historyNormalTexture); - std::swap(materialIdxTexture, historyMaterialIdxTexture); - std::swap(postProcessTexture, historyPostProcessTexture); - - } - - void PathTracerRenderTarget::CreateFramebuffers() { - - auto graphicsDevice = Graphics::GraphicsDevice::DefaultDevice; - - auto outputFrameBufferDesc = Graphics::FrameBufferDesc{ - .renderPass = outputRenderPass, - .colorAttachments = { - {outputTexture.image, 0, true} - }, - .extent = {uint32_t(width), uint32_t(height)} - }; - outputFrameBuffer = graphicsDevice->CreateFrameBuffer(outputFrameBufferDesc); - - } - -} \ No newline at end of file diff --git a/src/engine/renderer/target/PathTraceRenderTarget.h b/src/engine/renderer/target/PathTraceRenderTarget.h deleted file mode 100644 index c2dcc3a18..000000000 --- a/src/engine/renderer/target/PathTraceRenderTarget.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "System.h" -#include "texture/Texture2D.h" -#include "texture/Texture2DArray.h" -#include "graphics/RenderPass.h" -#include "graphics/Framebuffer.h" - -namespace Atlas::Renderer { - - class PathTracerRenderTarget { - - public: - PathTracerRenderTarget() {} - - PathTracerRenderTarget(int32_t width, int32_t height); - - void Resize(int32_t width, int32_t height); - - void Swap(); - - int32_t GetWidth() const { return width; } - int32_t GetHeight() const { return height; } - - Texture::Texture2D texture; - - Texture::Texture2DArray frameAccumTexture; - - Texture::Texture2D albedoTexture; - Texture::Texture2D velocityTexture; - Texture::Texture2D depthTexture; - Texture::Texture2D normalTexture; - Texture::Texture2D materialIdxTexture; - - Texture::Texture2D historyVelocityTexture; - Texture::Texture2D historyDepthTexture; - Texture::Texture2D historyNormalTexture; - Texture::Texture2D historyMaterialIdxTexture; - - Texture::Texture2D radianceTexture; - Texture::Texture2D historyRadianceTexture; - - Texture::Texture2D postProcessTexture; - Texture::Texture2D historyPostProcessTexture; - - Texture::Texture2D outputTexture; - - Ref outputRenderPass; - Ref outputFrameBuffer; - - int32_t sampleCount = 0; - - private: - void CreateFramebuffers(); - - int32_t width = 0; - int32_t height = 0; - - }; - -} \ No newline at end of file diff --git a/src/engine/renderer/target/RenderTarget.cpp b/src/engine/renderer/target/RenderTarget.cpp index 10163aa00..ebf9dcf4a 100644 --- a/src/engine/renderer/target/RenderTarget.cpp +++ b/src/engine/renderer/target/RenderTarget.cpp @@ -40,102 +40,13 @@ namespace Atlas::Renderer { oceanStencilTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R8_UINT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); - { - Graphics::RenderPassColorAttachment colorAttachments[] = { - {.imageFormat = targetData.baseColorTexture->format}, - {.imageFormat = targetData.normalTexture->format}, - {.imageFormat = targetData.geometryNormalTexture->format}, - {.imageFormat = targetData.roughnessMetallicAoTexture->format}, - {.imageFormat = targetData.materialIdxTexture->format}, - {.imageFormat = targetData.velocityTexture->format}, - {.imageFormat = targetData.stencilTexture->format}, - }; - - for (auto &attachment: colorAttachments) { - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - Graphics::RenderPassDepthAttachment depthAttachment = { - .imageFormat = targetData.depthTexture->format, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }; - - auto gBufferRenderPassDesc = Graphics::RenderPassDesc{ - .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2], - colorAttachments[3], colorAttachments[4], colorAttachments[5], colorAttachments[6]}, - .depthAttachment = depthAttachment - }; - gBufferRenderPass = graphicsDevice->CreateRenderPass(gBufferRenderPassDesc); - } - { - Graphics::RenderPassColorAttachment colorAttachments[] = { - {.imageFormat = lightingTexture.format}, - {.imageFormat = targetData.velocityTexture->format}, - {.imageFormat = targetData.stencilTexture->format}, - }; - - for (auto &attachment: colorAttachments) { - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - Graphics::RenderPassDepthAttachment depthAttachment = { - .imageFormat = targetData.depthTexture->format, - .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, - .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }; - - auto afterLightingRenderPassDesc = Graphics::RenderPassDesc{ - .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2]}, - .depthAttachment = depthAttachment - }; - afterLightingRenderPass = graphicsDevice->CreateRenderPass(afterLightingRenderPassDesc); - } - { - Graphics::RenderPassColorAttachment colorAttachments[] = { - {.imageFormat = oceanStencilTexture.format} - }; - for (auto &attachment: colorAttachments) { - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - Graphics::RenderPassDepthAttachment depthAttachment = { - .imageFormat = oceanDepthTexture.format, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }; - - auto oceanRenderPassDesc = Graphics::RenderPassDesc { - .colorAttachments = {colorAttachments[0]}, - .depthAttachment = depthAttachment - }; - oceanRenderPass = graphicsDevice->CreateRenderPass(oceanRenderPassDesc); - } - - { - Graphics::RenderPassColorAttachment colorAttachments[] = { - {.imageFormat = outputTexture.format} - }; - for (auto &attachment: colorAttachments) { - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - auto outputPassDesc = Graphics::RenderPassDesc { - .colorAttachments = {colorAttachments[0]} - }; - outputRenderPass = graphicsDevice->CreateRenderPass(outputPassDesc); - } + radianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + historyRadianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + frameAccumTexture = Texture::Texture2DArray(scaledWidth, scaledHeight, 3, VK_FORMAT_R32_UINT); + CreateRenderPasses(); CreateFrameBuffers(); SetGIResolution(HALF_RES, false); @@ -155,10 +66,7 @@ namespace Atlas::Renderer { // Need to at least have a size of 2x2 pixels scaledWidth = glm::max(2, int32_t(scalingFactor * width)); - scaledHeight = glm::max(2, int32_t(scalingFactor * height)); - - targetData.Resize(ivec2(scaledWidth, scaledHeight)); - targetDataSwap.Resize(ivec2(scaledWidth, scaledHeight)); + scaledHeight = glm::max(2, int32_t(scalingFactor * height)); // We have to also resize the other part of the history historyTexture.Resize(scaledWidth, scaledHeight); @@ -177,11 +85,7 @@ namespace Atlas::Renderer { SetVolumetricResolution(volumetricResolution); SetReflectionResolution(reflectionResolution); - ivec2 halfRes = GetRelativeResolution(HALF_RES); - targetDataDownsampled2x.Resize(halfRes); - targetDataSwapDownsampled2x.Resize(halfRes); - - CreateFrameBuffers(); + UseForPathTracing(useForPathTracing); hasHistory = false; @@ -216,6 +120,8 @@ namespace Atlas::Renderer { hasHistory = true; swap = !swap; + std::swap(historyRadianceTexture, radianceTexture); + CreateFrameBuffers(); } @@ -423,6 +329,150 @@ namespace Atlas::Renderer { } + void RenderTarget::UseForPathTracing(bool use) { + + if (use) { + ivec2 res = GetRelativeResolution(FULL_RES); + targetData = RenderTargetData(res, false); + targetDataSwap = RenderTargetData(res, false); + + targetDataDownsampled2x = RenderTargetData(); + targetDataSwapDownsampled2x = RenderTargetData(); + + radianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + historyRadianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + frameAccumTexture = Texture::Texture2DArray(scaledWidth, scaledHeight, 3, VK_FORMAT_R32_UINT); + } + else { + ivec2 res = GetRelativeResolution(FULL_RES); + targetData = RenderTargetData(res, true); + targetDataSwap = RenderTargetData(res, true); + + ivec2 halfRes = GetRelativeResolution(HALF_RES); + targetDataDownsampled2x = RenderTargetData(halfRes, false); + targetDataSwapDownsampled2x = RenderTargetData(halfRes, false); + + radianceTexture.Reset(); + historyRadianceTexture.Reset(); + frameAccumTexture.Reset(); + } + + CreateFrameBuffers(); + + useForPathTracing = use; + + } + + bool RenderTarget::IsUsedForPathTracing() const { + + return useForPathTracing; + + } + + void RenderTarget::CreateRenderPasses() { + + auto graphicsDevice = Graphics::GraphicsDevice::DefaultDevice; + + { + Graphics::RenderPassColorAttachment colorAttachments[] = { + {.imageFormat = targetData.baseColorTexture->format}, + {.imageFormat = targetData.normalTexture->format}, + {.imageFormat = targetData.geometryNormalTexture->format}, + {.imageFormat = targetData.roughnessMetallicAoTexture->format}, + {.imageFormat = targetData.materialIdxTexture->format}, + {.imageFormat = targetData.velocityTexture->format}, + {.imageFormat = targetData.stencilTexture->format}, + }; + + for (auto& attachment : colorAttachments) { + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + Graphics::RenderPassDepthAttachment depthAttachment = { + .imageFormat = targetData.depthTexture->format, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }; + + auto gBufferRenderPassDesc = Graphics::RenderPassDesc{ + .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2], + colorAttachments[3], colorAttachments[4], colorAttachments[5], colorAttachments[6]}, + .depthAttachment = depthAttachment + }; + gBufferRenderPass = graphicsDevice->CreateRenderPass(gBufferRenderPassDesc); + } + { + Graphics::RenderPassColorAttachment colorAttachments[] = { + {.imageFormat = lightingTexture.format}, + {.imageFormat = targetData.velocityTexture->format}, + {.imageFormat = targetData.stencilTexture->format}, + }; + + for (auto& attachment : colorAttachments) { + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + Graphics::RenderPassDepthAttachment depthAttachment = { + .imageFormat = targetData.depthTexture->format, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }; + + auto afterLightingRenderPassDesc = Graphics::RenderPassDesc{ + .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2]}, + .depthAttachment = depthAttachment + }; + afterLightingRenderPass = graphicsDevice->CreateRenderPass(afterLightingRenderPassDesc); + } + { + Graphics::RenderPassColorAttachment colorAttachments[] = { + {.imageFormat = oceanStencilTexture.format} + }; + for (auto& attachment : colorAttachments) { + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + Graphics::RenderPassDepthAttachment depthAttachment = { + .imageFormat = oceanDepthTexture.format, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }; + + auto oceanRenderPassDesc = Graphics::RenderPassDesc{ + .colorAttachments = {colorAttachments[0]}, + .depthAttachment = depthAttachment + }; + oceanRenderPass = graphicsDevice->CreateRenderPass(oceanRenderPassDesc); + } + + { + Graphics::RenderPassColorAttachment colorAttachments[] = { + {.imageFormat = outputTexture.format} + }; + for (auto& attachment : colorAttachments) { + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.outputLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + auto outputPassDesc = Graphics::RenderPassDesc{ + .colorAttachments = {colorAttachments[0]} + }; + outputRenderPass = graphicsDevice->CreateRenderPass(outputPassDesc); + } + + } + void RenderTarget::CreateFrameBuffers() { auto graphicsDevice = Graphics::GraphicsDevice::DefaultDevice; diff --git a/src/engine/renderer/target/RenderTarget.h b/src/engine/renderer/target/RenderTarget.h index f6c111bfe..ec344799c 100644 --- a/src/engine/renderer/target/RenderTarget.h +++ b/src/engine/renderer/target/RenderTarget.h @@ -2,6 +2,7 @@ #include "System.h" #include "texture/Texture2D.h" +#include "texture/Texture2DArray.h" #include "graphics/RenderPass.h" #include "graphics/Framebuffer.h" @@ -182,6 +183,10 @@ namespace Atlas::Renderer { float GetScalingFactor() const; + void UseForPathTracing(bool use); + + bool IsUsedForPathTracing() const; + Ref gBufferRenderPass; Ref gBufferFrameBuffer; @@ -230,11 +235,19 @@ namespace Atlas::Renderer { Texture::Texture2D reflectionMomentsTexture; Texture::Texture2D historyReflectionMomentsTexture; + Texture::Texture2D radianceTexture; + Texture::Texture2D historyRadianceTexture; + Texture::Texture2DArray frameAccumTexture; + Texture::Texture2D lightingTexture; Texture::Texture2D reactiveMaskTexture; Texture::Texture2D hdrTexture; + int32_t sampleCount = 0; + private: + void CreateRenderPasses(); + void CreateFrameBuffers(); Texture::Texture2D historyTexture; @@ -260,6 +273,7 @@ namespace Atlas::Renderer { bool swap = false; bool hasHistory = false; + bool useForPathTracing = false; }; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index eda00c066..29fc84c23 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -369,6 +369,8 @@ namespace Atlas::Scene { auto lightSubset = scene->GetSubset(); for (auto& lightEntity : lightSubset) { auto& light = lightEntity.GetComponent(); + if (!light.IsVisible(camera.frustum)) + continue; lightEntities.emplace_back(LightEntity{ lightEntity, light, -1 }); } diff --git a/src/engine/scene/components/CameraComponent.cpp b/src/engine/scene/components/CameraComponent.cpp index 056e47758..0a80657bc 100644 --- a/src/engine/scene/components/CameraComponent.cpp +++ b/src/engine/scene/components/CameraComponent.cpp @@ -110,6 +110,12 @@ namespace Atlas { } + mat4 CameraComponent::GetLastViewMatrix() const { + + return lastViewMatrix; + + } + vec3 CameraComponent::GetLocation() const { return vec3(invViewMatrix[3]); diff --git a/src/engine/scene/components/CameraComponent.h b/src/engine/scene/components/CameraComponent.h index da3ccbeed..396931725 100644 --- a/src/engine/scene/components/CameraComponent.h +++ b/src/engine/scene/components/CameraComponent.h @@ -29,6 +29,8 @@ namespace Atlas { mat4 GetLastJitteredMatrix() const; + mat4 GetLastViewMatrix() const; + vec3 GetLocation() const; vec3 GetLastLocation() const; diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index e0d422d17..bf6523d4e 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -68,10 +68,27 @@ namespace Atlas { AE_ASSERT(type == LightType::PointLight && "Component must be of type point light"); - shadow = CreateRef(0.0f, bias, resolution, 0.0f, true); + shadow = CreateRef(transformedProperties.point.radius, bias, resolution, 0.005f, true); } + bool LightComponent::IsVisible(const Volume::Frustum& frustum) const { + + if (type == LightType::DirectionalLight) + return true; + + Volume::AABB aabb; + + if (type == LightType::PointLight) { + auto min = transformedProperties.point.position - vec3(transformedProperties.point.radius); + auto max = transformedProperties.point.position + vec3(transformedProperties.point.radius); + aabb = Volume::AABB(min, max); + } + + return frustum.Intersects(aabb); + + } + void LightComponent::Update(const TransformComponent* transform) { transformedProperties = properties; diff --git a/src/engine/scene/components/LightComponent.h b/src/engine/scene/components/LightComponent.h index a1e906fdf..f73ea815f 100644 --- a/src/engine/scene/components/LightComponent.h +++ b/src/engine/scene/components/LightComponent.h @@ -34,7 +34,7 @@ namespace Atlas { struct PointLightProperties { vec3 position = vec3(0.0f); float radius = 10.0f; - float attenuation = 1.0f; + float attenuation = 2.0f; }; struct TypeProperties { @@ -69,6 +69,8 @@ namespace Atlas { void AddPointShadow(float bias, int32_t resolution); + bool IsVisible(const Volume::Frustum& frustum) const; + LightType type = LightType::DirectionalLight; LightMobility mobility = LightMobility::MovableLight; diff --git a/src/tests/App.cpp b/src/tests/App.cpp index 9bce3d9ca..5f20fca7f 100644 --- a/src/tests/App.cpp +++ b/src/tests/App.cpp @@ -18,7 +18,6 @@ void App::LoadContent(AppConfiguration config) { // Use lower resolution, we care only about correctness renderTarget = Atlas::CreateRef(320, 240); - pathTraceTarget = Atlas::CreateRef(320, 240); viewport = Atlas::CreateRef(0, 0, renderTarget->GetWidth(), renderTarget->GetHeight()); @@ -233,12 +232,14 @@ void App::Render(float deltaTime) { window.Maximize(); } + viewport->Set(0, 0, renderTarget->GetWidth(), renderTarget->GetHeight()); + if (config.exampleRenderer) { exampleRenderer.Render(camera); } else if (pathTrace) { - viewport->Set(0, 0, pathTraceTarget->GetWidth(), pathTraceTarget->GetHeight()); - mainRenderer->PathTraceScene(viewport, pathTraceTarget, scene); + + mainRenderer->PathTraceScene(viewport, renderTarget, scene); } else { mainRenderer->RenderScene(viewport, renderTarget, scene); @@ -385,7 +386,6 @@ void App::CheckLoadScene() { void App::SetResolution(int32_t width, int32_t height) { renderTarget->Resize(width, height); - pathTraceTarget->Resize(width, height); } diff --git a/src/tests/App.h b/src/tests/App.h index 0b76b65b0..3a0f37d64 100644 --- a/src/tests/App.h +++ b/src/tests/App.h @@ -59,7 +59,6 @@ class App : public Atlas::EngineInstance { void SetResolution(int32_t width, int32_t height); - Ref pathTraceTarget; Ref renderTarget; Ref viewport; From 28b186302dd79f676f38aec564b6e00f8a1962f1 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Wed, 11 Sep 2024 17:40:45 +0200 Subject: [PATCH 33/66] Implemented spot lights --- data/shader/deferred/direct.csh | 16 ++ data/shader/ocean/caustics.csh | 2 +- data/shader/ocean/underwater.csh | 2 +- data/shader/raytracer/common.hsh | 4 +- data/shader/raytracer/direct.hsh | 30 ++- data/shader/raytracer/structures.hsh | 3 +- data/shader/shadow.hsh | 212 ++---------------- data/shader/structures.hsh | 3 +- .../panels/components/LightComponentPanel.cpp | 14 +- src/engine/lighting/Shadow.h | 18 +- src/engine/loader/ModelImporter.cpp | 25 ++- src/engine/renderer/helper/CommonStructures.h | 4 +- .../renderer/helper/RayTracingHelper.cpp | 25 ++- src/engine/scene/SceneRenderState.cpp | 37 ++- .../scene/components/ComponentSerializer.cpp | 20 +- .../scene/components/LightComponent.cpp | 30 ++- src/engine/scene/components/LightComponent.h | 18 +- .../scripting/bindings/SceneBindings.cpp | 14 +- 18 files changed, 232 insertions(+), 245 deletions(-) diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index a7d9d3a64..46e97c9d5 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -103,6 +103,17 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai surface.L = pointToLight / dist; } + else if (lightType == SPOT_LIGHT) { + vec3 pointToLight = light.location.xyz - surface.P; + float sqrDistance = dot(pointToLight, pointToLight); + float dist = sqrt(sqrDistance); + + surface.L = pointToLight / dist; + + float strength = dot(surface.L, normalize(-light.direction.xyz)); + float attenuation = saturate(strength * light.radius + light.specific); + lightMultiplier = sqr(attenuation) / sqrDistance; + } UpdateSurface(surface); @@ -157,6 +168,11 @@ float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometr shadowFactor = CalculatePointShadow(light.shadow, cubeMaps[nonuniformEXT(light.shadow.mapIdx)], shadowSampler, surface.P); } + else if (lightType == SPOT_LIGHT) { + shadowFactor = CalculateSpotShadow(light.shadow, cascadeMaps[nonuniformEXT(light.shadow.mapIdx)], + shadowSampler, surface.P, vec3(vec2(pixel) + 0.5, 0.0), + shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); + } if (isMain) { #ifdef CLOUD_SHADOWS diff --git a/data/shader/ocean/caustics.csh b/data/shader/ocean/caustics.csh index b64c7534f..ffac818b8 100644 --- a/data/shader/ocean/caustics.csh +++ b/data/shader/ocean/caustics.csh @@ -1,6 +1,6 @@ layout (local_size_x = 8, local_size_y = 8) in; -#define SHADOW_FILTER_3x3 +#define SHADOW_FILTER_VOGEL #include <../structures.hsh> #include <../shadow.hsh> diff --git a/data/shader/ocean/underwater.csh b/data/shader/ocean/underwater.csh index 60bf8b067..c414e48cc 100644 --- a/data/shader/ocean/underwater.csh +++ b/data/shader/ocean/underwater.csh @@ -1,6 +1,6 @@ layout (local_size_x = 8, local_size_y = 8) in; -#define SHADOW_FILTER_3x3 +#define SHADOW_FILTER_VOGEL #include #include diff --git a/data/shader/raytracer/common.hsh b/data/shader/raytracer/common.hsh index 9d8a71045..8e16b81c4 100644 --- a/data/shader/raytracer/common.hsh +++ b/data/shader/raytracer/common.hsh @@ -11,6 +11,7 @@ #define DIRECTIONAL_LIGHT 0 #define TRIANGLE_LIGHT 1 #define POINT_LIGHT 2 +#define SPOT_LIGHT 3 #define INSTANCE_MASK_ALL (1 << 7) #define INSTANCE_MASK_SHADOW (1 << 6) @@ -116,7 +117,8 @@ Light UnpackLight(PackedLight compressed) { light.pdf = compressed.data.y; light.area = compressed.data.z; light.radius = compressed.data.z; - light.attenuation = compressed.data.w; + light.angleScale = compressed.data.z; + light.angleOffset = compressed.data.w; light.brightness = dot(light.radiance, vec3(0.33333)); return light; diff --git a/data/shader/raytracer/direct.hsh b/data/shader/raytracer/direct.hsh index a781d3e42..1d2f894fc 100644 --- a/data/shader/raytracer/direct.hsh +++ b/data/shader/raytracer/direct.hsh @@ -24,7 +24,7 @@ Light GetLight(Surface surface, float seed0, float seed1, out float lightPdf) { float sqrDistance = dot(pointToLight, pointToLight); float lightDistance = sqrt(sqrDistance); - vec3 L = normalize(pointToLight); + vec3 L = pointToLight / lightDistance; float NdotL = max(dot(light.N, -L), 0.0); weight = light.brightness * light.area * NdotL / sqrDistance; @@ -39,6 +39,16 @@ Light GetLight(Surface surface, float seed0, float seed1, out float lightPdf) { weight = light.brightness * light.radius / sqrDistance; } + else if (light.type == uint(SPOT_LIGHT)) { + vec3 pointToLight = light.P - surface.P; + float sqrDistance = dot(pointToLight, pointToLight); + float lightDistance = sqrt(sqrDistance); + + vec3 L = pointToLight / lightDistance; + float NdotL = max(dot(light.N, -L), 0.0); + + weight = light.brightness * NdotL / sqrDistance; + } weight = clamp(weight, 0.0000001, 1000000000000.0); totalWeight += weight; @@ -91,13 +101,27 @@ void SampleLight(Light light, inout Surface surface, float seed0, float seed1, solidAngle = 1.0; dist = INF; } - else { + else if (light.type == uint(POINT_LIGHT)) { vec3 pointToLight = light.P - surface.P; float sqrDistance = dot(pointToLight, pointToLight); dist = sqrt(sqrDistance); - solidAngle = saturate(1.0 - pow(dist / light.radius, 4.0)) / sqrDistance; + float attenuation = saturate(1.0 - pow(dist / light.radius, 4.0)); + solidAngle = attenuation / sqrDistance; + + surface.L = pointToLight / dist; + UpdateSurface(surface); + } + else if (light.type == uint(SPOT_LIGHT)) { + vec3 pointToLight = light.P - surface.P; + float sqrDistance = dot(pointToLight, pointToLight); + dist = sqrt(sqrDistance); surface.L = pointToLight / dist; + + float strength = dot(surface.L, normalize(-light.N)); + float attenuation = saturate(strength * light.angleScale + light.angleOffset); + solidAngle = sqr(attenuation) / sqrDistance; + UpdateSurface(surface); } } diff --git a/data/shader/raytracer/structures.hsh b/data/shader/raytracer/structures.hsh index ae1dfb48d..b3b1d89cb 100644 --- a/data/shader/raytracer/structures.hsh +++ b/data/shader/raytracer/structures.hsh @@ -157,7 +157,8 @@ struct Light { float pdf; float area; float radius; - float attenuation; + float angleScale; + float angleOffset; float brightness; }; diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh index 056b58174..dfcc33bde 100644 --- a/data/shader/shadow.hsh +++ b/data/shader/shadow.hsh @@ -119,100 +119,6 @@ float cascadeLookup(Shadow shadow, sampler2DArrayShadow cascadeMaps, float casca #ifdef SHADOW_FILTER_1x1 visibility += offsetLookup(cascadeMaps, shadowCoords.xy, 0.0, 0.0, float(cascadeIndex), resInv, shadowCoords.z, bias); #endif -#ifdef SHADOW_FILTER_3x3 - float uw0 = (3.0 - 2.0 * s); - float uw1 = (1.0 + 2.0 * s); - - float u0 = (2.0 - s) / uw0 - 1.0; - float u1 = s / uw1 + 1.0; - - float vw0 = (3.0 - 2.0 * t); - float vw1 = (1.0 + 2.0 * t); - - float v0 = (2.0 - t) / vw0 - 1.0; - float v1 = t / vw1 + 1.0; - - visibility += uw0 * vw0 * offsetLookup(cascadeMaps, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw0 * offsetLookup(cascadeMaps, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw0 * vw1 * offsetLookup(cascadeMaps, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw1 * offsetLookup(cascadeMaps, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility /= 16.0; -#endif -#ifdef SHADOW_FILTER_5x5 - float uw0 = (4.0 - 3.0 * s); - float uw1 = 7.0; - float uw2 = (1.0 + 3.0 * s); - - float u0 = (3.0 - 2.0 * s) / uw0 - 2.0; - float u1 = (3.0 + s) / uw1; - float u2 = s / uw2 + 2.0; - - float vw0 = (4.0 - 3.0 * t); - float vw1 = 7.0; - float vw2 = (1.0 + 3.0 * t); - - float v0 = (3.0 - 2.0 * t) / vw0 - 2.0; - float v1 = (3.0 + t) / vw1; - float v2 = t / vw2 + 2.0; - - visibility += uw0 * vw0 * offsetLookup(cascadeMaps, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw0 * offsetLookup(cascadeMaps, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw0 * offsetLookup(cascadeMaps, flooredUV, u2, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw1 * offsetLookup(cascadeMaps, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw1 * offsetLookup(cascadeMaps, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw1 * offsetLookup(cascadeMaps, flooredUV, u2, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw2 * offsetLookup(cascadeMaps, flooredUV, u0, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw2 * offsetLookup(cascadeMaps, flooredUV, u1, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw2 * offsetLookup(cascadeMaps, flooredUV, u2, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility /= 144.0; -#endif -#ifdef SHADOW_FILTER_7x7 - float uw0 = (5.0 * s - 6.0); - float uw1 = (11.0 * s - 28.0); - float uw2 = -(11.0 * s + 17.0); - float uw3 = -(5.0 * s + 1.0); - - float u0 = (4.0 * s - 5.0) / uw0 - 3.0; - float u1 = (4.0 * s - 16.0) / uw1 - 1.0; - float u2 = -(7.0 * s + 5.0) / uw2 + 1.0; - float u3 = -s / uw3 + 3.0; - - float vw0 = (5.0 * t - 6.0); - float vw1 = (11.0 * t - 28.0); - float vw2 = -(11.0 * t + 17.0); - float vw3 = -(5.0 * t + 1.0); - - float v0 = (4.0 * t - 5.0) / vw0 - 3.0; - float v1 = (4.0 * t - 16.0) / vw1 - 1.0; - float v2 = -(7.0 * t + 5.0) / vw2 + 1.0; - float v3 = -t / vw3 + 3.0; - - visibility += uw0 * vw0 * offsetLookup(cascadeMaps, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw0 * offsetLookup(cascadeMaps, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw0 * offsetLookup(cascadeMaps, flooredUV, u2, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw0 * offsetLookup(cascadeMaps, flooredUV, u3, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw1 * offsetLookup(cascadeMaps, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw1 * offsetLookup(cascadeMaps, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw1 * offsetLookup(cascadeMaps, flooredUV, u2, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw1 * offsetLookup(cascadeMaps, flooredUV, u3, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw2 * offsetLookup(cascadeMaps, flooredUV, u0, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw2 * offsetLookup(cascadeMaps, flooredUV, u1, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw2 * offsetLookup(cascadeMaps, flooredUV, u2, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw2 * offsetLookup(cascadeMaps, flooredUV, u3, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw3 * offsetLookup(cascadeMaps, flooredUV, u0, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw3 * offsetLookup(cascadeMaps, flooredUV, u1, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw3 * offsetLookup(cascadeMaps, flooredUV, u2, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw3 * offsetLookup(cascadeMaps, flooredUV, u3, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility /= 2704.0; -#endif #ifdef SHADOW_FILTER_VOGEL vec2 texelSize = vec2(shadow.cascades[int(cascadeIndex)].texelSize); @@ -470,110 +376,14 @@ float cascadeLookup(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSa #ifdef SHADOW_FILTER_1x1 visibility += offsetLookup(cascadeMaps, shadowSampler, shadowCoords.xy, 0.0, 0.0, float(cascadeIndex), resInv, shadowCoords.z, bias); #endif -#ifdef SHADOW_FILTER_3x3 - float uw0 = (3.0 - 2.0 * s); - float uw1 = (1.0 + 2.0 * s); - - float u0 = (2.0 - s) / uw0 - 1.0; - float u1 = s / uw1 + 1.0; - - float vw0 = (3.0 - 2.0 * t); - float vw1 = (1.0 + 2.0 * t); - - float v0 = (2.0 - t) / vw0 - 1.0; - float v1 = t / vw1 + 1.0; - - visibility += uw0 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw0 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility /= 16.0; -#endif -#ifdef SHADOW_FILTER_5x5 - float uw0 = (4.0 - 3.0 * s); - float uw1 = 7.0; - float uw2 = (1.0 + 3.0 * s); - - float u0 = (3.0 - 2.0 * s) / uw0 - 2.0; - float u1 = (3.0 + s) / uw1; - float u2 = s / uw2 + 2.0; - - float vw0 = (4.0 - 3.0 * t); - float vw1 = 7.0; - float vw2 = (1.0 + 3.0 * t); - - float v0 = (3.0 - 2.0 * t) / vw0 - 2.0; - float v1 = (3.0 + t) / vw1; - float v2 = t / vw2 + 2.0; - - visibility += uw0 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility /= 144.0; -#endif -#ifdef SHADOW_FILTER_7x7 - float uw0 = (5.0 * s - 6.0); - float uw1 = (11.0 * s - 28.0); - float uw2 = -(11.0 * s + 17.0); - float uw3 = -(5.0 * s + 1.0); - - float u0 = (4.0 * s - 5.0) / uw0 - 3.0; - float u1 = (4.0 * s - 16.0) / uw1 - 1.0; - float u2 = -(7.0 * s + 5.0) / uw2 + 1.0; - float u3 = -s / uw3 + 3.0; - - float vw0 = (5.0 * t - 6.0); - float vw1 = (11.0 * t - 28.0); - float vw2 = -(11.0 * t + 17.0); - float vw3 = -(5.0 * t + 1.0); - - float v0 = (4.0 * t - 5.0) / vw0 - 3.0; - float v1 = (4.0 * t - 16.0) / vw1 - 1.0; - float v2 = -(7.0 * t + 5.0) / vw2 + 1.0; - float v3 = -t / vw3 + 3.0; - - visibility += uw0 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw0 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v0, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw1 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v1, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw2 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v2, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility += uw0 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u0, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw1 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u1, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw2 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u2, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - visibility += uw3 * vw3 * offsetLookup(cascadeMaps, shadowSampler, flooredUV, u3, v3, float(cascadeIndex), resInv, shadowCoords.z, bias); - - visibility /= 2704.0; -#endif - #ifdef SHADOW_FILTER_VOGEL vec2 texelSize = vec2(shadow.cascades[int(cascadeIndex)].texelSize); for (int i = 0; i < 16; i++) { visibility += offsetLookup(cascadeMaps, shadowSampler, uv, float(cascadeIndex), shadow.edgeSoftness, texelSize, resInv, position, i, shadowCoords.z, bias); } - - visibility /= 16.0; #endif + visibility /= 16.0; // Fade out shadow in the distance return clamp(visibility + fadeout, 0.0, 1.0); @@ -698,7 +508,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sample fragmentPosition += bias; float visibility = cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), - cascadeMatrix, fragmentPosition, position, 0.0, true); + cascadeMatrix, fragmentPosition, position, -0.00005, true); #ifdef SHADOW_CASCADE_BLENDING if (cascadeIndex < shadow.cascadeCount - 1) { @@ -736,7 +546,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sample fragmentPosition += bias; visibility = mix(cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), - cascadeMatrix, fragmentPosition, position, 0.0, true), visibility, blend); + cascadeMatrix, fragmentPosition, position, -0.0001, true), visibility, blend); } } #endif @@ -785,4 +595,20 @@ float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSam return shadowFactor; +} + +float CalculateSpotShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, + vec3 fragmentPosition, vec3 position, vec3 normal, float cosTheta) { + + float distance = -fragmentPosition.z; + + mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + float texelSize = shadow.cascades[0].texelSize; + + vec3 bias = shadow.bias * (1.0 / 256.0) * normal / max(cosTheta * cosTheta, 0.01); + fragmentPosition += bias; + + return cascadeLookup(shadow, cascadeMaps, shadowSampler, 0.0, + cascadeMatrix, fragmentPosition, position, -0.0001, false); + } \ No newline at end of file diff --git a/data/shader/structures.hsh b/data/shader/structures.hsh index 3b746981d..ed20f9252 100644 --- a/data/shader/structures.hsh +++ b/data/shader/structures.hsh @@ -2,6 +2,7 @@ #define DIRECTIONAL_LIGHT 0 #define POINT_LIGHT 1 +#define SPOT_LIGHT 2 //Light struct has to be implemented like this struct Light { @@ -15,7 +16,7 @@ struct Light { float scatteringFactor; float radius; - float attenuation; + float specific; Shadow shadow; diff --git a/src/editor/ui/panels/components/LightComponentPanel.cpp b/src/editor/ui/panels/components/LightComponentPanel.cpp index 7b3f23f20..4661c88fe 100644 --- a/src/editor/ui/panels/components/LightComponentPanel.cpp +++ b/src/editor/ui/panels/components/LightComponentPanel.cpp @@ -9,7 +9,7 @@ namespace Atlas::Editor::UI { bool LightComponentPanel::Render(Ref& scene, Scene::Entity entity, LightComponent &lightComponent) { - const char* typeItems[] = { "Directional", "Point" }; + const char* typeItems[] = { "Directional", "Point", "Spot"}; int typeItem = static_cast(lightComponent.type); ImGui::Combo("Light type", &typeItem, typeItems, IM_ARRAYSIZE(typeItems)); lightComponent.type = static_cast(typeItem); @@ -31,7 +31,14 @@ namespace Atlas::Editor::UI { auto& point = lightComponent.properties.point; ImGui::DragFloat3("Position", glm::value_ptr(point.position), 0.1f, -10000.0f, 10000.0f); ImGui::DragFloat("Radius", &point.radius, 0.1f, 0.01f, 10000.0f); - ImGui::DragFloat("Attenuation", &point.attenuation, 0.01f, -0.01f, 10.0f); + } + else if (lightComponent.type == LightType::SpotLight) { + auto& spot = lightComponent.properties.spot; + ImGui::DragFloat3("Position", glm::value_ptr(spot.position), 0.1f, -10000.0f, 10000.0f); + ImGui::DragFloat3("Direction", glm::value_ptr(spot.direction), 0.01f, -1.0f, 1.0f); + ImGui::DragFloat("Radius", &spot.radius, 0.01f, -1.0f, 1.0f); + ImGui::DragFloat("Inner cone angle", &spot.innerConeAngle, 0.01f, 0.01f, 2.0f); + ImGui::DragFloat("Outer cone angle", &spot.outerConeAngle, 0.01f, 0.01f, 2.0f); } ImGui::Separator(); @@ -50,6 +57,9 @@ namespace Atlas::Editor::UI { if (lightComponent.type == LightType::PointLight) { lightComponent.AddPointShadow(0.1f, 1024); } + if (lightComponent.type == LightType::SpotLight) { + lightComponent.AddSpotShadow(0.1f, 1024); + } } else if (lightComponent.shadow && !castShadow) { lightComponent.shadow = nullptr; diff --git a/src/engine/lighting/Shadow.h b/src/engine/lighting/Shadow.h index f71beee16..33d86b52e 100644 --- a/src/engine/lighting/Shadow.h +++ b/src/engine/lighting/Shadow.h @@ -13,16 +13,16 @@ namespace Atlas { struct ShadowView { - float nearDistance; - float farDistance; + float nearDistance = 0.0f; + float farDistance = 100.0f; - mat4 viewMatrix; - mat4 projectionMatrix; + mat4 viewMatrix = mat4(1.0f); + mat4 projectionMatrix = mat4(1.0f); - mat4 frustumMatrix; - mat4 terrainFrustumMatrix; + mat4 frustumMatrix = mat4(1.0f); + mat4 terrainFrustumMatrix = mat4(1.0f); - vec4 orthoSize; + vec4 orthoSize = vec4(1.0f); }; @@ -50,10 +50,10 @@ namespace Atlas { float cascadeBlendDistance = 2.5f; - int32_t resolution; + int32_t resolution = 1024; std::vector views; - int32_t viewCount; + int32_t viewCount = 1; Ref maps; Ref cubemap; diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index d407309c3..7e3dca4b9 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -432,15 +432,30 @@ namespace Atlas { if (lightMap.contains(node->mName.C_Str())) { auto light = lightMap[node->mName.C_Str()]; - if (light->mType == aiLightSource_POINT) { - auto& lightComp = parentEntity.AddComponent(LightType::PointLight, LightMobility::StationaryLight); - lightComp.color = Common::ColorConverter::ConvertLinearToSRGB(vec3(light->mColorDiffuse.r, light->mColorDiffuse.g, light->mColorDiffuse.b)); - lightComp.intensity = std::max(lightComp.color.r, std::max(lightComp.color.g, lightComp.color.b)); - lightComp.color /= std::max(lightComp.intensity, 1e-9f); + auto lightType = LightType::DirectionalLight; + switch (light->mType) { + case aiLightSource_POINT: lightType = LightType::PointLight; break; + case aiLightSource_SPOT: lightType = LightType::SpotLight; break; + default: lightType = LightType::PointLight; break; + } + + auto& lightComp = parentEntity.AddComponent(lightType, LightMobility::StationaryLight); + lightComp.color = Common::ColorConverter::ConvertLinearToSRGB(vec3(light->mColorDiffuse.r, light->mColorDiffuse.g, light->mColorDiffuse.b)); + lightComp.intensity = std::max(lightComp.color.r, std::max(lightComp.color.g, lightComp.color.b)); + lightComp.color /= std::max(lightComp.intensity, 1e-9f); + + if (lightType == LightType::PointLight) { lightComp.properties.point.position = vec3(light->mPosition.x, light->mPosition.y, light->mPosition.z); lightComp.properties.point.radius = glm::sqrt(100.0f * light->mAttenuationQuadratic); lightComp.AddPointShadow(3.0f, 1024); } + if (lightType == LightType::SpotLight) { + lightComp.properties.spot.position = vec3(light->mPosition.x, light->mPosition.y, light->mPosition.z); + lightComp.properties.spot.direction = vec3(light->mDirection.x, light->mDirection.y, light->mDirection.z); + lightComp.properties.spot.innerConeAngle = light->mAngleInnerCone; + lightComp.properties.spot.outerConeAngle = light->mAngleOuterCone; + lightComp.AddSpotShadow(3.0f, 1024); + } } for (uint32_t i = 0; i < node->mNumChildren; i++) { diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index 76522fff5..a94f11002 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -52,8 +52,8 @@ namespace Atlas { float scatteringFactor; - float radius; - float attenuation; + float typeSpecific0; + float typeSpecific1; Shadow shadow; }; diff --git a/src/engine/renderer/helper/RayTracingHelper.cpp b/src/engine/renderer/helper/RayTracingHelper.cpp index 91c31495c..dd51dd5e0 100644 --- a/src/engine/renderer/helper/RayTracingHelper.cpp +++ b/src/engine/renderer/helper/RayTracingHelper.cpp @@ -9,6 +9,7 @@ #define DIRECTIONAL_LIGHT 0 #define TRIANGLE_LIGHT 1 #define POINT_LIGHT 2 +#define SPOT_LIGHT 3 namespace Atlas { @@ -448,11 +449,12 @@ namespace Atlas { vec3 P = vec3(0.0f); vec3 N = vec3(0.0f); float weight = 0.0f; - float area = 0.0f; - float specific = 0.0f; + float specific0 = 0.0f; + float specific1 = 0.0f; uint32_t data = 0; + auto& prop = light.transformedProperties; // Parse individual light information based on type if (light.type == LightType::DirectionalLight) { data |= (DIRECTIONAL_LIGHT << 28u); @@ -463,8 +465,21 @@ namespace Atlas { data |= (POINT_LIGHT << 28u); weight = brightness; P = light.transformedProperties.point.position; - area = light.transformedProperties.point.radius; - specific = light.transformedProperties.point.attenuation; + specific0 = light.transformedProperties.point.radius; + } + else if (light.type == LightType::SpotLight) { + data |= (SPOT_LIGHT << 28u); + weight = brightness; + P = light.transformedProperties.spot.position; + N = light.transformedProperties.spot.direction; + + auto cosOuter = cosf(prop.spot.outerConeAngle); + auto cosInner = cosf(prop.spot.innerConeAngle); + auto lightAngleScale = 1.0f / std::max(0.001f, cosInner - cosOuter); + auto lightAngleOffset = -cosOuter * lightAngleScale; + + specific0 = lightAngleScale; + specific1 = lightAngleOffset; } data |= uint32_t(lights.size()); @@ -474,7 +489,7 @@ namespace Atlas { gpuLight.P = vec4(P, 1.0f); gpuLight.N = vec4(N, 0.0f); gpuLight.color = vec4(radiance, 0.0f); - gpuLight.data = vec4(cd, weight, area, specific); + gpuLight.data = vec4(cd, weight, specific0, specific1); lights.push_back(gpuLight); } diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 29fc84c23..bf8133fdf 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -375,6 +375,15 @@ namespace Atlas::Scene { } if (lightEntities.size() > 1) { + auto cameraLocation = camera.GetLocation(); + auto getPositionForLight = [cameraLocation](const LightEntity& light) -> vec3 { + switch (light.comp.type) { + case LightType::PointLight: return light.comp.transformedProperties.point.position; + case LightType::SpotLight: return light.comp.transformedProperties.spot.position; + default: return cameraLocation; + } + }; + std::sort(lightEntities.begin(), lightEntities.end(), [&](const LightEntity& light0, const LightEntity& light1) { if (light0.comp.isMain) @@ -383,13 +392,8 @@ namespace Atlas::Scene { if (light0.comp.type == LightType::DirectionalLight) return true; - if (light0.comp.type == LightType::PointLight && - light1.comp.type == LightType::PointLight) { - return glm::distance2(light0.comp.transformedProperties.point.position, camera.GetLocation()) - < glm::distance2(light1.comp.transformedProperties.point.position, camera.GetLocation()); - } - - return false; + return glm::distance2(getPositionForLight(light0), cameraLocation) + < glm::distance2(getPositionForLight(light1), cameraLocation); }); } @@ -413,8 +417,19 @@ namespace Atlas::Scene { } else if (light.type == LightType::PointLight) { lightUniform.location = camera.viewMatrix * vec4(prop.point.position, 1.0f); - lightUniform.radius = prop.point.radius; - lightUniform.attenuation = prop.point.attenuation; + lightUniform.typeSpecific0 = prop.point.radius; + } + else if (light.type == LightType::SpotLight) { + lightUniform.location = camera.viewMatrix * vec4(prop.spot.position, 1.0f); + lightUniform.direction = camera.viewMatrix * vec4(prop.spot.direction, 0.0f); + + auto cosOuter = cosf(prop.spot.outerConeAngle); + auto cosInner = cosf(prop.spot.innerConeAngle); + auto angleScale = 1.0f / std::max(0.001f, cosInner - cosOuter); + auto angleOffset = -cosOuter * angleScale; + + lightUniform.typeSpecific0 = angleScale; + lightUniform.typeSpecific1 = angleOffset; } if (light.shadow) { @@ -447,6 +462,10 @@ namespace Atlas::Scene { else shadowUniform.cascades[i].cascadeSpace = glm::translate(mat4(1.0f), -prop.point.position) * camera.invViewMatrix; } + else if (light.type == LightType::SpotLight) { + shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * + cascade->viewMatrix * camera.invViewMatrix; + } shadowUniform.cascades[i].texelSize = texelSize; } else { diff --git a/src/engine/scene/components/ComponentSerializer.cpp b/src/engine/scene/components/ComponentSerializer.cpp index 19bf51467..62ef3fac8 100644 --- a/src/engine/scene/components/ComponentSerializer.cpp +++ b/src/engine/scene/components/ComponentSerializer.cpp @@ -110,8 +110,16 @@ namespace Atlas::Scene::Components { else if (p.type == LightType::PointLight) { typeProperties = json { {"position", p.properties.point.position}, - {"radius", p.properties.point.radius}, - {"attenuation", p.properties.point.attenuation}, + {"radius", p.properties.point.radius} + }; + } + else if (p.type == LightType::SpotLight) { + typeProperties = json{ + {"position", p.properties.spot.position}, + {"direction", p.properties.spot.direction}, + {"radius", p.properties.spot.radius}, + {"outerConeAngle", p.properties.spot.outerConeAngle}, + {"innerConeAngle", p.properties.spot.innerConeAngle}, }; } @@ -153,7 +161,13 @@ namespace Atlas::Scene::Components { else if (p.type == LightType::PointLight) { typeProperties.at("position").get_to(p.properties.point.position); typeProperties.at("radius").get_to(p.properties.point.radius); - typeProperties.at("attenuation").get_to(p.properties.point.attenuation); + } + else if (p.type == LightType::SpotLight) { + typeProperties.at("position").get_to(p.properties.spot.position); + typeProperties.at("direction").get_to(p.properties.spot.direction); + typeProperties.at("radius").get_to(p.properties.spot.radius); + typeProperties.at("outerConeAngle").get_to(p.properties.spot.outerConeAngle); + typeProperties.at("innerConeAngle").get_to(p.properties.spot.innerConeAngle); } if (j.contains("shadow")) { diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index bf6523d4e..88b40f214 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -72,6 +72,14 @@ namespace Atlas { } + void LightComponent::AddSpotShadow(float bias, int32_t resolution) { + + AE_ASSERT(type == LightType::SpotLight && "Component must be of type spot light"); + + shadow = CreateRef(transformedProperties.spot.radius, bias, resolution, 0.005f, false); + + } + bool LightComponent::IsVisible(const Volume::Frustum& frustum) const { if (type == LightType::DirectionalLight) @@ -84,6 +92,9 @@ namespace Atlas { auto max = transformedProperties.point.position + vec3(transformedProperties.point.radius); aabb = Volume::AABB(min, max); } + else if (type == LightType::SpotLight) { + aabb = Volume::AABB(-vec3(2000.0f), vec3(2000.0f)); + } return frustum.Intersects(aabb); @@ -100,6 +111,11 @@ namespace Atlas { else if (type == LightType::PointLight && transform) { transformedProperties.point.position = vec3(transform->globalMatrix * vec4(properties.point.position, 1.0f)); } + else if (type == LightType::SpotLight && transform) { + transformedProperties.spot.position = vec3(transform->globalMatrix * vec4(properties.spot.position, 1.0f)); + transformedProperties.spot.direction = glm::normalize(vec3(transform->globalMatrix * + vec4(properties.spot.direction, 0.0f))); + } } @@ -130,12 +146,12 @@ namespace Atlas { } else if (!shadow->isCascaded && type == LightType::DirectionalLight) { shadow->views[0].viewMatrix = glm::lookAt(shadow->center, - shadow->center + transformedProperties.directional.direction, vec3(0.0f, 1.0f, 0.0f)); + shadow->center + transformedProperties.directional.direction, vec3(1e-12f, 1.0f, 1e-12f)); } else if (type == LightType::PointLight) { vec3 position = transformedProperties.point.position; - mat4 projectionMatrix = clipMatrix * glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, properties.point.radius); + mat4 projectionMatrix = clipMatrix * glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, shadow->distance); vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; @@ -151,6 +167,14 @@ namespace Atlas { shadow->views[i].frustumMatrix = projectionMatrix * viewMatrix; } } + else if (type == LightType::SpotLight) { + auto viewMatrix = glm::lookAt(transformedProperties.spot.position, transformedProperties.spot.position + + transformedProperties.spot.direction, vec3(1e-12f, 1.0f, 1e-12f)); + auto projectionMatrix = glm::perspective(2.0f * transformedProperties.spot.outerConeAngle, 1.0f, 0.1f, shadow->distance); + shadow->views[0].viewMatrix = viewMatrix; + shadow->views[0].projectionMatrix = clipMatrix * projectionMatrix; + shadow->views[0].frustumMatrix = clipMatrix * projectionMatrix * viewMatrix; + } if (mobility == LightMobility::MovableLight) shadow->Update(); @@ -170,7 +194,7 @@ namespace Atlas { // A near enough up vector. This is because if the light location is // (0.0f, 1.0f, 0.0f) the shadows wouldn't render correctly due to the // shadows (or lights) view matrix. This is just a hack - vec3 up = glm::vec3(0.0000000000000001f, 1.0f, 0.0000000000000001f); + vec3 up = vec3(1e-12f, 1.0f, 1e-12f); cascade.viewMatrix = glm::lookAt(cascadeCenter, cascadeCenter + lightDirection, up); std::vector corners = camera.GetFrustumCorners(cascade.nearDistance, diff --git a/src/engine/scene/components/LightComponent.h b/src/engine/scene/components/LightComponent.h index f73ea815f..8d70d902b 100644 --- a/src/engine/scene/components/LightComponent.h +++ b/src/engine/scene/components/LightComponent.h @@ -19,7 +19,8 @@ namespace Atlas { enum class LightType { DirectionalLight = 0, - PointLight = 1 + PointLight = 1, + SpotLight = 2, }; enum class LightMobility { @@ -33,8 +34,15 @@ namespace Atlas { struct PointLightProperties { vec3 position = vec3(0.0f); - float radius = 10.0f; - float attenuation = 2.0f; + float radius = 20.0f; + }; + + struct SpotLightProperties { + vec3 position = vec3(0.0f); + vec3 direction = -vec3(1.0f); + float radius = 20.0f; + float innerConeAngle = 1.0f; + float outerConeAngle = 1.0f; }; struct TypeProperties { @@ -46,12 +54,14 @@ namespace Atlas { TypeProperties(LightType type) { switch (type) { case LightType::PointLight: point = PointLightProperties(); break; + case LightType::SpotLight: spot = SpotLightProperties(); break; default: directional = DirectionalLightProperties(); break; } } DirectionalLightProperties directional; PointLightProperties point; + SpotLightProperties spot; }; class LightComponent { @@ -69,6 +79,8 @@ namespace Atlas { void AddPointShadow(float bias, int32_t resolution); + void AddSpotShadow(float bias, int32_t resolution); + bool IsVisible(const Volume::Frustum& frustum) const; LightType type = LightType::DirectionalLight; diff --git a/src/engine/scripting/bindings/SceneBindings.cpp b/src/engine/scripting/bindings/SceneBindings.cpp index d0bb3529c..32452d714 100644 --- a/src/engine/scripting/bindings/SceneBindings.cpp +++ b/src/engine/scripting/bindings/SceneBindings.cpp @@ -154,13 +154,21 @@ namespace Atlas::Scripting::Bindings { ns->new_usertype("PointLightProperties", "position", &PointLightProperties::position, - "radius", &PointLightProperties::radius, - "attenuation", &PointLightProperties::attenuation + "radius", &PointLightProperties::radius + ); + + ns->new_usertype("SpotLightProperties", + "position", &SpotLightProperties::position, + "direction", &SpotLightProperties::direction, + "radius", &SpotLightProperties::radius, + "outerConeAngle", &SpotLightProperties::outerConeAngle, + "innerConeAngle", &SpotLightProperties::innerConeAngle ); ns->new_usertype("TypeProperties", "directional", &TypeProperties::directional, - "point", &TypeProperties::point + "point", &TypeProperties::point, + "spot", &TypeProperties::spot ); // TODO: Extend this From 2f5ff4d12ecbaa7dd0de2f9f4fc1d51554a458fc Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 12 Sep 2024 17:38:19 +0200 Subject: [PATCH 34/66] Emissive texture support --- data/shader/clouds/clouds.hsh | 2 +- data/shader/common/material.hsh | 9 ++-- data/shader/deferred/deferred.hsh | 14 +++--- data/shader/deferred/geometry.fsh | 13 ++++-- data/shader/deferred/geometry.vsh | 2 +- data/shader/deferred/texture.hsh | 45 +++++++++++++------ data/shader/globals.hsh | 6 +-- data/shader/raytracer/structures.hsh | 1 + data/shader/raytracer/surface.hsh | 2 + data/shader/raytracer/texture.hsh | 9 ++++ data/shader/structures.hsh | 2 +- libs/ImguiExtension/panels/MaterialPanel.cpp | 9 +++- src/demo/App.cpp | 4 +- src/editor/ContentDiscovery.cpp | 18 ++++---- src/editor/ui/panels/ResourceSelectionPanel.h | 10 ++++- src/editor/ui/panels/ViewportPanel.cpp | 4 ++ src/editor/ui/panels/ViewportPanel.h | 1 + .../panels/components/AudioComponentPanel.cpp | 2 + .../components/AudioVolumeComponentPanel.cpp | 2 + .../panels/components/MeshComponentPanel.cpp | 5 ++- .../components/RigidBodyComponentPanel.cpp | 2 + src/editor/ui/windows/SceneWindow.cpp | 1 + src/engine/Material.cpp | 6 +++ src/engine/Material.h | 2 + src/engine/loader/ModelImporter.cpp | 32 ++++++++++++- src/engine/loader/ModelImporter.h | 11 ++++- src/engine/mesh/MeshSerializer.cpp | 4 ++ src/engine/raytracing/RTStructures.h | 1 + src/engine/raytracing/RayTracingWorld.cpp | 4 ++ src/engine/renderer/MainRenderer.cpp | 28 +++++++----- src/engine/renderer/OpaqueRenderer.cpp | 8 +++- src/engine/renderer/OpaqueRenderer.h | 1 + src/engine/renderer/helper/CommonStructures.h | 5 ++- src/engine/renderer/target/RenderTarget.cpp | 6 ++- src/engine/renderer/target/RenderTarget.h | 4 ++ src/engine/scene/SceneRenderState.cpp | 3 ++ 36 files changed, 212 insertions(+), 66 deletions(-) diff --git a/data/shader/clouds/clouds.hsh b/data/shader/clouds/clouds.hsh index 4deb0c5e1..db5b116b3 100644 --- a/data/shader/clouds/clouds.hsh +++ b/data/shader/clouds/clouds.hsh @@ -6,7 +6,7 @@ layout(set = 3, binding = 2) uniform sampler3D shapeTexture; layout(set = 3, binding = 3) uniform sampler3D detailTexture; layout(set = 3, binding = 4) uniform sampler2D coverageTexture; -layout(set = 1, binding = 10) uniform samplerCube diffuseProbe; +layout(set = 1, binding = 12) uniform samplerCube diffuseProbe; layout(std140, set = 3, binding = 5) uniform CloudUniformBuffer { Light light; diff --git a/data/shader/common/material.hsh b/data/shader/common/material.hsh index e2ad60f1c..d3dc9e87d 100644 --- a/data/shader/common/material.hsh +++ b/data/shader/common/material.hsh @@ -8,8 +8,9 @@ #define FEATURE_ROUGHNESS_MAP (1 << 4) #define FEATURE_METALNESS_MAP (1 << 5) #define FEATURE_AO_MAP (1 << 6) -#define FEATURE_TRANSMISSION (1 << 7) -#define FEATURE_VERTEX_COLORS (1 << 8) +#define FEATURE_EMISSIVE_MAP (1 << 7) +#define FEATURE_TRANSMISSION (1 << 8) +#define FEATURE_VERTEX_COLORS (1 << 9) struct Material { uint ID; @@ -36,6 +37,7 @@ struct Material { bool roughnessMap; bool metalnessMap; bool aoMap; + bool emissiveMap; bool transmissive; bool vertexColors; }; @@ -45,7 +47,7 @@ struct PackedMaterial { vec4 data1; }; -layout (std430, set = 1, binding = 14) buffer PackedMaterials { +layout (std430, set = 1, binding = 15) buffer PackedMaterials { PackedMaterial packedMaterials[]; }; @@ -87,6 +89,7 @@ Material UnpackMaterial(uint idx) { material.roughnessMap = (features & FEATURE_ROUGHNESS_MAP) > 0; material.metalnessMap = (features & FEATURE_METALNESS_MAP) > 0; material.aoMap = (features & FEATURE_AO_MAP) > 0; + material.emissiveMap = (features & FEATURE_EMISSIVE_MAP) > 0; material.transmissive = (features & FEATURE_TRANSMISSION) > 0; material.vertexColors = (features & FEATURE_VERTEX_COLORS) > 0; diff --git a/data/shader/deferred/deferred.hsh b/data/shader/deferred/deferred.hsh index d639798ee..837abf6f5 100644 --- a/data/shader/deferred/deferred.hsh +++ b/data/shader/deferred/deferred.hsh @@ -7,12 +7,13 @@ layout(set = 1, binding = 3) uniform sampler2D baseColorTexture; layout(set = 1, binding = 4) uniform sampler2D normalTexture; layout(set = 1, binding = 5) uniform sampler2D geometryNormalTexture; layout(set = 1, binding = 6) uniform sampler2D roughnessMetalnessAoTexture; -layout(set = 1, binding = 7) uniform usampler2D materialIdxTexture; -layout(set = 1, binding = 8) uniform sampler2D depthTexture; -layout(set = 1, binding = 9) uniform sampler2D volumetricTexture; +layout(set = 1, binding = 7) uniform sampler2D emissiveTexture; +layout(set = 1, binding = 8) uniform usampler2D materialIdxTexture; +layout(set = 1, binding = 9) uniform sampler2D depthTexture; +layout(set = 1, binding = 10) uniform sampler2D volumetricTexture; -layout(set = 1, binding = 10) uniform samplerCube specularProbe; -layout(set = 1, binding = 11) uniform samplerCube diffuseProbe; +layout(set = 1, binding = 11) uniform samplerCube specularProbe; +layout(set = 1, binding = 12) uniform samplerCube diffuseProbe; Material GetMaterial(vec2 texCoord) { uint materialIdx = textureLod(materialIdxTexture, texCoord, 0).r; @@ -30,6 +31,9 @@ Material GetMaterial(vec2 texCoord) { if (material.aoMap) { material.ao *= textureLod(roughnessMetalnessAoTexture, texCoord, 0).b; } + if (material.emissiveMap) { + material.emissiveColor *= textureLod(emissiveTexture, texCoord, 0).rgb; + } return material; } diff --git a/data/shader/deferred/geometry.fsh b/data/shader/deferred/geometry.fsh index 0cb443b56..f5c1341f1 100644 --- a/data/shader/deferred/geometry.fsh +++ b/data/shader/deferred/geometry.fsh @@ -7,8 +7,9 @@ layout (location = 0) out vec3 baseColorFS; layout (location = 1) out vec2 normalFS; layout (location = 2) out vec2 geometryNormalFS; layout (location = 3) out vec3 roughnessMetalnessAoFS; -layout (location = 4) out uint materialIdxFS; -layout (location = 5) out vec2 velocityFS; +layout (location = 4) out vec3 emissiveFS; +layout (location = 5) out uint materialIdxFS; +layout (location = 6) out vec2 velocityFS; layout(location=0) in vec3 positionVS; layout(location=1) in vec3 normalVS; @@ -47,6 +48,7 @@ layout(push_constant) uniform constants { uint metalnessTextureIdx; uint aoTextureIdx; uint heightTextureIdx; + uint emissiveTextureIdx; } PushConstants; vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir) { @@ -102,7 +104,7 @@ void main() { #endif // Check if usage is valid (otherwise texCoords won't be used) -#if defined(HEIGHT_MAP) && (defined(BASE_COLOR_MAP) || defined(NORMAL_MAP) || defined(ROUGHNESS_MAP) || defined(METALNESS_MAP) || defined(AO_MAP)) +#if defined(HEIGHT_MAP) && (defined(BASE_COLOR_MAP) || defined(NORMAL_MAP) || defined(ROUGHNESS_MAP) || defined(METALNESS_MAP) || defined(AO_MAP) || defined(EMISSIVE_MAP)) vec3 viewDir = normalize(transpose(TBN) * -positionVS); texCoords = ParallaxMapping(texCoords, viewDir); #endif @@ -126,6 +128,11 @@ void main() { baseColorFS *= textureColor.rgb; #endif +#ifdef EMISSIVE_MAP + vec3 emissiveColor = SampleEmissive(texCoords, PushConstants.emissiveTextureIdx, globalData.mipLodBias); + emissiveFS = emissiveColor.rgb; +#endif + #ifdef VERTEX_COLORS baseColorFS *= vertexColorsVS.rgb; #endif diff --git a/data/shader/deferred/geometry.vsh b/data/shader/deferred/geometry.vsh index 2e50637a2..f4f0d18dd 100644 --- a/data/shader/deferred/geometry.vsh +++ b/data/shader/deferred/geometry.vsh @@ -53,7 +53,7 @@ layout(location=6) out float normalInversionVS; layout(location=7) out mat3 TBN; #endif -layout(set = 3, binding = 7) uniform sampler2D windNoiseMap; +layout(set = 3, binding = 8) uniform sampler2D windNoiseMap; layout(push_constant) uniform constants { uint vegetation; diff --git a/data/shader/deferred/texture.hsh b/data/shader/deferred/texture.hsh index 55fe7b9b7..f9acddb6f 100644 --- a/data/shader/deferred/texture.hsh +++ b/data/shader/deferred/texture.hsh @@ -22,102 +22,119 @@ layout(set = 3, binding = 5) uniform sampler2D aoMap; #ifdef HEIGHT_MAP layout(set = 3, binding = 6) uniform sampler2D heightMap; #endif +#ifdef EMISSIVE_MAP +layout(set = 3, binding = 7) uniform sampler2D emissiveMap; +#endif #endif vec3 SampleBaseColor(vec2 texCoords, uint textureID, float bias) { +#ifdef BASE_COLOR_MAP #ifdef BINDLESS_TEXTURES return texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).rgb; #else -#ifdef BASE_COLOR_MAP return texture(baseColorMap, texCoords, bias).rgb; -#else - return vec3(0.0); #endif +#else + return vec3(1.0); #endif } float SampleOpacity(vec2 texCoords, uint textureID, float bias) { +#ifdef OPACITY_MAP #ifdef BINDLESS_TEXTURES return texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).r; #else -#ifdef OPACITY_MAP return texture(opacityMap, texCoords, bias).r; +#endif #else return 1.0; #endif -#endif } vec3 SampleNormal(vec2 texCoords, uint textureID, float bias) { +#ifdef NORMAL_MAP #ifdef BINDLESS_TEXTURES return 2.0 * texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).rgb - 1.0; #else -#ifdef NORMAL_MAP return 2.0 * texture(normalMap, texCoords, bias).rgb - 1.0; +#endif #else return vec3(0.0); #endif -#endif } float SampleRoughness(vec2 texCoords, uint textureID, float bias) { +#ifdef ROUGHNESS_MAP #ifdef BINDLESS_TEXTURES return texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).r; #else -#ifdef ROUGHNESS_MAP return texture(roughnessMap, texCoords, bias).r; +#endif #else return 1.0; #endif -#endif } float SampleMetalness(vec2 texCoords, uint textureID, float bias) { +#ifdef METALNESS_MAP #ifdef BINDLESS_TEXTURES return texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).r; #else -#ifdef METALNESS_MAP return texture(metalnessMap, texCoords, bias).r; +#endif #else return 0.0; #endif -#endif } float SampleAo(vec2 texCoords, uint textureID, float bias) { +#ifdef AO_MAP #ifdef BINDLESS_TEXTURES return texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).r; #else -#ifdef AO_MAP return texture(aoMap, texCoords, bias).r; +#endif #else return 1.0; #endif -#endif } float SampleHeight(vec2 texCoords, uint textureID, vec2 ddx, vec2 ddy) { +#ifdef HEIGHT_MAP #ifdef BINDLESS_TEXTURES return textureGrad(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, ddx, ddy).r; #else -#ifdef HEIGHT_MAP return textureGrad(heightMap, texCoords, ddx, ddy).r; +#endif #else return 0.0; #endif + +} + +vec3 SampleEmissive(vec2 texCoords, uint textureID, float bias) { + +#ifdef EMISSIVE_MAP +#ifdef BINDLESS_TEXTURES + return texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).rgb; +#else + return texture(emissiveMap, texCoords, bias).r; +#endif +#else + return vec3(0.0); #endif } \ No newline at end of file diff --git a/data/shader/globals.hsh b/data/shader/globals.hsh index a276ae625..d3e8b4118 100644 --- a/data/shader/globals.hsh +++ b/data/shader/globals.hsh @@ -39,7 +39,7 @@ layout(set = 0, binding = 3) uniform texture2D bindlessTextures[TEXTURE_COUNT]; layout(set = 0, binding = 4) uniform texture2D bindlessCubemaps[CUBEMAP_COUNT]; layout(set = 0, binding = 5) uniform texture2D bindlessTextureArrays[TEXTURE_ARRAY_COUNT]; -layout(set = 1, binding = 12) uniform sampler2D dfgTexture; +layout(set = 1, binding = 13) uniform sampler2D dfgTexture; -layout(set = 1, binding = 13) uniform sampler bindlessSampler; -layout(set = 1, binding = 15) uniform sampler bindlessNearestSampler; \ No newline at end of file +layout(set = 1, binding = 14) uniform sampler bindlessSampler; +layout(set = 1, binding = 16) uniform sampler bindlessNearestSampler; \ No newline at end of file diff --git a/data/shader/raytracer/structures.hsh b/data/shader/raytracer/structures.hsh index b3b1d89cb..9d46c00d2 100644 --- a/data/shader/raytracer/structures.hsh +++ b/data/shader/raytracer/structures.hsh @@ -134,6 +134,7 @@ struct RaytraceMaterial { int roughnessTexture; int metalnessTexture; int aoTexture; + int emissiveTexture; }; diff --git a/data/shader/raytracer/surface.hsh b/data/shader/raytracer/surface.hsh index 546b6c0fe..1bb3499e5 100644 --- a/data/shader/raytracer/surface.hsh +++ b/data/shader/raytracer/surface.hsh @@ -107,6 +107,8 @@ Surface GetSurfaceParameters(Instance instance, Triangle tri, Ray ray, mat.roughness *= SampleRoughnessBilinear(rayMat.roughnessTexture, float(level), texCoord); mat.metalness *= SampleMetalnessBilinear(rayMat.metalnessTexture, float(level), texCoord); mat.ao *= SampleAoBilinear(rayMat.aoTexture, float(level), texCoord); + // Need to have the texture level to go to near zero, otherwise we will have light leaks + mat.emissiveColor *= SampleEmissiveBilinear(rayMat.emissiveTexture, max(0.0, float(level - 3.0)), texCoord); // Account for changing texture coord direction vec3 bitangent = rayMat.invertUVs > 0 ? tri.bt : -tri.bt; diff --git a/data/shader/raytracer/texture.hsh b/data/shader/raytracer/texture.hsh index 16e7b7ffd..d50b828ba 100644 --- a/data/shader/raytracer/texture.hsh +++ b/data/shader/raytracer/texture.hsh @@ -60,6 +60,15 @@ float SampleAoBilinear(int textureId, float mip, vec2 texCoord) { } +vec3 SampleEmissiveBilinear(int textureId, float mip, vec2 texCoord) { + + if (textureId < 0) + return vec3(0.0); + + return textureLod(sampler2D(bindlessTextures[nonuniformEXT(textureId)], bindlessSampler), texCoord, mip).rgb; + +} + vec4 SampleEnvironmentMap(vec3 v) { return textureLod(environmentMap, v, 0); diff --git a/data/shader/structures.hsh b/data/shader/structures.hsh index ed20f9252..15aaaf547 100644 --- a/data/shader/structures.hsh +++ b/data/shader/structures.hsh @@ -32,6 +32,6 @@ struct CloudShadow { }; -layout (std430, set = 1, binding = 16) buffer Lights { +layout (std430, set = 1, binding = 17) buffer Lights { Light lights[]; }; \ No newline at end of file diff --git a/libs/ImguiExtension/panels/MaterialPanel.cpp b/libs/ImguiExtension/panels/MaterialPanel.cpp index 8b6754f85..4eda7eb7a 100644 --- a/libs/ImguiExtension/panels/MaterialPanel.cpp +++ b/libs/ImguiExtension/panels/MaterialPanel.cpp @@ -11,6 +11,7 @@ namespace Atlas::ImguiExtension { auto widthAfterImage = availableWidth - padding - ImGui::GetTextLineHeight(); auto renderWithImagePreview = [&](ResourceHandle& texture, std::function element) { + if (texture.IsLoaded()) { UIElements::TexturePreview(wrapper, &texture); ImGui::SameLine(); @@ -21,6 +22,7 @@ namespace Atlas::ImguiExtension { texture = textureSelector.value()(texture); ImGui::PopItemWidth(); } + ImGui::PushID(texture.GetID()); } else { if (textureSelector.has_value()) @@ -35,8 +37,11 @@ namespace Atlas::ImguiExtension { renderWithImagePreview(material->baseColorMap, [&]() { ImGui::ColorEdit3("Base color", glm::value_ptr(material->baseColor)); }); - ImGui::ColorEdit3("Emissive color", glm::value_ptr(material->emissiveColor)); - ImGui::DragFloat("Emissive intensity", &material->emissiveIntensity, 0.1f, 0.0f, 10000.0f, "%.2f"); + + renderWithImagePreview(material->emissiveMap, [&]() { + ImGui::ColorEdit3("Emissive color", glm::value_ptr(material->emissiveColor)); + ImGui::DragFloat("Emissive intensity", &material->emissiveIntensity, 0.1f, 0.0f, 10000.0f, "%.2f"); + }); ImGui::Separator(); ImGui::Text("Opacity"); diff --git a/src/demo/App.cpp b/src/demo/App.cpp index 5fe6525e6..b040f906f 100644 --- a/src/demo/App.cpp +++ b/src/demo/App.cpp @@ -906,7 +906,7 @@ bool App::LoadScene() { scene->fog->volumetricIntensity = 0.0f; } else if (sceneSelection == FOREST) { - auto otherScene = Atlas::Loader::ModelImporter::ImportScene("forest/forest.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5); + auto otherScene = Atlas::Loader::ModelImporter::ImportScene("forest/forest.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5, false, false, false, 2048); otherScene->Timestep(1.0f); otherScene->Update(); @@ -924,7 +924,7 @@ bool App::LoadScene() { scene->fog->volumetricIntensity = 0.08f; } else if (sceneSelection == EMERALDSQUARE) { - auto otherScene = Atlas::Loader::ModelImporter::ImportScene("emeraldsquare/square.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5); + auto otherScene = Atlas::Loader::ModelImporter::ImportScene("emeraldsquare/square.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5, false, false, false, 2048); otherScene->Timestep(1.0f); otherScene->Update(); diff --git a/src/editor/ContentDiscovery.cpp b/src/editor/ContentDiscovery.cpp index 8f5527b4e..b0d855cbf 100644 --- a/src/editor/ContentDiscovery.cpp +++ b/src/editor/ContentDiscovery.cpp @@ -53,23 +53,23 @@ namespace Atlas::Editor { void ContentDiscovery::Update() { - bool canRediscover = (Clock::Get() - lastDiscoveryTime) >= discoverFrequency; + bool canRediscover = (Clock::Get() - lastDiscoveryTime) >= discoverFrequency || content->contentDirectories.empty(); if (contentDiscoveryJob.HasFinished() && canRediscover) { - // Might be that it took longer than the timeout time - content = nextContent; + // Swap here to not immediately release the memory of content (causes stutter due to freeing memory) + std::swap(content, nextContent); + lastDiscoveryTime = Clock::Get(); JobSystem::Execute(contentDiscoveryJob, [&](JobData&) { + // Now release the swapped memory here in the job async + nextContent.reset(); + nextContent = PerformContentDiscovery(); }); - return; - } - - if (!contentDiscoveryJob.HasFinished()) - return; - content = nextContent; + return; + } } Ref ContentDiscovery::PerformContentDiscovery() { diff --git a/src/editor/ui/panels/ResourceSelectionPanel.h b/src/editor/ui/panels/ResourceSelectionPanel.h index 4aaccf88b..dc662a701 100644 --- a/src/editor/ui/panels/ResourceSelectionPanel.h +++ b/src/editor/ui/panels/ResourceSelectionPanel.h @@ -31,7 +31,7 @@ namespace Atlas::Editor::UI { resourceChanged = false; auto buttonName = resourceHandle.IsValid() ? resourceHandle.GetResource()->GetFileName() : - "Drop resource here"; + "Drop resource here##" + std::to_string(counter++); ImGui::PushID(resourceHandle.GetID()); @@ -80,9 +80,17 @@ namespace Atlas::Editor::UI { } + void Reset() { + + counter = 0; + + } + private: ResourceSelectionPopup popup; + int32_t counter = 0; + }; } \ No newline at end of file diff --git a/src/editor/ui/panels/ViewportPanel.cpp b/src/editor/ui/panels/ViewportPanel.cpp index 8a26613d6..45b84b6d7 100644 --- a/src/editor/ui/panels/ViewportPanel.cpp +++ b/src/editor/ui/panels/ViewportPanel.cpp @@ -136,6 +136,10 @@ namespace Atlas::Editor::UI { mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, rtData->roughnessMetallicAoTexture.get(), 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); } + if (visualization == GBufferEmissive) { + mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, rtData->emissiveTexture.get(), + 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); + } if (visualization == GBufferNormals) { mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, rtData->normalTexture.get(), 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0, 1.0f, false, true); diff --git a/src/editor/ui/panels/ViewportPanel.h b/src/editor/ui/panels/ViewportPanel.h index bec126fdf..f1e1eb3c0 100644 --- a/src/editor/ui/panels/ViewportPanel.h +++ b/src/editor/ui/panels/ViewportPanel.h @@ -11,6 +11,7 @@ namespace Atlas::Editor::UI { Lit = 0, GBufferBaseColor, GBufferRoughnessMetalnessAo, + GBufferEmissive, GBufferNormals, GBufferGeometryNormals, GBufferMaterialIdx, diff --git a/src/editor/ui/panels/components/AudioComponentPanel.cpp b/src/editor/ui/panels/components/AudioComponentPanel.cpp index 47785e0e9..1405b6165 100644 --- a/src/editor/ui/panels/components/AudioComponentPanel.cpp +++ b/src/editor/ui/panels/components/AudioComponentPanel.cpp @@ -30,6 +30,8 @@ namespace Atlas::Editor::UI { ImGui::Checkbox("Loop stream", &audioComponent.stream->loop); } + audioSelectionPanel.Reset(); + return resourceChanged; } diff --git a/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp b/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp index aefb3a840..d13c0710d 100644 --- a/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp +++ b/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp @@ -34,6 +34,8 @@ namespace Atlas::Editor::UI { ImGui::Checkbox("Loop stream", &audioVolumeComponent.stream->loop); } + audioSelectionPanel.Reset(); + return resourceChanged; } diff --git a/src/editor/ui/panels/components/MeshComponentPanel.cpp b/src/editor/ui/panels/components/MeshComponentPanel.cpp index e63dd511d..9f13c8124 100644 --- a/src/editor/ui/panels/components/MeshComponentPanel.cpp +++ b/src/editor/ui/panels/components/MeshComponentPanel.cpp @@ -58,7 +58,10 @@ namespace Atlas::Editor::UI { // Just update materials regardless of any change mesh->UpdatePipelines(); - } + } + + materialSelectionPanel.Reset(); + textureSelectionPanel.Reset(); return resourceChanged; diff --git a/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp b/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp index 88f46b481..3358ac40d 100644 --- a/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp +++ b/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp @@ -23,6 +23,8 @@ namespace Atlas::Editor::UI { if (scene->physicsWorld->pauseSimulation) rigidBodyComponent.creationSettings = CreateRef(creationSettings); + meshSelectionPanel.Reset(); + return false; } diff --git a/src/editor/ui/windows/SceneWindow.cpp b/src/editor/ui/windows/SceneWindow.cpp index 9b25bc623..bca125515 100644 --- a/src/editor/ui/windows/SceneWindow.cpp +++ b/src/editor/ui/windows/SceneWindow.cpp @@ -395,6 +395,7 @@ namespace Atlas::Editor::UI { if (ImGui::BeginMenu("GBuffer")) { menuItem("Base color", ViewportVisualization::GBufferBaseColor); menuItem("Roughness/Metalness/Ao", ViewportVisualization::GBufferRoughnessMetalnessAo); + menuItem("Emissive color", ViewportVisualization::GBufferEmissive); menuItem("Depth", ViewportVisualization::GBufferDepth); menuItem("Normals", ViewportVisualization::GBufferNormals); menuItem("Geometry normals", ViewportVisualization::GBufferGeometryNormals); diff --git a/src/engine/Material.cpp b/src/engine/Material.cpp index 2f666ddca..00bf977c3 100644 --- a/src/engine/Material.cpp +++ b/src/engine/Material.cpp @@ -50,4 +50,10 @@ namespace Atlas { } + bool Material::HasEmissiveMap() const { + + return emissiveMap.IsValid(); + + } + } \ No newline at end of file diff --git a/src/engine/Material.h b/src/engine/Material.h index efbd4adb3..c0a8015a4 100644 --- a/src/engine/Material.h +++ b/src/engine/Material.h @@ -24,6 +24,7 @@ namespace Atlas { bool HasMetalnessMap() const; bool HasAoMap() const; bool HasDisplacementMap() const; + bool HasEmissiveMap() const; std::string name; @@ -34,6 +35,7 @@ namespace Atlas { ResourceHandle metalnessMap; ResourceHandle aoMap; ResourceHandle displacementMap; + ResourceHandle emissiveMap; vec3 baseColor = vec3(1.0f); vec3 transmissiveColor = vec3(0.0f); diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index 7e3dca4b9..7f4587db0 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -684,8 +684,15 @@ namespace Atlas { } if (assimpMaterial->GetTextureCount(aiTextureType_EMISSION_COLOR) > 0 || assimpMaterial->GetTextureCount(aiTextureType_EMISSIVE) > 0) { - // We don't support this right now - material.emissiveIntensity = 0.0f; + aiString aiPath; + if (assimpMaterial->GetTextureCount(aiTextureType_EMISSION_COLOR) > 0) + assimpMaterial->GetTexture(aiTextureType_EMISSION_COLOR, 0, &aiPath); + else + assimpMaterial->GetTexture(aiTextureType_EMISSIVE, 0, &aiPath); + auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); + if (images.emissiveTextures.contains(path)) { + material.emissiveMap = images.emissiveTextures[path]; + } } // Probably foliage @@ -831,6 +838,19 @@ namespace Atlas { images.Add(MaterialImageType::Displacement, path, image); } } + if (material->GetTextureCount(aiTextureType_EMISSION_COLOR) > 0 || + material->GetTextureCount(aiTextureType_EMISSIVE) > 0) { + aiString aiPath; + if (material->GetTextureCount(aiTextureType_EMISSION_COLOR) > 0) + material->GetTexture(aiTextureType_EMISSION_COLOR, 0, &aiPath); + else + material->GetTexture(aiTextureType_EMISSIVE, 0, &aiPath); + auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); + if (!images.Contains(MaterialImageType::Emissive, path)) { + auto image = ImageLoader::LoadImage(path, false, 0, maxTextureResolution); + images.Add(MaterialImageType::Emissive, path, image); + } + } } std::vector>> ModelImporter::ImagesToTextures(ImporterState& state) { @@ -874,6 +894,12 @@ namespace Atlas { images.displacementTextures[path] = ResourceManager::AddResource(image->fileName, texture); imagesToSave.push_back(image); } + for (const auto& [path, image] : images.emissiveImages) { + auto texture = std::make_shared(image); + image->fileName = GetMaterialImageImportPath(state, MaterialImageType::Emissive, path); + images.emissiveTextures[path] = ResourceManager::AddResource(image->fileName, texture); + imagesToSave.push_back(image); + } return imagesToSave; @@ -912,6 +938,8 @@ namespace Atlas { typeName = "Normal"; break; case MaterialImageType::Displacement: typeName = "Displacement"; break; + case MaterialImageType::Emissive: + typeName = "Emissive"; break; default: typeName = "Invalid"; break; } diff --git a/src/engine/loader/ModelImporter.h b/src/engine/loader/ModelImporter.h index 2910e7cdf..7a59ade2e 100644 --- a/src/engine/loader/ModelImporter.h +++ b/src/engine/loader/ModelImporter.h @@ -46,6 +46,8 @@ namespace Atlas { Metallic, Normal, Displacement, + Emissive, + Count }; struct MaterialImages { @@ -55,6 +57,7 @@ namespace Atlas { std::map>> metallicImages; std::map>> normalImages; std::map>> displacementImages; + std::map>> emissiveImages; std::map> baseColorTextures; std::map> opacityTextures; @@ -62,8 +65,9 @@ namespace Atlas { std::map> metallicTextures; std::map> normalTextures; std::map> displacementTextures; + std::map> emissiveTextures; - std::mutex mutexes[6]; + std::mutex mutexes[static_cast(MaterialImageType::Count)]; void Add(MaterialImageType type, const std::string& path, const Ref>& image) { std::scoped_lock lock(mutexes[static_cast(type)]); @@ -87,6 +91,9 @@ namespace Atlas { case MaterialImageType::Displacement: displacementImages[path] = image; break; + case MaterialImageType::Emissive: + emissiveImages[path] = image; + break; default: break; } @@ -108,6 +115,8 @@ namespace Atlas { return normalImages.contains(path); case MaterialImageType::Displacement: return displacementImages.contains(path); + case MaterialImageType::Emissive: + return emissiveImages.contains(path); default: return true; } diff --git a/src/engine/mesh/MeshSerializer.cpp b/src/engine/mesh/MeshSerializer.cpp index b07a5189c..ffd5fbfb1 100644 --- a/src/engine/mesh/MeshSerializer.cpp +++ b/src/engine/mesh/MeshSerializer.cpp @@ -211,6 +211,8 @@ namespace Atlas { j["aoMapPath"] = p.aoMap.GetResource()->path; if (p.displacementMap.IsValid()) j["displacementMapPath"] = p.displacementMap.GetResource()->path; + if (p.emissiveMap.IsValid()) + j["emissiveMapPath"] = p.emissiveMap.GetResource()->path; } @@ -252,6 +254,8 @@ namespace Atlas { p.aoMap = getTextureHandle(j["aoMapPath"], false); if (j.contains("displacementMapPath")) p.displacementMap = getTextureHandle(j["displacementMapPath"], false); + if (j.contains("emissiveMapPath")) + p.emissiveMap = getTextureHandle(j["emissiveMapPath"], false); } diff --git a/src/engine/raytracing/RTStructures.h b/src/engine/raytracing/RTStructures.h index 7e0235b0b..90e5ccae0 100644 --- a/src/engine/raytracing/RTStructures.h +++ b/src/engine/raytracing/RTStructures.h @@ -75,6 +75,7 @@ namespace Atlas { int32_t roughnessTexture = -1; int32_t metalnessTexture = -1; int32_t aoTexture = -1; + int32_t emissiveTexture = -1; }; struct GPUAABB { diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index 539c9b721..f56728a79 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -257,6 +257,10 @@ namespace Atlas { if (material->HasAoMap()) { gpuMaterial.aoTexture = sceneState->textureToBindlessIdx[material->aoMap.Get()]; } + + if (material->HasEmissiveMap()) { + gpuMaterial.emissiveTexture = sceneState->textureToBindlessIdx[material->emissiveMap.Get()]; + } } materials.push_back(gpuMaterial); diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 07fd3a983..608d305de 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -108,9 +108,9 @@ namespace Atlas { SetUniforms(target, scene, camera); commandList->BindBuffer(globalUniformBuffer, 1, 31); - commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 12); - commandList->BindSampler(globalSampler, 1, 13); - commandList->BindSampler(globalNearestSampler, 1, 15); + commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); + commandList->BindSampler(globalSampler, 1, 14); + commandList->BindSampler(globalNearestSampler, 1, 16); if (scene->clutter) vegetationRenderer.helper.PrepareInstanceBuffer(*scene->clutter, camera, commandList); @@ -136,7 +136,7 @@ namespace Atlas { volumetricCloudRenderer.RenderShadow(target, scene, commandList); JobSystem::WaitSpin(renderState->materialUpdateJob); - renderState->materialBuffer.Bind(commandList, 1, 14); + renderState->materialBuffer.Bind(commandList, 1, 15); // Wait as long as possible for this to finish JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); @@ -161,9 +161,9 @@ namespace Atlas { if (scene->sky.GetProbe()) { commandList->BindImage(scene->sky.GetProbe()->filteredSpecular.image, - scene->sky.GetProbe()->filteredSpecular.sampler, 1, 10); + scene->sky.GetProbe()->filteredSpecular.sampler, 1, 11); commandList->BindImage(scene->sky.GetProbe()->filteredDiffuse.image, - scene->sky.GetProbe()->filteredDiffuse.sampler, 1, 11); + scene->sky.GetProbe()->filteredDiffuse.sampler, 1, 12); } { @@ -191,7 +191,7 @@ namespace Atlas { JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); JobSystem::WaitSpin(renderState->cullAndSortLightsJob); - renderState->lightBuffer.Bind(commandList, 1, 16); + renderState->lightBuffer.Bind(commandList, 1, 17); ddgiRenderer.TraceAndUpdateProbes(scene, commandList); @@ -226,8 +226,9 @@ namespace Atlas { commandList->BindImage(targetData->normalTexture->image, targetData->normalTexture->sampler, 1, 4); commandList->BindImage(targetData->geometryNormalTexture->image, targetData->geometryNormalTexture->sampler, 1, 5); commandList->BindImage(targetData->roughnessMetallicAoTexture->image, targetData->roughnessMetallicAoTexture->sampler, 1, 6); - commandList->BindImage(targetData->materialIdxTexture->image, targetData->materialIdxTexture->sampler, 1, 7); - commandList->BindImage(targetData->depthTexture->image, targetData->depthTexture->sampler, 1, 8); + commandList->BindImage(targetData->emissiveTexture->image, targetData->emissiveTexture->sampler, 1, 7); + commandList->BindImage(targetData->materialIdxTexture->image, targetData->materialIdxTexture->sampler, 1, 8); + commandList->BindImage(targetData->depthTexture->image, targetData->depthTexture->sampler, 1, 9); if (!target->HasHistory()) { auto rtHalfData = target->GetHistoryData(HALF_RES); @@ -241,6 +242,7 @@ namespace Atlas { {rtData->normalTexture->image, layout, access}, {rtData->geometryNormalTexture->image, layout, access}, {rtData->roughnessMetallicAoTexture->image, layout, access}, + {rtData->emissiveTexture->image, layout, access}, {rtData->offsetTexture->image, layout, access}, {rtData->materialIdxTexture->image, layout, access}, {rtData->stencilTexture->image, layout, access}, @@ -250,6 +252,7 @@ namespace Atlas { {rtHalfData->normalTexture->image, layout, access}, {rtHalfData->geometryNormalTexture->image, layout, access}, {rtHalfData->roughnessMetallicAoTexture->image, layout, access}, + {rtHalfData->emissiveTexture->image, layout, access}, {rtHalfData->offsetTexture->image, layout, access}, {rtHalfData->materialIdxTexture->image, layout, access}, {rtHalfData->stencilTexture->image, layout, access}, @@ -271,6 +274,7 @@ namespace Atlas { {rtData->normalTexture->image, layout, access}, {rtData->geometryNormalTexture->image, layout, access}, {rtData->roughnessMetallicAoTexture->image, layout, access}, + {rtData->emissiveTexture->image, layout, access}, {rtData->offsetTexture->image, layout, access}, {rtData->materialIdxTexture->image, layout, access}, {rtData->stencilTexture->image, layout, access}, @@ -460,9 +464,9 @@ namespace Atlas { JobSystem::WaitSpin(renderState->prepareBindlessTexturesJob); commandList->BindBuffer(pathTraceGlobalUniformBuffer, 1, 31); - commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 12); - commandList->BindSampler(globalSampler, 1, 13); - commandList->BindSampler(globalNearestSampler, 1, 15); + commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); + commandList->BindSampler(globalSampler, 1, 14); + commandList->BindSampler(globalNearestSampler, 1, 16); commandList->BindBuffers(renderState->triangleBuffers, 0, 1); if (renderState->images.size()) commandList->BindSampledImages(renderState->images, 0, 3); diff --git a/src/engine/renderer/OpaqueRenderer.cpp b/src/engine/renderer/OpaqueRenderer.cpp index a3e7a43b8..84a7f2633 100644 --- a/src/engine/renderer/OpaqueRenderer.cpp +++ b/src/engine/renderer/OpaqueRenderer.cpp @@ -31,7 +31,7 @@ namespace Atlas { commandList->BindBuffer(mainPass->impostorMatricesBuffer, 1, 3); // Bind wind map - scene->wind.noiseMap.Bind(commandList, 3, 7); + scene->wind.noiseMap.Bind(commandList, 3, 8); int32_t subDataCount = 0; // Retrieve all possible materials; @@ -105,6 +105,8 @@ namespace Atlas { material->aoMap->Bind(commandList, 3, 5); if (material->HasDisplacementMap()) material->displacementMap->Bind(commandList, 3, 6); + if (material->HasEmissiveMap()) + material->emissiveMap->Bind(commandList, 3, 7); #endif auto pushConstants = PushConstants { @@ -125,6 +127,7 @@ namespace Atlas { .metalnessTextureIdx = material->HasMetalnessMap() ? sceneState->textureToBindlessIdx[material->metalnessMap.Get()] : 0, .aoTextureIdx = material->HasAoMap() ? sceneState->textureToBindlessIdx[material->aoMap.Get()] : 0, .heightTextureIdx = material->HasDisplacementMap() ? sceneState->textureToBindlessIdx[material->displacementMap.Get()] : 0, + .emissiveTextureIdx = material->HasEmissiveMap() ? sceneState->textureToBindlessIdx[material->emissiveMap.Get()] : 0, }; commandList->PushConstants("constants", &pushConstants); @@ -183,6 +186,9 @@ namespace Atlas { if (material->HasDisplacementMap() && hasTangents && hasTexCoords) { macros.push_back("HEIGHT_MAP"); } + if (material->HasEmissiveMap() && hasTexCoords) { + macros.push_back("EMISSIVE_MAP"); + } // This is a check if we have any maps at all (no macros, no maps) if (macros.size()) { macros.push_back("TEX_COORDS"); diff --git a/src/engine/renderer/OpaqueRenderer.h b/src/engine/renderer/OpaqueRenderer.h index f19371056..9e6274651 100644 --- a/src/engine/renderer/OpaqueRenderer.h +++ b/src/engine/renderer/OpaqueRenderer.h @@ -46,6 +46,7 @@ namespace Atlas { uint32_t metalnessTextureIdx; uint32_t aoTextureIdx; uint32_t heightTextureIdx; + uint32_t emissiveTextureIdx; }; diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index a94f11002..fdacc974f 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -15,8 +15,9 @@ namespace Atlas { FEATURE_ROUGHNESS_MAP = (1 << 4), FEATURE_METALNESS_MAP = (1 << 5), FEATURE_AO_MAP = (1 << 6), - FEATURE_TRANSMISSION = (1 << 7), - FEATURE_VERTEX_COLORS = (1 << 8) + FEATURE_EMISSIVE_MAP = (1 << 7), + FEATURE_TRANSMISSION = (1 << 8), + FEATURE_VERTEX_COLORS = (1 << 9) }; struct alignas(16) Cascade { diff --git a/src/engine/renderer/target/RenderTarget.cpp b/src/engine/renderer/target/RenderTarget.cpp index ebf9dcf4a..f397302a0 100644 --- a/src/engine/renderer/target/RenderTarget.cpp +++ b/src/engine/renderer/target/RenderTarget.cpp @@ -381,6 +381,7 @@ namespace Atlas::Renderer { {.imageFormat = targetData.normalTexture->format}, {.imageFormat = targetData.geometryNormalTexture->format}, {.imageFormat = targetData.roughnessMetallicAoTexture->format}, + {.imageFormat = targetData.emissiveTexture->format}, {.imageFormat = targetData.materialIdxTexture->format}, {.imageFormat = targetData.velocityTexture->format}, {.imageFormat = targetData.stencilTexture->format}, @@ -400,8 +401,8 @@ namespace Atlas::Renderer { }; auto gBufferRenderPassDesc = Graphics::RenderPassDesc{ - .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2], - colorAttachments[3], colorAttachments[4], colorAttachments[5], colorAttachments[6]}, + .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2], colorAttachments[3], + colorAttachments[4], colorAttachments[5], colorAttachments[6], colorAttachments[7]}, .depthAttachment = depthAttachment }; gBufferRenderPass = graphicsDevice->CreateRenderPass(gBufferRenderPassDesc); @@ -486,6 +487,7 @@ namespace Atlas::Renderer { {target->normalTexture->image, 0, true}, {target->geometryNormalTexture->image, 0, true}, {target->roughnessMetallicAoTexture->image, 0, true}, + {target->emissiveTexture->image, 0, true}, {target->materialIdxTexture->image, 0, true}, {target->velocityTexture->image, 0, true}, {target->stencilTexture->image, 0, false}, diff --git a/src/engine/renderer/target/RenderTarget.h b/src/engine/renderer/target/RenderTarget.h index ec344799c..b38c11af8 100644 --- a/src/engine/renderer/target/RenderTarget.h +++ b/src/engine/renderer/target/RenderTarget.h @@ -34,6 +34,8 @@ namespace Atlas::Renderer { VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); roughnessMetallicAoTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + emissiveTexture = std::make_shared(resolution.x, resolution.y, + VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); offsetTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_R8_SINT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); materialIdxTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_R16_UINT, @@ -50,6 +52,7 @@ namespace Atlas::Renderer { normalTexture->Resize(resolution.x, resolution.y); geometryNormalTexture->Resize(resolution.x, resolution.y); roughnessMetallicAoTexture->Resize(resolution.x, resolution.y); + emissiveTexture->Resize(resolution.x, resolution.y); offsetTexture->Resize(resolution.x, resolution.y); materialIdxTexture->Resize(resolution.x, resolution.y); stencilTexture->Resize(resolution.x, resolution.y); @@ -61,6 +64,7 @@ namespace Atlas::Renderer { Ref normalTexture = nullptr; Ref geometryNormalTexture = nullptr; Ref roughnessMetallicAoTexture = nullptr; + Ref emissiveTexture = nullptr; Ref offsetTexture = nullptr; Ref materialIdxTexture = nullptr; Ref stencilTexture = nullptr; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index bf8133fdf..765842b43 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -88,6 +88,7 @@ namespace Atlas::Scene { packed.features |= material->HasRoughnessMap() ? Renderer::MaterialFeatures::FEATURE_ROUGHNESS_MAP : 0; packed.features |= material->HasMetalnessMap() ? Renderer::MaterialFeatures::FEATURE_METALNESS_MAP : 0; packed.features |= material->HasAoMap() ? Renderer::MaterialFeatures::FEATURE_AO_MAP : 0; + packed.features |= material->HasEmissiveMap() ? Renderer::MaterialFeatures::FEATURE_EMISSIVE_MAP : 0; packed.features |= glm::length(material->transmissiveColor) > 0.0f ? Renderer::MaterialFeatures::FEATURE_TRANSMISSION : 0; packed.features |= material->vertexColors ? Renderer::MaterialFeatures::FEATURE_VERTEX_COLORS : 0; @@ -259,6 +260,8 @@ namespace Atlas::Scene { textures.insert(material->aoMap.Get()); if (material->HasDisplacementMap()) textures.insert(material->displacementMap.Get()); + if (material->HasEmissiveMap()) + textures.insert(material->emissiveMap.Get()); } for (const auto& texture : textures) { From b14e28791920dfa505b88e92df53a4c3f1e785df Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 12 Sep 2024 21:14:25 +0200 Subject: [PATCH 35/66] Fixed threading issues --- src/engine/ecs/EntityManager.cpp | 4 ++-- src/engine/ecs/Pools.h | 31 ++++++++++++++++++--------- src/engine/ecs/TypeIndex.h | 5 +++-- src/engine/loader/ModelImporter.cpp | 9 ++++++-- src/engine/scene/SceneRenderState.cpp | 15 ++++++------- 5 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/engine/ecs/EntityManager.cpp b/src/engine/ecs/EntityManager.cpp index 11760cf16..dd0c61537 100644 --- a/src/engine/ecs/EntityManager.cpp +++ b/src/engine/ecs/EntityManager.cpp @@ -52,7 +52,7 @@ namespace Atlas { entities.clear(); destroyed.clear(); - pools.data.clear(); + pools.Clear(); } @@ -83,4 +83,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/ecs/Pools.h b/src/engine/ecs/Pools.h index ddd5f24bd..4704fa64f 100644 --- a/src/engine/ecs/Pools.h +++ b/src/engine/ecs/Pools.h @@ -3,7 +3,7 @@ #include "Pool.h" #include "TypeIndex.h" -#include +#include #include #include @@ -18,14 +18,23 @@ namespace Atlas { template Pool& Get(); + + void Clear() { + + for (auto& poolData : data) { + poolData.storage.reset(); + } + + } private: struct PoolData { - uint64_t idx; - std::shared_ptr storage; + std::shared_ptr storage = nullptr; }; + + static constexpr uint64_t dataCount = 1024; - std::vector data; + std::array data; friend class EntityManager; @@ -36,19 +45,21 @@ namespace Atlas { Storage* storage = nullptr; auto idx = TypeIndex::Get(); - auto find = std::find_if(data.begin(), data.end(), [idx](const auto& poolData) { return idx == poolData.idx; }); + + AE_ASSERT(idx < dataCount && "Too many component types stored. Please increase pool capacity"); + auto& poolData = data[idx]; - if (find != data.end()) { + if (poolData.storage != nullptr) { - storage = find->storage.get(); + storage = poolData.storage.get(); } else { // https://stackoverflow.com/questions/15783342/should-i-use-c11-emplace-back-with-pointers-containters // Need shared_ptr here such that destructor of Pool is called, not destructor of Storage - data.emplace_back(PoolData{ idx, std::make_shared>() }); - storage = data.back().storage.get(); + poolData.storage = std::make_shared>(); + storage = poolData.storage.get(); } @@ -58,4 +69,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/ecs/TypeIndex.h b/src/engine/ecs/TypeIndex.h index 24e2bafea..73fb8f28d 100644 --- a/src/engine/ecs/TypeIndex.h +++ b/src/engine/ecs/TypeIndex.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Atlas { @@ -28,7 +29,7 @@ namespace Atlas { private: static uint64_t Identifier() noexcept { - static uint64_t value = 0; + static std::atomic value = 0; return value++; } @@ -37,4 +38,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index 7f4587db0..e12471973 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -251,6 +251,8 @@ namespace Atlas { std::vector meshes; meshes.resize(state.scene->mNumMeshes); + + std::mutex vertexColorMutex; JobGroup group; JobSystem::ExecuteMultiple(group, int32_t(meshes.size()), [&](const JobData& data) { @@ -303,7 +305,10 @@ namespace Atlas { tangents.SetElementCount(hasTangents ? vertexCount : 0); colors.SetElementCount(hasVertexColors ? vertexCount : 0); - material->vertexColors &= hasVertexColors; + { + std::scoped_lock lock(vertexColorMutex); + material->vertexColors &= hasVertexColors; + } meshData.materials.push_back(material); auto min = vec3(std::numeric_limits::max()); @@ -969,4 +974,4 @@ namespace Atlas { } -} \ No newline at end of file +} diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 765842b43..93d082037 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -281,12 +281,12 @@ namespace Atlas::Scene { void SceneRenderState::UpdateOtherTextureBindlessData() { + auto lightSubset = scene->GetSubset(); JobSystem::Wait(bindlessOtherTextureMapUpdateJob); - JobSystem::Execute(bindlessOtherTextureMapUpdateJob, [&](JobData&) { - auto lightSubset = scene->entityManager.GetSubset(); + JobSystem::Execute(bindlessOtherTextureMapUpdateJob, [lightSubset](JobData&) { for (auto entity : lightSubset) { - const auto& lightComponent = lightSubset.Get(entity); + const auto& lightComponent = entity.GetComponent(); if (!lightComponent.shadow) continue; @@ -308,15 +308,14 @@ namespace Atlas::Scene { return; JobSystem::Wait(fillRenderListJob); + + auto lightSubset = scene->GetSubset(); + auto camera = scene->GetMainCamera(); - JobSystem::Execute(fillRenderListJob, [&](JobData&) { - auto& camera = scene->GetMainCamera(); - + JobSystem::Execute(fillRenderListJob, [&, lightSubset, camera](JobData&) { auto meshes = scene->GetMeshes(); renderList.NewFrame(scene); - auto lightSubset = scene->GetSubset(); - JobGroup group; for (auto& lightEntity : lightSubset) { From f1c43d1dd3868f1b70288f56b71fde8ffff0ba93 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 12 Sep 2024 23:18:25 +0200 Subject: [PATCH 36/66] Up to 4096 lights in the frustum can now be visible --- data/shader/deferred/direct.csh | 21 +++++++++++- data/shader/globals.hsh | 4 +-- data/shader/shadow.hsh | 4 +-- src/engine/ecs/EntityManager.cpp | 2 ++ src/engine/renderer/DirectLightRenderer.cpp | 4 +++ src/engine/renderer/MainRenderer.cpp | 13 +++++--- src/engine/scene/Scene.cpp | 15 +++++---- src/engine/scene/SceneRenderState.cpp | 36 ++++++++++++++------- src/engine/scene/SceneRenderState.h | 5 +-- 9 files changed, 75 insertions(+), 29 deletions(-) diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 46e97c9d5..a084b9240 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -63,10 +63,12 @@ void main() { direct = vec3(.0); - for (int i = 0; i < pushConstants.lightCount && i < 8; i++) { + for (int i = 0; i < pushConstants.lightCount; i++) { Light light = lights[i]; +#ifndef AE_BINDLESS light.shadow.mapIdx = pushConstants.mapIndices[i]; +#endif bool isMain = i == 0 ? true : false; direct += EvaluateLight(light, surface, geometryNormal, isMain); } @@ -160,18 +162,35 @@ float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometr -geometryNormal : geometryNormal : geometryNormal; if (lightType == DIRECTIONAL_LIGHT) { +#ifdef AE_BINDLESS + shadowFactor = CalculateCascadedShadow(light.shadow, bindlessTextureArrays[nonuniformEXT(light.shadow.mapIdx)], + shadowSampler, surface.P, vec3(vec2(pixel) + 0.5, 0.0), + shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); +#else shadowFactor = CalculateCascadedShadow(light.shadow, cascadeMaps[nonuniformEXT(light.shadow.mapIdx)], shadowSampler, surface.P, vec3(vec2(pixel) + 0.5, 0.0), shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); +#endif } else if (lightType == POINT_LIGHT) { +#ifdef AE_BINDLESS + shadowFactor = CalculatePointShadow(light.shadow, bindlessCubemaps[nonuniformEXT(light.shadow.mapIdx)], + shadowSampler, surface.P); +#else shadowFactor = CalculatePointShadow(light.shadow, cubeMaps[nonuniformEXT(light.shadow.mapIdx)], shadowSampler, surface.P); +#endif } else if (lightType == SPOT_LIGHT) { +#ifdef AE_BINDLESS + shadowFactor = CalculateSpotShadow(light.shadow, bindlessTextureArrays[nonuniformEXT(light.shadow.mapIdx)], + shadowSampler, surface.P, vec3(vec2(pixel) + 0.5, 0.0), + shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); +#else shadowFactor = CalculateSpotShadow(light.shadow, cascadeMaps[nonuniformEXT(light.shadow.mapIdx)], shadowSampler, surface.P, vec3(vec2(pixel) + 0.5, 0.0), shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); +#endif } if (isMain) { diff --git a/data/shader/globals.hsh b/data/shader/globals.hsh index d3e8b4118..0afa8752e 100644 --- a/data/shader/globals.hsh +++ b/data/shader/globals.hsh @@ -36,8 +36,8 @@ layout(set = 1, binding = 31, std140) uniform GlobalBuffer { } globalData; layout(set = 0, binding = 3) uniform texture2D bindlessTextures[TEXTURE_COUNT]; -layout(set = 0, binding = 4) uniform texture2D bindlessCubemaps[CUBEMAP_COUNT]; -layout(set = 0, binding = 5) uniform texture2D bindlessTextureArrays[TEXTURE_ARRAY_COUNT]; +layout(set = 0, binding = 4) uniform textureCube bindlessCubemaps[CUBEMAP_COUNT]; +layout(set = 0, binding = 5) uniform texture2DArray bindlessTextureArrays[TEXTURE_ARRAY_COUNT]; layout(set = 1, binding = 13) uniform sampler2D dfgTexture; diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh index dfcc33bde..c8c6edab7 100644 --- a/data/shader/shadow.hsh +++ b/data/shader/shadow.hsh @@ -576,7 +576,7 @@ vec3 sampleOffsetDirections[20] = vec3[] ( float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSampler, vec3 position) { - int samples = 20; + int samples = 20; float diskRadius = shadow.edgeSoftness; vec4 shadowCoords = shadow.cascades[1].cascadeSpace * vec4(position, 1.0); @@ -597,7 +597,7 @@ float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSam } -float CalculateSpotShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, +float CalculateSpotShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 fragmentPosition, vec3 position, vec3 normal, float cosTheta) { float distance = -fragmentPosition.z; diff --git a/src/engine/ecs/EntityManager.cpp b/src/engine/ecs/EntityManager.cpp index dd0c61537..ce13c4416 100644 --- a/src/engine/ecs/EntityManager.cpp +++ b/src/engine/ecs/EntityManager.cpp @@ -39,6 +39,8 @@ namespace Atlas { entities[pos] = EntityConfig::InvalidEntity; for (auto& poolData : pools.data) { + if (!poolData.storage) + continue; if (poolData.storage->Contains(entity)) poolData.storage->Erase(entity); } diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index 35a647cce..853c059d2 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -40,6 +40,9 @@ namespace Atlas { std::vector> cubeMaps; PushConstants pushConstants; +#ifdef AE_BINDLESS + pushConstants.lightCount = std::min(4096, int32_t(renderState->lightEntities.size())); +#else pushConstants.lightCount = std::min(8, int32_t(renderState->lightEntities.size())); for (int32_t i = 0; i < pushConstants.lightCount; i++) { auto& comp = renderState->lightEntities[i].comp; @@ -59,6 +62,7 @@ namespace Atlas { commandList->BindSampledImages(cascadeMaps, 3, 6); commandList->BindSampledImages(cubeMaps, 3, 14); +#endif pipelineConfig.ManageMacro("SCREEN_SPACE_SHADOWS", sss && sss->enable); pipelineConfig.ManageMacro("CLOUD_SHADOWS", clouds && clouds->enable && clouds->castShadow); diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 608d305de..832170ff3 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -141,9 +141,14 @@ namespace Atlas { // Wait as long as possible for this to finish JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); JobSystem::WaitSpin(renderState->prepareBindlessTexturesJob); + JobSystem::WaitSpin(renderState->bindlessOtherTextureMapUpdateJob); commandList->BindBuffers(renderState->triangleBuffers, 0, 1); - if (renderState->images.size()) - commandList->BindSampledImages(renderState->images, 0, 3); + if (renderState->textures.size()) + commandList->BindSampledImages(renderState->textures, 0, 3); + if (renderState->cubemaps.size()) + commandList->BindSampledImages(renderState->cubemaps, 0, 4); + if (renderState->textureArrays.size()) + commandList->BindSampledImages(renderState->textureArrays, 0, 5); if (device->support.hardwareRayTracing) { commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); @@ -468,8 +473,8 @@ namespace Atlas { commandList->BindSampler(globalSampler, 1, 14); commandList->BindSampler(globalNearestSampler, 1, 16); commandList->BindBuffers(renderState->triangleBuffers, 0, 1); - if (renderState->images.size()) - commandList->BindSampledImages(renderState->images, 0, 3); + if (renderState->textures.size()) + commandList->BindSampledImages(renderState->textures, 0, 3); if (device->support.hardwareRayTracing) { commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index e6cb7c688..cb6ffdb89 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -97,13 +97,6 @@ namespace Atlas { // Do cleanup first such that we work with valid data CleanupUnusedResources(); -#ifdef AE_BINDLESS - renderState.UpdateMeshBindlessData(); - renderState.UpdateTextureBindlessData(); - renderState.UpdateOtherTextureBindlessData(); -#endif - renderState.PrepareMaterials(); - // Update scripting components (but only after the first timestep when everything else is settled) if (!firstTimestep) { // Work with a copy here @@ -117,6 +110,14 @@ namespace Atlas { } } + // Can only update after scripts were run +#ifdef AE_BINDLESS + renderState.UpdateMeshBindlessData(); + renderState.UpdateTextureBindlessData(); + renderState.UpdateOtherTextureBindlessData(); +#endif + renderState.PrepareMaterials(); + TransformComponent rootTransform = {}; auto hierarchyTransformSubset = entityManager.GetSubset(); diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 93d082037..ed52efe30 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -218,15 +218,13 @@ namespace Atlas::Scene { auto bindlessTextureBuffersUpdate = [&](JobData&) { JobSystem::Wait(bindlessTextureMapUpdateJob); - if (images.size() < textureToBindlessIdx.size()) { - images.resize(textureToBindlessIdx.size()); + if (textures.size() < textureToBindlessIdx.size()) { + textures.resize(textureToBindlessIdx.size()); } - for (const auto& [texture, idx] : textureToBindlessIdx) { + for (const auto& [texture, idx] : textureToBindlessIdx) + textures[idx] = texture->image; - images[idx] = texture->image; - - } }; auto bindlessTextureMapUpdate = [&, bindlessTextureBuffersUpdate](JobData&) { @@ -284,7 +282,10 @@ namespace Atlas::Scene { auto lightSubset = scene->GetSubset(); JobSystem::Wait(bindlessOtherTextureMapUpdateJob); - JobSystem::Execute(bindlessOtherTextureMapUpdateJob, [lightSubset](JobData&) { + JobSystem::Execute(bindlessOtherTextureMapUpdateJob, [&, lightSubset](JobData&) { + + uint32_t textureArrayIdx = 0; + uint32_t cubemapIdx = 0; for (auto entity : lightSubset) { const auto& lightComponent = entity.GetComponent(); @@ -292,12 +293,23 @@ namespace Atlas::Scene { continue; if (lightComponent.shadow->useCubemap) { - + cubemapToBindlessIdx[lightComponent.shadow->cubemap] = cubemapIdx++; } else { - + textureArrayToBindlessIdx[lightComponent.shadow->maps] = textureArrayIdx++; } } + + if (cubemaps.size() < cubemapToBindlessIdx.size()) + cubemaps.resize(cubemapToBindlessIdx.size()); + for (const auto& [cubemap, idx] : cubemapToBindlessIdx) + cubemaps[idx] = cubemap->image; + + if (textureArrays.size() < textureArrayToBindlessIdx.size()) + textureArrays.resize(textureArrayToBindlessIdx.size()); + for (const auto& [textureArray, idx] : textureArrayToBindlessIdx) + textureArrays[idx] = textureArray->image; + }); } @@ -373,7 +385,7 @@ namespace Atlas::Scene { auto& light = lightEntity.GetComponent(); if (!light.IsVisible(camera.frustum)) continue; - lightEntities.emplace_back(LightEntity{ lightEntity, light, -1 }); + lightEntities.emplace_back(LightEntity{ lightEntity, light }); } if (lightEntities.size() > 1) { @@ -399,6 +411,8 @@ namespace Atlas::Scene { }); } + JobSystem::Wait(bindlessOtherTextureMapUpdateJob); + std::vector lights; if (lightEntities.size()) { lights.reserve(lightEntities.size()); @@ -443,7 +457,7 @@ namespace Atlas::Scene { shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; shadowUniform.cascadeCount = shadow->viewCount; shadowUniform.resolution = vec2(shadow->resolution); - shadowUniform.mapIdx = entity.mapIdx; + shadowUniform.mapIdx = shadow->useCubemap ? cubemapToBindlessIdx[shadow->cubemap] : textureArrayToBindlessIdx[shadow->maps]; auto componentCount = shadow->viewCount; for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index 522c8b829..1486d00cf 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -20,7 +20,6 @@ namespace Atlas::Scene { struct LightEntity { Entity entity; LightComponent comp; - int32_t mapIdx = -1; }; class SceneRenderState { @@ -49,7 +48,9 @@ namespace Atlas::Scene { Buffer::Buffer materialBuffer; Buffer::Buffer lightBuffer; - std::vector> images; + std::vector> textures; + std::vector> textureArrays; + std::vector> cubemaps; std::vector> blasBuffers; std::vector> triangleBuffers; std::vector> bvhTriangleBuffers; From eb12dc0e602b23f700fca322daf62e9c21ed784c Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Fri, 13 Sep 2024 23:52:07 +0200 Subject: [PATCH 37/66] Improved UI + UI performance --- src/editor/App.cpp | 3 + src/editor/ContentDiscovery.cpp | 8 +- src/editor/ContentDiscovery.h | 1 + .../ui/windows/ContentBrowserWindow.cpp | 92 ++++++++++++++----- src/editor/ui/windows/ContentBrowserWindow.h | 5 +- src/editor/ui/windows/LogWindow.cpp | 13 ++- src/editor/ui/windows/LogWindow.h | 3 + vcpkg.json | 2 +- 8 files changed, 96 insertions(+), 31 deletions(-) diff --git a/src/editor/App.cpp b/src/editor/App.cpp index 7b2355744..ce5303c35 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -368,8 +368,11 @@ namespace Atlas::Editor { } } + auto target = Singletons::renderTarget; + ImGui::SetWindowFontScale(1.5f); ImGui::Text("Frame time: %.3fms, GPU time: %.3f", Clock::GetAverage() * 1000.0f, float(slowestTime / 1000000.0)); + ImGui::Text("Resolution %dx%d upscaled from %dx%d", target->GetWidth(), target->GetHeight(), target->GetScaledWidth(), target->GetScaledHeight()); ImGui::SetWindowFontScale(1.0f); } diff --git a/src/editor/ContentDiscovery.cpp b/src/editor/ContentDiscovery.cpp index b0d855cbf..7081bb8ff 100644 --- a/src/editor/ContentDiscovery.cpp +++ b/src/editor/ContentDiscovery.cpp @@ -101,7 +101,11 @@ namespace Atlas::Editor { assetPath.erase(assetPath.begin()); if (dirEntry.is_directory()) { + auto dirname = Common::Path::GetFileName(dirEntry.path()); + std::transform(dirname.begin(), dirname.end(), dirname.begin(), ::tolower); + auto childDirectory = CreateRef({ + .name = dirname, .path = dirEntry.path(), .assetPath = assetPath }); @@ -132,13 +136,13 @@ namespace Atlas::Editor { // Sort for directories to be ordered alphabetically std::sort(directory->directories.begin(), directory->directories.end(), [](const Ref& dir0, const Ref& dir1) { - return dir0->path < dir1->path; + return dir0->name < dir1->name; }); // Sort for files to be ordered alphabetically std::sort(directory->files.begin(), directory->files.end(), [](const Content& file0, const Content& file1) { - return file0.path < file1.path; + return file0.name < file1.name; }); } diff --git a/src/editor/ContentDiscovery.h b/src/editor/ContentDiscovery.h index 6462fe43e..7d14df4d5 100644 --- a/src/editor/ContentDiscovery.h +++ b/src/editor/ContentDiscovery.h @@ -10,6 +10,7 @@ namespace Atlas::Editor { struct ContentDirectory { + std::string name; std::filesystem::path path; std::string assetPath; diff --git a/src/editor/ui/windows/ContentBrowserWindow.cpp b/src/editor/ui/windows/ContentBrowserWindow.cpp index 567eac237..4cd68e607 100644 --- a/src/editor/ui/windows/ContentBrowserWindow.cpp +++ b/src/editor/ui/windows/ContentBrowserWindow.cpp @@ -22,7 +22,7 @@ namespace Atlas::Editor::UI { ContentBrowserWindow::ContentBrowserWindow(bool show) : Window("Content browser", show) { - + selectionStorage.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return uint32_t(idx); }; } @@ -99,7 +99,7 @@ namespace Atlas::Editor::UI { ImGui::Begin("ResourceTypeOverview", nullptr); // Use a child as a dummy to create a drop target, since it doesn't work directly on a window - ImGui::BeginChild("ResourceTypeDropChild"); + ImGui::BeginChild("ResourceTypeDropChild", ImVec2(0.0, 0.0)); RenderDirectoryControl(); @@ -224,10 +224,15 @@ namespace Atlas::Editor::UI { void ContentBrowserWindow::RenderDirectoryContent() { float totalWidth = ImGui::GetContentRegionAvail().x; - auto columnItemCount = int32_t(totalWidth / itemSize); - columnItemCount = columnItemCount <= 0 ? 1 : columnItemCount; + auto columnCount = int32_t(totalWidth / itemSize); + columnCount = columnCount <= 0 ? 1 : columnCount; + + float columnSize = totalWidth / float(columnCount); - ImGui::Columns(columnItemCount, nullptr, false); + auto entryCount = int32_t(directories.size()) + int32_t(files.size()); + ImGuiMultiSelectIO* multiSelectionIO = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_BoxSelect2d | + ImGuiMultiSelectFlags_ClearOnClickVoid, selectionStorage.Size, entryCount); + selectionStorage.ApplyRequests(multiSelectionIO); if (!std::filesystem::exists(currentDirectory)) { auto message = "Content directory " + Common::Path::Normalize(currentDirectory) + " has been moved or deleted."; @@ -241,14 +246,27 @@ namespace Atlas::Editor::UI { nextDirectory = std::string(); + ImGui::SetCursorPosX(padding); + + int32_t entryIdx = 0; + float columnHeight = 0.0f; for (const auto& directory : directories) { - RenderContentEntry(directory->path, directory->assetPath, ContentType::None); + // Ignore 'invisible' directories + if (directory->assetPath.at(0) == '.') + continue; + + RenderContentEntry(directory->path, directory->assetPath, ContentType::None, + entryIdx++, columnCount, columnSize, columnHeight); } for (const auto& file : files) { - RenderContentEntry(file.path, file.assetPath, file.type); + RenderContentEntry(file.path, file.assetPath, file.type, + entryIdx++, columnCount, columnSize, columnHeight); } + multiSelectionIO = ImGui::EndMultiSelect(); + selectionStorage.ApplyRequests(multiSelectionIO); + if (ImGui::BeginPopupContextWindow(nullptr, ImGuiPopupFlags_NoOpenOverItems | ImGuiPopupFlags_MouseButtonRight)) { if (ImGui::BeginMenu("Create")) { if (ImGui::MenuItem("Folder")) { @@ -277,16 +295,15 @@ namespace Atlas::Editor::UI { } - void ContentBrowserWindow::RenderContentEntry(const std::filesystem::path& path, const std::string& assetPath, ContentType contentType) { + void ContentBrowserWindow::RenderContentEntry(const std::filesystem::path& path, const std::string& assetPath, + ContentType contentType, int32_t entryIdx, int32_t columnCount, float columnSize, float& columnHeight) { bool isDirectory = contentType == ContentType::None; - // Ignore 'invisible' directories - if (isDirectory && assetPath.at(0) == '.') - return; auto filename = Common::Path::GetFileName(assetPath); ImVec2 buttonSize = ImVec2(iconSize, iconSize); + auto cursorPos = ImGui::GetCursorPos(); ImGui::BeginGroup(); @@ -310,15 +327,23 @@ namespace Atlas::Editor::UI { type = Content::contentTypeMapping.at(fileType); auto assetRelativePath = Common::Path::Normalize(assetPath); - auto buttonFlags = isDirectory || type == ContentType::Scene ? ImGuiButtonFlags_PressedOnDoubleClick : 0; - if (ImGui::ImageButtonEx(ImGui::GetID("ImageButton"), set, buttonSize, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), - ImVec4(0.0f, 0.0f, 0.0f, 0.0f), ImVec4(1.0f, 1.0f, 1.0f, 1.0f), buttonFlags)) { - if (isDirectory) - nextDirectory = path.string(); - else if (type == ContentType::Scene) - FileImporter::ImportFile(assetRelativePath); + + // Add selectable to allow for multi-select + bool selected = selectionStorage.Contains((ImGuiID)entryIdx); + ImGui::SetNextItemSelectionUserData(entryIdx); + if (ImGui::Selectable("##Selectable", &selected, ImGuiSelectableFlags_None, buttonSize)); + + if (ImGui::IsItemHovered()) { + if (ImGui::IsMouseDoubleClicked(0)) { + if (isDirectory) + nextDirectory = path.string(); + else if (type == ContentType::Scene) + FileImporter::ImportFile(assetRelativePath); + } } + ImGui::SetItemAllowOverlap(); + if (!isDirectory && ImGui::BeginDragDropSource()) { // Size doesn't count the termination character, so add +1 ImGui::SetDragDropPayload("ContentBrowserResource", assetRelativePath.data(), assetRelativePath.size() + 1); @@ -352,7 +377,7 @@ namespace Atlas::Editor::UI { std::filesystem::copy(path, dupFilePath); } - if (ImGui::MenuItem("Rename") && !isDirectory) { + if (ImGui::MenuItem("Rename")) { renamePopupVisible = true; auto dirEntryFilename = path.filename(); renameString = dirEntryFilename.replace_extension("").string(); @@ -365,23 +390,44 @@ namespace Atlas::Editor::UI { ImGui::EndPopup(); } + // Just draw the icon if it is actually visible + if (ImGui::IsItemVisible()) { + ImGui::SameLine(); + ImGui::SetCursorPosX(cursorPos.x); + ImGui::Image(set, buttonSize); + } + ImGui::PopStyleColor(); auto offset = 0.0f; auto textSize = ImGui::CalcTextSize(filename.c_str()); - if (textSize.x < iconSize + padding) - offset = (iconSize + padding - textSize.x) / 2.0f; + if (textSize.x < iconSize) + offset = (iconSize - textSize.x) / 2.0f; auto cursorX = ImGui::GetCursorPosX(); ImGui::SetCursorPosX(cursorX + offset); - ImGui::TextWrapped("%s", filename.c_str()); + + ImGui::PushTextWrapPos(cursorX + buttonSize.x); + ImGui::Text("%s", filename.c_str()); + ImGui::PopTextWrapPos(); ImGui::PopID(); ImGui::EndGroup(); - ImGui::NextColumn(); + // Advance to next column + columnHeight = std::max(ImGui::GetCursorPosY() - cursorPos.y, columnHeight); + + ImGui::SetCursorPosX(((entryIdx + 1) % columnCount) * columnSize + padding); + if ((entryIdx + 1) % columnCount == 0) { + cursorPos.y = cursorPos.y + columnHeight; + ImGui::SetCursorPosY(cursorPos.y); + columnHeight = 0.0f; + } + else { + ImGui::SetCursorPosY(cursorPos.y); + } } diff --git a/src/editor/ui/windows/ContentBrowserWindow.h b/src/editor/ui/windows/ContentBrowserWindow.h index d330e88e8..ca798a110 100644 --- a/src/editor/ui/windows/ContentBrowserWindow.h +++ b/src/editor/ui/windows/ContentBrowserWindow.h @@ -32,7 +32,8 @@ namespace Atlas::Editor::UI { void RenderDirectoryContent(); - void RenderContentEntry(const std::filesystem::path& path, const std::string& assetPath, ContentType contentType); + void RenderContentEntry(const std::filesystem::path& path, const std::string& assetPath, + ContentType contentType, int32_t entryIdx, int32_t columnCount, float columnSize, float& columnHeight); bool IsValidFileType(const std::string& filename); @@ -61,6 +62,8 @@ namespace Atlas::Editor::UI { JobGroup searchAndFilterJob{ JobPriority::Medium }; + ImGuiSelectionBasicStorage selectionStorage; + const float padding = 8.0f; const float iconSize = 64.f; const float itemSize = iconSize + 2.0f * padding; diff --git a/src/editor/ui/windows/LogWindow.cpp b/src/editor/ui/windows/LogWindow.cpp index 2014ff86c..642375cae 100644 --- a/src/editor/ui/windows/LogWindow.cpp +++ b/src/editor/ui/windows/LogWindow.cpp @@ -12,10 +12,15 @@ namespace Atlas::Editor::UI { auto darkMode = Singletons::config->darkMode; - static size_t entriesCount = 0; - auto entries = Atlas::Log::GetLatestEntries(10000); for (auto& entry : entries) { + + ImGui::Text(""); + if (!ImGui::IsItemVisible()) { + continue; + } + ImGui::SameLine(); + std::string logText; logText.append("[" + std::to_string(entry.time) + "] "); logText.append(entry.message); @@ -40,9 +45,9 @@ namespace Atlas::Editor::UI { ImGui::PopStyleColor(); } - if (entriesCount != entries.size()) { + if (logEntryCount != entries.size()) { + logEntryCount = entries.size(); ImGui::SetScrollHereY(1.0f); - entriesCount = entries.size(); } End(); diff --git a/src/editor/ui/windows/LogWindow.h b/src/editor/ui/windows/LogWindow.h index cb150c818..c6af70a7a 100644 --- a/src/editor/ui/windows/LogWindow.h +++ b/src/editor/ui/windows/LogWindow.h @@ -14,6 +14,9 @@ namespace Atlas::Editor::UI { private: std::string logSearch; + size_t logEntryCount = 0; + bool scroll = false; + }; } \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index 68dd576d1..12c8b40e5 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -68,7 +68,7 @@ }, { "name": "imgui", - "version": "1.90.7#1" + "version": "1.91.0#0" }, { "name": "vulkan-memory-allocator", From 94b7cd7e0783cf34a84a1869dd8feb2168a011a1 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Fri, 13 Sep 2024 23:52:25 +0200 Subject: [PATCH 38/66] Fixed a shader bug --- data/shader/deferred/texture.hsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shader/deferred/texture.hsh b/data/shader/deferred/texture.hsh index f9acddb6f..c225188af 100644 --- a/data/shader/deferred/texture.hsh +++ b/data/shader/deferred/texture.hsh @@ -131,7 +131,7 @@ vec3 SampleEmissive(vec2 texCoords, uint textureID, float bias) { #ifdef BINDLESS_TEXTURES return texture(sampler2D(bindlessTextures[textureID], bindlessSampler), texCoords, bias).rgb; #else - return texture(emissiveMap, texCoords, bias).r; + return texture(emissiveMap, texCoords, bias).rgb; #endif #else return vec3(0.0); From 7363785e4f243e64c80957fd5d7e393ce41d2d31 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 14 Sep 2024 21:34:42 +0200 Subject: [PATCH 39/66] A lot of editor UI changes --- libs/ImguiExtension/CMakeLists.txt | 3 +- libs/ImguiExtension/ImguiWrapper.cpp | 4 + libs/ImguiExtension/ImguiWrapper.h | 3 + .../panels/GPUProfilerPanel.cpp | 82 ++++++++++++- libs/ImguiExtension/panels/GPUProfilerPanel.h | 19 +++ src/editor/App.cpp | 41 ++++--- src/editor/App.h | 1 - src/editor/CMakeLists.txt | 3 +- src/editor/tools/CopyPasteHelper.cpp | 12 ++ src/editor/tools/CopyPasteHelper.h | 110 ++++++++++++++++++ src/editor/tools/FileSystemHelper.cpp | 102 ++++++++++++++++ src/editor/tools/FileSystemHelper.h | 31 +++++ .../ui/panels/EntityPropertiesPanel.cpp | 23 ++++ src/editor/ui/panels/EntityPropertiesPanel.h | 56 ++++++++- src/editor/ui/panels/SceneHierarchyPanel.cpp | 2 +- src/editor/ui/panels/SceneStatisticsPanel.cpp | 1 + .../components/PlayerComponentPanel.cpp | 3 + .../components/RigidBodyComponentPanel.cpp | 7 ++ .../ui/windows/ContentBrowserWindow.cpp | 79 +++++++++---- src/editor/ui/windows/ContentBrowserWindow.h | 6 + src/editor/ui/windows/LogWindow.cpp | 4 +- src/engine/Main.cpp | 2 +- src/engine/graphics/Profiler.cpp | 2 +- src/engine/physics/Body.h | 2 +- src/engine/physics/PhysicsWorld.cpp | 15 +++ src/engine/physics/PhysicsWorld.h | 4 + src/engine/scene/SceneRenderState.cpp | 11 +- .../scene/components/LightComponent.cpp | 17 +++ src/engine/scene/components/LightComponent.h | 2 +- .../scene/components/RigidBodyComponent.cpp | 10 ++ vcpkg.json | 5 + 31 files changed, 601 insertions(+), 61 deletions(-) create mode 100644 src/editor/tools/CopyPasteHelper.cpp create mode 100644 src/editor/tools/CopyPasteHelper.h create mode 100644 src/editor/tools/FileSystemHelper.cpp create mode 100644 src/editor/tools/FileSystemHelper.h diff --git a/libs/ImguiExtension/CMakeLists.txt b/libs/ImguiExtension/CMakeLists.txt index 5ad3fbfea..b5e477cde 100644 --- a/libs/ImguiExtension/CMakeLists.txt +++ b/libs/ImguiExtension/CMakeLists.txt @@ -24,9 +24,10 @@ foreach(SOURCE_FILE IN ITEMS ${IMGUI_SOURCE_FILES}) endforeach() find_package(imgui CONFIG REQUIRED) +find_package(implot CONFIG REQUIRED) # We cam do this here, since the ImguiExtension dependency uses the engine and therefore is always included # after the engine is added add_library(${PROJECT_NAME} STATIC ${IMGUI_SOURCE_FILES}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${ATLAS_ENGINE_COMPILE_DEFINITIONS}) -target_link_libraries(${PROJECT_NAME} imgui::imgui volk::volk volk::volk_headers SDL2::SDL2 GPUOpen::VulkanMemoryAllocator Jolt::Jolt) \ No newline at end of file +target_link_libraries(${PROJECT_NAME} imgui::imgui implot::implot volk::volk volk::volk_headers SDL2::SDL2 GPUOpen::VulkanMemoryAllocator Jolt::Jolt) \ No newline at end of file diff --git a/libs/ImguiExtension/ImguiWrapper.cpp b/libs/ImguiExtension/ImguiWrapper.cpp index 6d0cadf92..b9344db59 100644 --- a/libs/ImguiExtension/ImguiWrapper.cpp +++ b/libs/ImguiExtension/ImguiWrapper.cpp @@ -11,6 +11,8 @@ namespace Atlas::ImguiExtension { void ImguiWrapper::Load(Atlas::Window *window) { + ImPlot::CreateContext(); + // Setup back-end capabilities flags ImGuiIO &io = ImGui::GetIO(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) @@ -65,6 +67,8 @@ namespace Atlas::ImguiExtension { // Unsubscribe from all events ImGui_ImplVulkan_Shutdown(); + ImPlot::DestroyContext(); + pool.reset(); initialized = false; diff --git a/libs/ImguiExtension/ImguiWrapper.h b/libs/ImguiExtension/ImguiWrapper.h index caa847174..3284061dd 100644 --- a/libs/ImguiExtension/ImguiWrapper.h +++ b/libs/ImguiExtension/ImguiWrapper.h @@ -4,6 +4,9 @@ #include #include +// Implot +#include + // Atlas engine includes #include #include diff --git a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp index 9a668e253..f4578e3fd 100644 --- a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp +++ b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp @@ -1,6 +1,7 @@ #include "GPUProfilerPanel.h" #include "graphics/Profiler.h" +#include "Clock.h" namespace Atlas::ImguiExtension { @@ -10,8 +11,22 @@ namespace Atlas::ImguiExtension { bool enabled = Graphics::Profiler::enable; ImGui::Checkbox("Enable##Profiler", &enabled); + ImGui::Checkbox("Show graph##Profiler", &showGraph); Graphics::Profiler::enable = enabled; + UpdateGraphData(); + + if (showGraph) + RenderGraph(); + else + RenderTable(); + + ImGui::PopID(); + + } + + void GPUProfilerPanel::RenderTable() { + const char* items[] = { "Chronologically", "Max time", "Min time" }; static int item = 0; ImGui::Combo("Sort##Performance", &item, items, IM_ARRAYSIZE(items)); @@ -48,7 +63,6 @@ namespace Atlas::ImguiExtension { ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; if (ImGui::BeginTable("PerfTable", 2, flags)) { - // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); ImGui::TableSetupColumn("Elapsed (ms)", ImGuiTableColumnFlags_NoHide); ImGui::TableHeadersRow(); @@ -75,7 +89,71 @@ namespace Atlas::ImguiExtension { ImGui::EndTable(); } - ImGui::PopID(); + } + + void GPUProfilerPanel::RenderGraph() { + + auto dataSize = int32_t(frameTimes.size()); + + std::vector localFrameTimes(frameTimes.begin(), frameTimes.end()); + std::vector localGpuTimes(gpuTimes.begin(), gpuTimes.end()); + + auto availSize = ImGui::GetContentRegionAvail(); + + auto frameColor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); + ImPlot::PushStyleColor(ImPlotCol_PlotBorder, frameColor); + ImPlot::PushStyleColor(ImPlotCol_FrameBg, frameColor); + ImPlot::PushStyleVar(ImPlotStyleVar_PlotBorderSize, 0.0f); + + if (ImPlot::BeginPlot("Performance graph", availSize)) { + ImPlot::SetupAxes("Frames", "Time (ms)"); + ImPlot::SetupAxesLimits(0, timeWindowSize, 0, std::min(200.0f, maxFrameTime), ImPlotCond_Always); + ImPlot::SetupLegend(ImPlotLocation_SouthWest); + + ImPlot::PlotLine("Frame time", localFrameTimes.data(), dataSize); + ImPlot::PlotLine("GPU time", localGpuTimes.data(), dataSize); + + ImPlot::EndPlot(); + } + + ImPlot::PopStyleVar(); + ImPlot::PopStyleColor(); + ImPlot::PopStyleColor(); + + } + + void GPUProfilerPanel::UpdateGraphData() { + + auto gpuProfilerData = Graphics::Profiler::GetQueries(Graphics::Profiler::OrderBy::MAX_TIME); + + int32_t slowestThreadIdx = 0; + double slowestTime = 0.0; + for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { + const auto& threadData = gpuProfilerData[i]; + double threadTime = 0.0; + for (const auto& query : threadData.queries) { + threadTime += query.timer.elapsedTime; + } + if (threadTime > slowestTime) { + slowestTime = threadTime; + slowestThreadIdx = i; + } + } + + frameTimes.push_back(Clock::GetDelta() * 1000.0f); + gpuTimes.push_back(float(slowestTime / 1000000.0)); + + if (int32_t(frameTimes.size()) > timeWindowSize) { + frameTimes.pop_front(); + gpuTimes.pop_front(); + } + + maxFrameTime = 0.0f; + maxGpuTime = 0.0f; + for (int32_t i = 0; i < timeWindowSize; i++) { + maxFrameTime = std::max(frameTimes[i], maxFrameTime); + maxGpuTime = std::max(gpuTimes[i], maxGpuTime); + } } diff --git a/libs/ImguiExtension/panels/GPUProfilerPanel.h b/libs/ImguiExtension/panels/GPUProfilerPanel.h index 7af0ef17e..b7a2ceb42 100644 --- a/libs/ImguiExtension/panels/GPUProfilerPanel.h +++ b/libs/ImguiExtension/panels/GPUProfilerPanel.h @@ -4,6 +4,8 @@ #include "lighting/IrradianceVolume.h" +#include + namespace Atlas::ImguiExtension { class GPUProfilerPanel : public Panel { @@ -13,6 +15,23 @@ namespace Atlas::ImguiExtension { void Render(); + private: + void RenderTable(); + + void RenderGraph(); + + void UpdateGraphData(); + + bool showGraph = false; + + int32_t timeWindowSize = 1024; + + float maxFrameTime = 0.0f; + float maxGpuTime = 0.0f; + + std::deque frameTimes; + std::deque gpuTimes; + }; } \ No newline at end of file diff --git a/src/editor/App.cpp b/src/editor/App.cpp index ce5303c35..c476de6b7 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -5,7 +5,9 @@ #include "Notifications.h" #include "ContentDiscovery.h" #include "ui/panels/PopupPanels.h" +#include "tools/FileSystemHelper.h" #include +#include #include #include @@ -26,6 +28,7 @@ namespace Atlas::Editor { ContentDiscovery::Update(); ImGui::CreateContext(); + ImPlot::CreateContext(); ImGuiIO &io = ImGui::GetIO(); (void) io; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; @@ -59,10 +62,14 @@ namespace Atlas::Editor { mouseHandler = Input::MouseHandler(1.5f, 8.0f); keyboardHandler = Input::KeyboardHandler(7.0f, 5.0f); - if (Singletons::config->darkMode) + if (Singletons::config->darkMode) { ImGui::StyleColorsDark(); - else + ImPlot::StyleColorsDark(); + } + else { ImGui::StyleColorsLight(); + ImPlot::StyleColorsLight(); + } } @@ -70,6 +77,8 @@ namespace Atlas::Editor { Singletons::imguiWrapper->Unload(); + CopyPasteHelper::Clear(); + for (const auto& sceneWindow : sceneWindows) { if (sceneWindow->isPlaying) sceneWindow->StopPlaying(); @@ -81,6 +90,8 @@ namespace Atlas::Editor { Singletons::Destruct(); + ImPlot::DestroyContext(); + } void App::Update(float deltaTime) { @@ -226,6 +237,7 @@ namespace Atlas::Editor { ImGuizmo::BeginFrame(); // ImGui::ShowDemoWindow(); + // ImPlot::ShowDemoWindow(); ImGuiViewport *viewport = ImGui::GetMainViewport(); @@ -279,10 +291,14 @@ namespace Atlas::Editor { if (ImGui::BeginMenu("View")) { if (ImGui::MenuItem("Dark mode", nullptr, &config->darkMode)) { - if (config->darkMode) + if (config->darkMode) { ImGui::StyleColorsDark(); - else + ImPlot::StyleColorsDark(); + } + else { ImGui::StyleColorsLight(); + ImPlot::StyleColorsLight(); + } } ImGui::MenuItem("Reset layout", nullptr, &resetDockspaceLayout); @@ -443,22 +459,9 @@ namespace Atlas::Editor { // Also kind of a resource event Events::EventManager::DropEventDelegate.Subscribe([&](Events::DropEvent event) { if (!event.file.empty() && contentBrowserWindow.show) { - // Need to create a copy here auto destinationDirectory = Common::Path::GetAbsolute(contentBrowserWindow.currentDirectory); - JobSystem::Execute(fileImportGroup, [&, event, destinationDirectory](JobData&) { - try { - std::filesystem::copy(event.file, destinationDirectory, - std::filesystem::copy_options::overwrite_existing | - std::filesystem::copy_options::recursive); - } - catch (std::exception& e) { - auto message = "Error copying " + event.file + " to asset directory: " + e.what(); - Notifications::Push({ message, vec3(1.0f, 0.0f, 0.0f) }); - Log::Error(message); - } - }); - - Notifications::Push({"Copying " + event.file + " to asset directory"}); + + FileSystemHelper::Copy(event.file, destinationDirectory); } }); diff --git a/src/editor/App.h b/src/editor/App.h index 7f4cedede..295414b9d 100644 --- a/src/editor/App.h +++ b/src/editor/App.h @@ -54,7 +54,6 @@ namespace Atlas::Editor { size_t activeSceneIdx = 0; JobGroup bvhBuilderGroup; - JobGroup fileImportGroup; ImGuiID upperDockNodeID; diff --git a/src/editor/CMakeLists.txt b/src/editor/CMakeLists.txt index 996270e10..08638f88f 100644 --- a/src/editor/CMakeLists.txt +++ b/src/editor/CMakeLists.txt @@ -47,7 +47,8 @@ endif() # We want to use both ImGui and the AtlasEngine. For ImGui, the ATLAS_IMGUI option # needs to be turned on. -target_link_libraries (${PROJECT_NAME} AtlasEngine ImguiExtension unofficial::imguizmo::imguizmo Jolt::Jolt) +target_link_libraries (${PROJECT_NAME} AtlasEngine ImguiExtension + unofficial::imguizmo::imguizmo Jolt::Jolt) if (APPLE AND ATLAS_BUNDLE) set(path ${Vulkan_LIBRARY}) diff --git a/src/editor/tools/CopyPasteHelper.cpp b/src/editor/tools/CopyPasteHelper.cpp new file mode 100644 index 000000000..4867b4752 --- /dev/null +++ b/src/editor/tools/CopyPasteHelper.cpp @@ -0,0 +1,12 @@ +#include "CopyPasteHelper.h" + +namespace Atlas::Editor { + + std::type_index CopyPasteHelper::typeInfo = typeid(CopyPasteHelper); + + void* CopyPasteHelper::data = nullptr; + size_t CopyPasteHelper::elementCount = 0; + size_t CopyPasteHelper::elementSize = 0; + std::function CopyPasteHelper::destructor; + +} \ No newline at end of file diff --git a/src/editor/tools/CopyPasteHelper.h b/src/editor/tools/CopyPasteHelper.h new file mode 100644 index 000000000..885913229 --- /dev/null +++ b/src/editor/tools/CopyPasteHelper.h @@ -0,0 +1,110 @@ +#pragma once + +#include "../FileImporter.h" + +#include "resource/ResourceManager.h" + +#include +#include + +namespace Atlas::Editor { + + class CopyPasteHelper { + + public: + template + static void Copy(T& copy) { + + Copy(©, 1); + + } + + template + static void CopyMulti(std::vector& copy) { + + Copy(copy.data(), copy.size()); + + } + + template + static bool AcceptPaste(bool acceptMultiValue = false) { + + return typeid(T) == typeInfo && data != nullptr && + (elementCount == 1 || acceptMultiValue && elementCount >= 1); + + } + + template + static void Paste(T& paste) { + + AE_ASSERT(elementCount == 1 && "Can't paste multi value, call PasteMulti() instead"); + Paste(&paste, 1); + + } + + template + static void PasteMulti(std::vector& paste) { + + if (paste.size() != elementCount) + paste.resize(elementCount); + + Paste(paste.data(), elementCount); + + } + + static void Clear() { + + if (data != nullptr) { + auto ptr = static_cast(data); + for (int32_t i = 0; i < elementCount; i++) { + ptr += elementSize; + destructor(static_cast(ptr)); + } + std::free(data); + } + + data = nullptr; + elementCount = 0; + + } + + private: + template + static void Copy(T* source, size_t count) { + + Clear(); + + elementCount = count; + + typeInfo = typeid(T); + data = std::malloc(sizeof(T) * elementCount); + + T* typeData = static_cast(data); + for (size_t i = 0; i < elementCount; i++) + typeData[i] = source[i]; + + destructor = [](void* ptr) { + static_cast(ptr)->~T(); + }; + + } + + template + static void Paste(T* dst, size_t count) { + + T* typeData = static_cast(data); + for (size_t i = 0; i < count; i++) + dst[i] = typeData[i]; + + } + + static std::type_index typeInfo; + + static void* data; + static size_t elementCount; + static size_t elementSize; + static std::function destructor; + + }; + +} \ No newline at end of file diff --git a/src/editor/tools/FileSystemHelper.cpp b/src/editor/tools/FileSystemHelper.cpp new file mode 100644 index 000000000..333241d33 --- /dev/null +++ b/src/editor/tools/FileSystemHelper.cpp @@ -0,0 +1,102 @@ +#include "FileSystemHelper.h" +#include "Notifications.h" +#include "Log.h" +#include "common/Path.h" + +#include + +namespace Atlas::Editor { + + JobGroup FileSystemHelper::copyGroup; + JobGroup FileSystemHelper::deleteGroup; + JobGroup FileSystemHelper::duplicateGroup; + + void FileSystemHelper::Copy(const std::string& path, const std::string& destination) { + + std::vector paths = { path }; + Copy(paths, destination); + + } + + void FileSystemHelper::Copy(const std::vector& paths, const std::string& destination) { + + JobSystem::Execute(copyGroup, [paths, destination](JobData&) { + bool success = true; + for (const auto& path : paths) { + try { + std::filesystem::copy(path, destination, + std::filesystem::copy_options::overwrite_existing | + std::filesystem::copy_options::recursive); + } + catch (std::exception& e) { + success = false; + auto message = "Error copying " + path + " to asset directory: " + e.what(); + Notifications::Push({ message, vec3(1.0f, 0.0f, 0.0f) }); + Log::Error(message); + } + } + if (success) { + Notifications::Push({ "Finished copying file(s) to " + Common::Path::GetAbsolute(destination) }); + } + }); + + } + + void FileSystemHelper::Delete(const std::string& path) { + + std::vector paths = { path }; + Delete(paths); + + } + + void FileSystemHelper::Delete(const std::vector& paths) { + + JobSystem::Execute(deleteGroup, [paths](JobData&) { + bool success = true; + for (const auto& path : paths) { + try { + std::filesystem::remove_all(path); + } + catch (std::exception& e) { + success = false; + auto message = "Error deleting " + path + ": " + e.what(); + Notifications::Push({ message, vec3(1.0f, 0.0f, 0.0f) }); + Log::Error(message); + } + } + if (success) { + Notifications::Push({ "Successfully deleted files(s)" }); + } + }); + + } + + void FileSystemHelper::Duplicate(const std::string& path) { + + JobSystem::Execute(duplicateGroup, [path](JobData&) { + int32_t counter = 0; + auto filePath = std::filesystem::path(path); + auto dupFilePath = std::filesystem::path(path); + + try { + do { + dupFilePath = path; + dupFilePath.replace_extension(""); + auto replacement = dupFilePath.filename().string() + "(" + std::to_string(++counter) + ")"; + dupFilePath.replace_filename(replacement); + dupFilePath.replace_extension(filePath.extension()); + } while (std::filesystem::exists(dupFilePath) && counter < 20); + std::filesystem::copy(filePath, dupFilePath); + Notifications::Push({ "Successfully duplicated " + path }); + } + catch (std::exception& e) { + auto message = "Error duplicating " + path + ": " + e.what(); + Notifications::Push({ message, vec3(1.0f, 0.0f, 0.0f) }); + Log::Error(message); + } + }); + + + } + +} \ No newline at end of file diff --git a/src/editor/tools/FileSystemHelper.h b/src/editor/tools/FileSystemHelper.h new file mode 100644 index 000000000..85079d750 --- /dev/null +++ b/src/editor/tools/FileSystemHelper.h @@ -0,0 +1,31 @@ +#pragma once + +#include "jobsystem/JobSystem.h" + +#include +#include + + +namespace Atlas::Editor { + + class FileSystemHelper { + + public: + static void Copy(const std::string& path, const std::string& destination); + + static void Copy(const std::vector& paths, const std::string& destination); + + static void Delete(const std::string& path); + + static void Delete(const std::vector& paths); + + static void Duplicate(const std::string& path); + + private: + static JobGroup copyGroup; + static JobGroup deleteGroup; + static JobGroup duplicateGroup; + + }; + +} \ No newline at end of file diff --git a/src/editor/ui/panels/EntityPropertiesPanel.cpp b/src/editor/ui/panels/EntityPropertiesPanel.cpp index 07ce4a9ab..d7dd31311 100644 --- a/src/editor/ui/panels/EntityPropertiesPanel.cpp +++ b/src/editor/ui/panels/EntityPropertiesPanel.cpp @@ -1,5 +1,7 @@ #include "EntityPropertiesPanel.h" +#include "Notifications.h" + namespace Atlas::Editor::UI { void EntityPropertiesPanel::Render(Ref& scene, EntityProperties entityProperties) { @@ -180,6 +182,27 @@ namespace Atlas::Editor::UI { } } + // Paste components + if (ImGui::BeginPopupContextWindow(nullptr, ImGuiPopupFlags_NoOpenOverItems | ImGuiPopupFlags_MouseButtonRight)) { + if (ImGui::MenuItem("Paste")) { + if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else if (HandleComponentPaste(scene, entity)) {} + else { + Notifications::Push({"Invalid type to paste as a component."}); + } + } + + ImGui::EndPopup(); + } + } } \ No newline at end of file diff --git a/src/editor/ui/panels/EntityPropertiesPanel.h b/src/editor/ui/panels/EntityPropertiesPanel.h index 71c57a107..6f3d9a7ed 100644 --- a/src/editor/ui/panels/EntityPropertiesPanel.h +++ b/src/editor/ui/panels/EntityPropertiesPanel.h @@ -15,7 +15,12 @@ #include "components/CameraComponentPanel.h" #include "components/TextComponentPanel.h" +#include "tools/CopyPasteHelper.h" +#include "Notifications.h" + #include +#include +#include namespace Atlas::Editor::UI { @@ -32,6 +37,12 @@ namespace Atlas::Editor::UI { void Render(Ref& scene, EntityProperties entityProperties); private: + template + struct ComponentCopy { + Scene::Scene* scene; + T component; + }; + NameComponentPanel nameComponentPanel; TransformComponentPanel transformComponentPanel; MeshComponentPanel meshComponentPanel; @@ -52,7 +63,24 @@ namespace Atlas::Editor::UI { ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Framed; - if (ImGui::TreeNodeEx(name.c_str(), nodeFlags)) { + bool open = ImGui::TreeNodeEx(name.c_str(), nodeFlags); + + if (ImGui::BeginPopupContextItem(name.c_str())) { + // We shouldn't allow the user to delete the root entity + if (ImGui::MenuItem("Copy")) { + if constexpr (std::is_same_v) { + // Restore body creation settings, after the copy the current body id is not valid anymore due + // to body recreation + component.creationSettings = CreateRef(component.GetBodyCreationSettings()); + } + ComponentCopy copy { scene.get(), component }; + CopyPasteHelper::Copy(copy); + } + + ImGui::EndPopup(); + } + + if (open) { resourceChanged = panel.Render(scene, entity, component); ImGui::TreePop(); @@ -61,6 +89,32 @@ namespace Atlas::Editor::UI { return resourceChanged; } + template + bool HandleComponentPaste(Ref& scene, Scene::Entity entity, std::optional> func = std::nullopt) { + + if (CopyPasteHelper::AcceptPaste>()) { + ComponentCopy copy; + CopyPasteHelper::Paste(copy); + + if (copy.scene != scene.get()) { + Notifications::Push({ "Cannot copy component from one scene to another", vec3(1.0f, 0.0f, 0.0f) }); + return true; + } + + if (entity.HasComponent()) + entity.RemoveComponent(); + + auto& comp = entity.AddComponent(copy.component); + if (func.has_value()) + func.value()(comp); + + return true; + } + + return false; + + } + }; } \ No newline at end of file diff --git a/src/editor/ui/panels/SceneHierarchyPanel.cpp b/src/editor/ui/panels/SceneHierarchyPanel.cpp index f14a97b94..0c127a5f8 100644 --- a/src/editor/ui/panels/SceneHierarchyPanel.cpp +++ b/src/editor/ui/panels/SceneHierarchyPanel.cpp @@ -98,7 +98,7 @@ namespace Atlas::Editor::UI { std::unordered_set& matchSet, bool inFocus, bool* selectionChanged) { ImGuiTreeNodeFlags baseFlags = ImGuiTreeNodeFlags_OpenOnArrow | - ImGuiTreeNodeFlags_OpenOnDoubleClick; + ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; auto hierarchyComponent = entity.TryGetComponent(); auto nameComponent = entity.TryGetComponent(); diff --git a/src/editor/ui/panels/SceneStatisticsPanel.cpp b/src/editor/ui/panels/SceneStatisticsPanel.cpp index 6a25f0368..ca113927d 100644 --- a/src/editor/ui/panels/SceneStatisticsPanel.cpp +++ b/src/editor/ui/panels/SceneStatisticsPanel.cpp @@ -31,6 +31,7 @@ namespace Atlas::Editor::UI { ImGui::Text("Entity count: %d", int32_t(scene->GetEntityCount())); ImGui::Text("Mesh count: %d", int32_t(meshes.size())); ImGui::Text("Material count: %d", int32_t(materials.size())); + ImGui::Text("Physics body count: %d", scene->physicsWorld->GetBodyCount()); } diff --git a/src/editor/ui/panels/components/PlayerComponentPanel.cpp b/src/editor/ui/panels/components/PlayerComponentPanel.cpp index ea9591c61..11816c154 100644 --- a/src/editor/ui/panels/components/PlayerComponentPanel.cpp +++ b/src/editor/ui/panels/components/PlayerComponentPanel.cpp @@ -9,6 +9,9 @@ namespace Atlas::Editor::UI { ImGui::PushID(GetNameID()); + if (!entity.HasComponent()) + ImGui::Text("Player component needs a transform component to work properly"); + ImGui::Text("Shape"); RenderShapeSettings(entity, playerComponent, *playerComponent.creationSettings); diff --git a/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp b/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp index 3358ac40d..73728a6b7 100644 --- a/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp +++ b/src/editor/ui/panels/components/RigidBodyComponentPanel.cpp @@ -7,7 +7,14 @@ namespace Atlas::Editor::UI { bool RigidBodyComponentPanel::Render(const Ref& scene, Scene::Entity entity, RigidBodyComponent &rigidBodyComponent) { + if (!entity.HasComponent()) + ImGui::Text("Rigid body component needs a transform component to work properly"); + auto creationSettings = rigidBodyComponent.GetBodyCreationSettings(); + if (!creationSettings.shape) { + ImGui::Text("Couldn't get body creation settings or shape"); + return false; + } ImGui::Text("Shape"); diff --git a/src/editor/ui/windows/ContentBrowserWindow.cpp b/src/editor/ui/windows/ContentBrowserWindow.cpp index 4cd68e607..136746dab 100644 --- a/src/editor/ui/windows/ContentBrowserWindow.cpp +++ b/src/editor/ui/windows/ContentBrowserWindow.cpp @@ -3,6 +3,8 @@ #include "DataCreator.h" #include "Notifications.h" #include "ui/panels/PopupPanels.h" +#include "tools/CopyPasteHelper.h" +#include "tools/FileSystemHelper.h" #include "mesh/Mesh.h" #include "scene/Scene.h" @@ -229,11 +231,6 @@ namespace Atlas::Editor::UI { float columnSize = totalWidth / float(columnCount); - auto entryCount = int32_t(directories.size()) + int32_t(files.size()); - ImGuiMultiSelectIO* multiSelectionIO = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_BoxSelect2d | - ImGuiMultiSelectFlags_ClearOnClickVoid, selectionStorage.Size, entryCount); - selectionStorage.ApplyRequests(multiSelectionIO); - if (!std::filesystem::exists(currentDirectory)) { auto message = "Content directory " + Common::Path::Normalize(currentDirectory) + " has been moved or deleted."; Notifications::Push({ .message = message, .color = vec3(1.0f, 1.0f, 0.0f) }); @@ -246,6 +243,11 @@ namespace Atlas::Editor::UI { nextDirectory = std::string(); + auto entryCount = int32_t(directories.size()) + int32_t(files.size()); + ImGuiMultiSelectIO* multiSelectionIO = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_BoxSelect2d | + ImGuiMultiSelectFlags_ClearOnClickVoid, selectionStorage.Size, entryCount); + selectionStorage.ApplyRequests(multiSelectionIO); + ImGui::SetCursorPosX(padding); int32_t entryIdx = 0; @@ -278,6 +280,12 @@ namespace Atlas::Editor::UI { ImGui::EndMenu(); } + if (CopyPasteHelper::AcceptPaste() && ImGui::MenuItem("Paste")) { + ContentCopy copy; + CopyPasteHelper::Paste(copy); + FileSystemHelper::Copy(copy.paths, Common::Path::GetAbsolute(currentDirectory)); + } + ImGui::EndPopup(); } @@ -331,7 +339,7 @@ namespace Atlas::Editor::UI { // Add selectable to allow for multi-select bool selected = selectionStorage.Contains((ImGuiID)entryIdx); ImGui::SetNextItemSelectionUserData(entryIdx); - if (ImGui::Selectable("##Selectable", &selected, ImGuiSelectableFlags_None, buttonSize)); + ImGui::Selectable("##Selectable", &selected, ImGuiSelectableFlags_None, buttonSize); if (ImGui::IsItemHovered()) { if (ImGui::IsMouseDoubleClicked(0)) { @@ -353,39 +361,37 @@ namespace Atlas::Editor::UI { } if (ImGui::BeginPopupContextItem()) { + auto singleSelect = selectionStorage.Size == 1; // Do a direct import here without relying on the file importer - if (type == ContentType::MeshSource && ImGui::MenuItem("Import as scene")) { + if (type == ContentType::MeshSource && singleSelect && ImGui::MenuItem("Import as scene")) { PopupPanels::filename = assetRelativePath; PopupPanels::isImportScenePopupVisible = true; } // We shouldn't allow the user to delete the root entity - if (ImGui::MenuItem("Open externally")) + if (singleSelect && ImGui::MenuItem("Open externally")) OpenExternally(std::filesystem::absolute(path).string(), isDirectory); - // We shouldn't allow the user to delete the root entity - if (ImGui::MenuItem("Duplicate")) { - int32_t counter = 0; - auto dupFilePath = path; - do { - dupFilePath = path; - dupFilePath.replace_extension(""); - auto replacement = dupFilePath.filename().string() + "(" + std::to_string(++counter) + ")"; - dupFilePath.replace_filename(replacement); - dupFilePath.replace_extension(path.extension()); - } while (std::filesystem::exists(dupFilePath)); - std::filesystem::copy(path, dupFilePath); - } - - if (ImGui::MenuItem("Rename")) { + if (singleSelect && ImGui::MenuItem("Rename")) { renamePopupVisible = true; auto dirEntryFilename = path.filename(); renameString = dirEntryFilename.replace_extension("").string(); renamePath = path; } - if (ImGui::MenuItem("Delete")) - std::filesystem::remove_all(path); + if (singleSelect && ImGui::MenuItem("Duplicate")) { + FileSystemHelper::Duplicate(path); + } + + if (ImGui::MenuItem("Copy")) { + ContentCopy copy { GetSelectedPaths() }; + CopyPasteHelper::Copy(copy); + } + + if (ImGui::MenuItem("Delete")) { + auto paths = GetSelectedPaths(); + FileSystemHelper::Delete(paths); + } ImGui::EndPopup(); } @@ -574,4 +580,27 @@ namespace Atlas::Editor::UI { } + std::vector ContentBrowserWindow::GetSelectedPaths() { + + std::vector paths; + + int32_t entryIdx = 0; + for (const auto& directory : directories) { + // Ignore 'invisible' directories + if (directory->assetPath.at(0) == '.') + continue; + + if (selectionStorage.Contains(entryIdx++)) + paths.push_back(directory->path); + } + + for (const auto& file : files) { + if (selectionStorage.Contains(entryIdx++)) + paths.push_back(file.path); + } + + return paths; + + } + } \ No newline at end of file diff --git a/src/editor/ui/windows/ContentBrowserWindow.h b/src/editor/ui/windows/ContentBrowserWindow.h index ca798a110..49bb7d158 100644 --- a/src/editor/ui/windows/ContentBrowserWindow.h +++ b/src/editor/ui/windows/ContentBrowserWindow.h @@ -28,6 +28,10 @@ namespace Atlas::Editor::UI { std::string currentDirectory = Loader::AssetLoader::GetAssetDirectory(); private: + struct ContentCopy { + std::vector paths; + }; + void RenderDirectoryControl(); void RenderDirectoryContent(); @@ -48,6 +52,8 @@ namespace Atlas::Editor::UI { bool TextInputPopup(const char* name, bool& isVisible, std::string& input); + std::vector GetSelectedPaths(); + int selectedFilter = -1; std::string nextDirectory; diff --git a/src/editor/ui/windows/LogWindow.cpp b/src/editor/ui/windows/LogWindow.cpp index 642375cae..1fee0554b 100644 --- a/src/editor/ui/windows/LogWindow.cpp +++ b/src/editor/ui/windows/LogWindow.cpp @@ -16,9 +16,9 @@ namespace Atlas::Editor::UI { for (auto& entry : entries) { ImGui::Text(""); - if (!ImGui::IsItemVisible()) { + if (!ImGui::IsItemVisible()) continue; - } + ImGui::SameLine(); std::string logText; diff --git a/src/engine/Main.cpp b/src/engine/Main.cpp index 0a5f728fc..c24e9323b 100644 --- a/src/engine/Main.cpp +++ b/src/engine/Main.cpp @@ -28,7 +28,7 @@ int main(int argc, char* argv[]) { } #if defined(AE_OS_MACOS) && defined(AE_BINDLESS) - setenv("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", "2", 1); + setenv("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", "1", 1); setenv("MVK_DEBUG", "0", 1); #elif defined(AE_OS_MACOS) && defined(AE_BINDLESS) setenv("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", "0", 1); diff --git a/src/engine/graphics/Profiler.cpp b/src/engine/graphics/Profiler.cpp index 6f6b16673..eb14ab2e6 100644 --- a/src/engine/graphics/Profiler.cpp +++ b/src/engine/graphics/Profiler.cpp @@ -207,7 +207,7 @@ namespace Atlas { ThreadData data; data.name = name; - auto idx = threadHistory.historyIdx > 0 ? threadHistory.historyIdx - 1 : 64; + auto idx = threadHistory.historyIdx > 0 ? threadHistory.historyIdx - 1 : 63; data.queries = threadHistory.history[idx]; if (order != OrderBy::CHRONO) diff --git a/src/engine/physics/Body.h b/src/engine/physics/Body.h index c9b5e055a..4aff3dc06 100644 --- a/src/engine/physics/Body.h +++ b/src/engine/physics/Body.h @@ -13,7 +13,7 @@ namespace Atlas::Physics { Body() = default; Body(BodyID bodyId, PhysicsWorld* world) : bodyId(bodyId), world(world) {} - bool IsValid() const { return world != nullptr; } + bool IsValid() const { return world != nullptr && !bodyId.IsInvalid(); } void SetMatrix(mat4 matrix); diff --git a/src/engine/physics/PhysicsWorld.cpp b/src/engine/physics/PhysicsWorld.cpp index e1227778a..22b359a25 100644 --- a/src/engine/physics/PhysicsWorld.cpp +++ b/src/engine/physics/PhysicsWorld.cpp @@ -93,6 +93,15 @@ namespace Atlas { } + bool PhysicsWorld::ContainsBody(Body body) const { + + if (body.bodyId.IsInvalid()) + return false; + + return bodyToShapeMap.contains(body.bodyId); + + } + void PhysicsWorld::SetBodyMatrix(BodyID bodyId, const mat4& matrix) { JPH::Vec3 pos; @@ -243,6 +252,12 @@ namespace Atlas { } + uint32_t PhysicsWorld::GetBodyCount() const { + + return system->GetNumBodies(); + + } + Volume::RayResult PhysicsWorld::CastRay(Volume::Ray& ray) { JPH::RayCastResult hit; diff --git a/src/engine/physics/PhysicsWorld.h b/src/engine/physics/PhysicsWorld.h index 538d86379..c64de2283 100644 --- a/src/engine/physics/PhysicsWorld.h +++ b/src/engine/physics/PhysicsWorld.h @@ -42,6 +42,8 @@ namespace Atlas { void DestroyBody(Body body); + bool ContainsBody(Body body) const; + void SetBodyMatrix(BodyID bodyId, const mat4& matrix); mat4 GetBodyMatrix(BodyID bodyId); @@ -76,6 +78,8 @@ namespace Atlas { vec3 GetGravity(); + uint32_t GetBodyCount() const; + Volume::RayResult CastRay(Volume::Ray& ray); void OptimizeBroadphase(); diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index ed52efe30..929600cc0 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -162,7 +162,7 @@ namespace Atlas::Scene { auto bindlessMeshBuffersUpdate = [&](JobData&) { JobSystem::Wait(bindlessMeshMapUpdateJob); - if (blasBuffers.size() < meshIdToBindlessIdx.size()) { + if (blasBuffers.size() != meshIdToBindlessIdx.size()) { blasBuffers.resize(meshIdToBindlessIdx.size()); triangleBuffers.resize(meshIdToBindlessIdx.size()); bvhTriangleBuffers.resize(meshIdToBindlessIdx.size()); @@ -218,7 +218,7 @@ namespace Atlas::Scene { auto bindlessTextureBuffersUpdate = [&](JobData&) { JobSystem::Wait(bindlessTextureMapUpdateJob); - if (textures.size() < textureToBindlessIdx.size()) { + if (textures.size() != textureToBindlessIdx.size()) { textures.resize(textureToBindlessIdx.size()); } @@ -284,6 +284,9 @@ namespace Atlas::Scene { JobSystem::Execute(bindlessOtherTextureMapUpdateJob, [&, lightSubset](JobData&) { + cubemapToBindlessIdx.clear(); + textureArrayToBindlessIdx.clear(); + uint32_t textureArrayIdx = 0; uint32_t cubemapIdx = 0; for (auto entity : lightSubset) { @@ -300,12 +303,12 @@ namespace Atlas::Scene { } } - if (cubemaps.size() < cubemapToBindlessIdx.size()) + if (cubemaps.size() != cubemapToBindlessIdx.size()) cubemaps.resize(cubemapToBindlessIdx.size()); for (const auto& [cubemap, idx] : cubemapToBindlessIdx) cubemaps[idx] = cubemap->image; - if (textureArrays.size() < textureArrayToBindlessIdx.size()) + if (textureArrays.size() != textureArrayToBindlessIdx.size()) textureArrays.resize(textureArrayToBindlessIdx.size()); for (const auto& [textureArray, idx] : textureArrayToBindlessIdx) textureArrays[idx] = textureArray->image; diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index 88b40f214..7e6db06c0 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -11,6 +11,23 @@ namespace Atlas { 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f); + LightComponent::LightComponent(const LightComponent& that) { + + if (this != &that) { + + *this = that; + + // Copy shadow, need to have separate resources + if (that.shadow != nullptr) { + shadow = CreateRef(*that.shadow); + shadow->SetResolution(shadow->resolution); + shadow->update = true; + } + + } + + } + LightComponent::LightComponent(LightType type, LightMobility mobility) : type(type), mobility(mobility), properties(type), transformedProperties(type) { diff --git a/src/engine/scene/components/LightComponent.h b/src/engine/scene/components/LightComponent.h index 8d70d902b..17a7f77b7 100644 --- a/src/engine/scene/components/LightComponent.h +++ b/src/engine/scene/components/LightComponent.h @@ -68,7 +68,7 @@ namespace Atlas { public: LightComponent() = default; - LightComponent(const LightComponent& that) = default; + LightComponent(const LightComponent& that); LightComponent(LightType type, LightMobility mobility = LightMobility::MovableLight); void AddDirectionalShadow(float distance, float bias, int32_t resolution, float edgeSoftness, diff --git a/src/engine/scene/components/RigidBodyComponent.cpp b/src/engine/scene/components/RigidBodyComponent.cpp index c313b500f..f95aa67fe 100644 --- a/src/engine/scene/components/RigidBodyComponent.cpp +++ b/src/engine/scene/components/RigidBodyComponent.cpp @@ -9,9 +9,19 @@ namespace Atlas { RigidBodyComponent::RigidBodyComponent(Scene* scene, Entity entity, const RigidBodyComponent& that) { if (this != &that) { + // In case this contains a valid body -> destroy, since we assume to own the body + if (world != nullptr && world->ContainsBody(*this)) { + world->DestroyBody(*this); + } + *this = that; + + // Reset body and create new settings + this->bodyId = Physics::BodyID(); + this->creationSettings = CreateRef(that.GetBodyCreationSettings()); } + // In a copy constructor we want to enforce to create a new body this->entity = entity; } diff --git a/vcpkg.json b/vcpkg.json index 12c8b40e5..6535129da 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -38,6 +38,7 @@ "gtest", "joltphysics", "imguizmo", + "implot", "lua", "sol2" ], @@ -70,6 +71,10 @@ "name": "imgui", "version": "1.91.0#0" }, + { + "name": "implot", + "version": "0.16#0" + }, { "name": "vulkan-memory-allocator", "version": "3.1.0#0" From 7fbe618559d2cf699fc1341f69ccb58d3e92d932 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 14 Sep 2024 22:24:58 +0200 Subject: [PATCH 40/66] Some fixes for the previous changes --- libs/ImguiExtension/panels/GPUProfilerPanel.cpp | 2 +- src/editor/ContentDiscovery.cpp | 2 +- src/editor/tools/CopyPasteHelper.h | 4 +++- src/editor/ui/windows/ContentBrowserWindow.cpp | 7 ++++--- src/engine/scene/components/LightComponent.cpp | 2 +- src/engine/scene/components/LightComponent.h | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp index f4578e3fd..753f36cfa 100644 --- a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp +++ b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp @@ -150,7 +150,7 @@ namespace Atlas::ImguiExtension { maxFrameTime = 0.0f; maxGpuTime = 0.0f; - for (int32_t i = 0; i < timeWindowSize; i++) { + for (int32_t i = 0; i < timeWindowSize && i < int32_t(frameTimes.size()); i++) { maxFrameTime = std::max(frameTimes[i], maxFrameTime); maxGpuTime = std::max(gpuTimes[i], maxGpuTime); } diff --git a/src/editor/ContentDiscovery.cpp b/src/editor/ContentDiscovery.cpp index 7081bb8ff..2741b77b5 100644 --- a/src/editor/ContentDiscovery.cpp +++ b/src/editor/ContentDiscovery.cpp @@ -101,7 +101,7 @@ namespace Atlas::Editor { assetPath.erase(assetPath.begin()); if (dirEntry.is_directory()) { - auto dirname = Common::Path::GetFileName(dirEntry.path()); + auto dirname = Common::Path::GetFileName(dirEntry.path().string()); std::transform(dirname.begin(), dirname.end(), dirname.begin(), ::tolower); auto childDirectory = CreateRef({ diff --git a/src/editor/tools/CopyPasteHelper.h b/src/editor/tools/CopyPasteHelper.h index 885913229..9185c2fdb 100644 --- a/src/editor/tools/CopyPasteHelper.h +++ b/src/editor/tools/CopyPasteHelper.h @@ -78,10 +78,12 @@ namespace Atlas::Editor { typeInfo = typeid(T); data = std::malloc(sizeof(T) * elementCount); + std::memset(data, 0, sizeof(T) * elementCount); T* typeData = static_cast(data); - for (size_t i = 0; i < elementCount; i++) + for (size_t i = 0; i < elementCount; i++) { typeData[i] = source[i]; + } destructor = [](void* ptr) { static_cast(ptr)->~T(); diff --git a/src/editor/ui/windows/ContentBrowserWindow.cpp b/src/editor/ui/windows/ContentBrowserWindow.cpp index 136746dab..a44f207a2 100644 --- a/src/editor/ui/windows/ContentBrowserWindow.cpp +++ b/src/editor/ui/windows/ContentBrowserWindow.cpp @@ -16,6 +16,7 @@ #include #ifdef AE_OS_WINDOWS +#define NOMINMAX #include #include #endif @@ -380,7 +381,7 @@ namespace Atlas::Editor::UI { } if (singleSelect && ImGui::MenuItem("Duplicate")) { - FileSystemHelper::Duplicate(path); + FileSystemHelper::Duplicate(path.string()); } if (ImGui::MenuItem("Copy")) { @@ -591,12 +592,12 @@ namespace Atlas::Editor::UI { continue; if (selectionStorage.Contains(entryIdx++)) - paths.push_back(directory->path); + paths.push_back(directory->path.string()); } for (const auto& file : files) { if (selectionStorage.Contains(entryIdx++)) - paths.push_back(file.path); + paths.push_back(file.path.string()); } return paths; diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index 7e6db06c0..4b7c74e0c 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -11,7 +11,7 @@ namespace Atlas { 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f); - LightComponent::LightComponent(const LightComponent& that) { + LightComponent::LightComponent(Scene* scene, const LightComponent& that) { if (this != &that) { diff --git a/src/engine/scene/components/LightComponent.h b/src/engine/scene/components/LightComponent.h index 17a7f77b7..a2958f61d 100644 --- a/src/engine/scene/components/LightComponent.h +++ b/src/engine/scene/components/LightComponent.h @@ -68,7 +68,7 @@ namespace Atlas { public: LightComponent() = default; - LightComponent(const LightComponent& that); + LightComponent(Scene* scene, const LightComponent& that); LightComponent(LightType type, LightMobility mobility = LightMobility::MovableLight); void AddDirectionalShadow(float distance, float bias, int32_t resolution, float edgeSoftness, From 6f1a37768cc8100456892895a8b28ccc3d16d19a Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 15 Sep 2024 17:56:31 +0200 Subject: [PATCH 41/66] Small fixes --- src/editor/ContentDiscovery.cpp | 10 +++++++++- src/editor/ContentDiscovery.h | 4 ++++ src/editor/tools/CopyPasteHelper.h | 2 ++ src/editor/tools/FileSystemHelper.cpp | 4 ++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/editor/ContentDiscovery.cpp b/src/editor/ContentDiscovery.cpp index 2741b77b5..1ec93aa20 100644 --- a/src/editor/ContentDiscovery.cpp +++ b/src/editor/ContentDiscovery.cpp @@ -13,9 +13,16 @@ namespace Atlas::Editor { Ref ContentDiscovery::nextContent = CreateRef(); JobGroup ContentDiscovery::contentDiscoveryJob; + std::atomic_bool ContentDiscovery::execute = false; const float ContentDiscovery::discoverFrequency = 3.0f; float ContentDiscovery::lastDiscoveryTime = -ContentDiscovery::discoverFrequency; + void ContentDiscovery::Execute() { + + execute = true; + + } + const Ref ContentDiscovery::GetContent() { return content->rootDirectory; @@ -53,7 +60,8 @@ namespace Atlas::Editor { void ContentDiscovery::Update() { - bool canRediscover = (Clock::Get() - lastDiscoveryTime) >= discoverFrequency || content->contentDirectories.empty(); + bool canRediscover = (Clock::Get() - lastDiscoveryTime) >= discoverFrequency + || content->contentDirectories.empty() || execute; if (contentDiscoveryJob.HasFinished() && canRediscover) { // Swap here to not immediately release the memory of content (causes stutter due to freeing memory) diff --git a/src/editor/ContentDiscovery.h b/src/editor/ContentDiscovery.h index 7d14df4d5..83ca699b3 100644 --- a/src/editor/ContentDiscovery.h +++ b/src/editor/ContentDiscovery.h @@ -6,6 +6,7 @@ #include #include +#include namespace Atlas::Editor { @@ -23,6 +24,8 @@ namespace Atlas::Editor { public: static void Shutdown() { JobSystem::Wait(contentDiscoveryJob); } + static void Execute(); + static const Ref GetContent(); static std::vector GetContent(const ContentType type); @@ -48,6 +51,7 @@ namespace Atlas::Editor { static Ref nextContent; static JobGroup contentDiscoveryJob; + static std::atomic_bool execute; static const float discoverFrequency; static float lastDiscoveryTime; diff --git a/src/editor/tools/CopyPasteHelper.h b/src/editor/tools/CopyPasteHelper.h index 9185c2fdb..963913c4f 100644 --- a/src/editor/tools/CopyPasteHelper.h +++ b/src/editor/tools/CopyPasteHelper.h @@ -65,6 +65,7 @@ namespace Atlas::Editor { data = nullptr; elementCount = 0; + elementSize = 0; } @@ -75,6 +76,7 @@ namespace Atlas::Editor { Clear(); elementCount = count; + elementSize = sizeof(T); typeInfo = typeid(T); data = std::malloc(sizeof(T) * elementCount); diff --git a/src/editor/tools/FileSystemHelper.cpp b/src/editor/tools/FileSystemHelper.cpp index 333241d33..4f66d12d7 100644 --- a/src/editor/tools/FileSystemHelper.cpp +++ b/src/editor/tools/FileSystemHelper.cpp @@ -2,6 +2,7 @@ #include "Notifications.h" #include "Log.h" #include "common/Path.h" +#include "ContentDiscovery.h" #include @@ -37,6 +38,7 @@ namespace Atlas::Editor { } if (success) { Notifications::Push({ "Finished copying file(s) to " + Common::Path::GetAbsolute(destination) }); + ContentDiscovery::Execute(); } }); @@ -66,6 +68,7 @@ namespace Atlas::Editor { } if (success) { Notifications::Push({ "Successfully deleted files(s)" }); + ContentDiscovery::Execute(); } }); @@ -88,6 +91,7 @@ namespace Atlas::Editor { } while (std::filesystem::exists(dupFilePath) && counter < 20); std::filesystem::copy(filePath, dupFilePath); Notifications::Push({ "Successfully duplicated " + path }); + ContentDiscovery::Execute(); } catch (std::exception& e) { auto message = "Error duplicating " + path + ": " + e.what(); From d4e9dcb82164deccfbbfd8de5cb2113e2b813ead Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Mon, 16 Sep 2024 00:13:54 +0200 Subject: [PATCH 42/66] Fix more issues --- libs/ImguiExtension/panels/GPUProfilerPanel.cpp | 2 -- src/editor/App.cpp | 8 ++------ src/editor/tools/FileSystemHelper.cpp | 8 +++++--- src/editor/ui/panels/ResourceSelectionPanel.h | 9 +++++++++ src/editor/ui/panels/components/LightComponentPanel.cpp | 4 ++-- src/engine/jobsystem/JobSystem.cpp | 2 +- src/engine/renderer/DirectLightRenderer.cpp | 6 +++--- src/engine/renderer/PostProcessRenderer.cpp | 2 +- src/engine/renderer/PostProcessRenderer.h | 2 +- src/engine/renderer/helper/RayTracingHelper.cpp | 2 +- src/engine/scene/components/LightComponent.cpp | 8 ++++---- 11 files changed, 29 insertions(+), 24 deletions(-) diff --git a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp index 753f36cfa..eb49fbdcc 100644 --- a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp +++ b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp @@ -126,7 +126,6 @@ namespace Atlas::ImguiExtension { auto gpuProfilerData = Graphics::Profiler::GetQueries(Graphics::Profiler::OrderBy::MAX_TIME); - int32_t slowestThreadIdx = 0; double slowestTime = 0.0; for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { const auto& threadData = gpuProfilerData[i]; @@ -136,7 +135,6 @@ namespace Atlas::ImguiExtension { } if (threadTime > slowestTime) { slowestTime = threadTime; - slowestThreadIdx = i; } } diff --git a/src/editor/App.cpp b/src/editor/App.cpp index c476de6b7..e608b7a0c 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -320,10 +320,8 @@ namespace Atlas::Editor { newScene = false; } - if (saveScene) { - auto activeSceneWindow = sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]; - if (activeSceneWindow != nullptr) - activeSceneWindow->SaveScene(); + if (saveScene && activeSceneWindow != nullptr) { + activeSceneWindow->SaveScene(); } if (exitEditor) @@ -370,7 +368,6 @@ namespace Atlas::Editor { auto gpuProfilerData = Graphics::Profiler::GetQueriesAverage(32, Graphics::Profiler::OrderBy::MAX_TIME); std::string perfString; - int32_t slowestThreadIdx = 0; double slowestTime = 0.0; for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { const auto& threadData = gpuProfilerData[i]; @@ -380,7 +377,6 @@ namespace Atlas::Editor { } if (threadTime > slowestTime) { slowestTime = threadTime; - slowestThreadIdx = i; } } diff --git a/src/editor/tools/FileSystemHelper.cpp b/src/editor/tools/FileSystemHelper.cpp index 4f66d12d7..800033382 100644 --- a/src/editor/tools/FileSystemHelper.cpp +++ b/src/editor/tools/FileSystemHelper.cpp @@ -77,11 +77,12 @@ namespace Atlas::Editor { void FileSystemHelper::Duplicate(const std::string& path) { JobSystem::Execute(duplicateGroup, [path](JobData&) { - int32_t counter = 0; - auto filePath = std::filesystem::path(path); - auto dupFilePath = std::filesystem::path(path); try { + int32_t counter = 0; + auto filePath = std::filesystem::path(path); + auto dupFilePath = std::filesystem::path(path); + do { dupFilePath = path; dupFilePath.replace_extension(""); @@ -89,6 +90,7 @@ namespace Atlas::Editor { dupFilePath.replace_filename(replacement); dupFilePath.replace_extension(filePath.extension()); } while (std::filesystem::exists(dupFilePath) && counter < 20); + std::filesystem::copy(filePath, dupFilePath); Notifications::Push({ "Successfully duplicated " + path }); ContentDiscovery::Execute(); diff --git a/src/editor/ui/panels/ResourceSelectionPanel.h b/src/editor/ui/panels/ResourceSelectionPanel.h index dc662a701..5a744c530 100644 --- a/src/editor/ui/panels/ResourceSelectionPanel.h +++ b/src/editor/ui/panels/ResourceSelectionPanel.h @@ -2,6 +2,7 @@ #include "Panel.h" #include "Singletons.h" +#include "Notifications.h" #include "ui/popups/ResourceSelectionPopup.h" #include "tools/ResourcePayloadHelper.h" @@ -39,6 +40,14 @@ namespace Atlas::Editor::UI { if (ImGui::Button(buttonName.c_str(), { resourceButtonSize, 0 })) popup.Open(); + if (resourceHandle.IsValid() && ImGui::BeginPopupContextItem()) { + if (ImGui::MenuItem("Copy name")) { + ImGui::SetClipboardText(buttonName.c_str()); + Notifications::Push({ .message = "Copied file name to clipboard.", .displayTime = 3.0f }); + } + ImGui::EndPopup(); + } + // Such that drag and drop will work from the content browser if (ImGui::IsDragDropActive() && ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) { ImGui::SetWindowFocus(); diff --git a/src/editor/ui/panels/components/LightComponentPanel.cpp b/src/editor/ui/panels/components/LightComponentPanel.cpp index 4661c88fe..51187bf8d 100644 --- a/src/editor/ui/panels/components/LightComponentPanel.cpp +++ b/src/editor/ui/panels/components/LightComponentPanel.cpp @@ -30,13 +30,13 @@ namespace Atlas::Editor::UI { else if (lightComponent.type == LightType::PointLight) { auto& point = lightComponent.properties.point; ImGui::DragFloat3("Position", glm::value_ptr(point.position), 0.1f, -10000.0f, 10000.0f); - ImGui::DragFloat("Radius", &point.radius, 0.1f, 0.01f, 10000.0f); + ImGui::DragFloat("Radius", &point.radius, 0.01f, 0.01f, 10000.0f); } else if (lightComponent.type == LightType::SpotLight) { auto& spot = lightComponent.properties.spot; ImGui::DragFloat3("Position", glm::value_ptr(spot.position), 0.1f, -10000.0f, 10000.0f); ImGui::DragFloat3("Direction", glm::value_ptr(spot.direction), 0.01f, -1.0f, 1.0f); - ImGui::DragFloat("Radius", &spot.radius, 0.01f, -1.0f, 1.0f); + ImGui::DragFloat("Radius", &spot.radius, 0.01f, 0.01f, 10000.0f); ImGui::DragFloat("Inner cone angle", &spot.innerConeAngle, 0.01f, 0.01f, 2.0f); ImGui::DragFloat("Outer cone angle", &spot.outerConeAngle, 0.01f, 0.01f, 2.0f); } diff --git a/src/engine/jobsystem/JobSystem.cpp b/src/engine/jobsystem/JobSystem.cpp index 308088c08..40e5cf15b 100644 --- a/src/engine/jobsystem/JobSystem.cpp +++ b/src/engine/jobsystem/JobSystem.cpp @@ -169,7 +169,7 @@ namespace Atlas { int32_t JobSystem::GetWorkerCount(const JobPriority priority) { - auto& priorityPool = priorityPools[static_cast(priority)]; + const auto& priorityPool = priorityPools[static_cast(priority)]; return priorityPool.workerCount; } diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index 853c059d2..6c6cd1994 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -36,13 +36,13 @@ namespace Atlas { auto sss = scene->sss; auto clouds = scene->sky.clouds; - std::vector> cascadeMaps; - std::vector> cubeMaps; - PushConstants pushConstants; #ifdef AE_BINDLESS pushConstants.lightCount = std::min(4096, int32_t(renderState->lightEntities.size())); #else + std::vector> cascadeMaps; + std::vector> cubeMaps; + pushConstants.lightCount = std::min(8, int32_t(renderState->lightEntities.size())); for (int32_t i = 0; i < pushConstants.lightCount; i++) { auto& comp = renderState->lightEntities[i].comp; diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index cc3a23ec5..4dcc2d6d0 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -180,7 +180,7 @@ namespace Atlas { } - void PostProcessRenderer::GenerateBloom(PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, + void PostProcessRenderer::GenerateBloom(const PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, Texture::Texture2D* bloomTexture, Graphics::CommandList* commandList) { const uint32_t maxDownsampleCount = 12; diff --git a/src/engine/renderer/PostProcessRenderer.h b/src/engine/renderer/PostProcessRenderer.h index 885966703..899ba4bc6 100644 --- a/src/engine/renderer/PostProcessRenderer.h +++ b/src/engine/renderer/PostProcessRenderer.h @@ -35,7 +35,7 @@ namespace Atlas { vec4 tintColor; }; - void GenerateBloom(PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, + void GenerateBloom(const PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, Texture::Texture2D* bloomTexture, Graphics::CommandList* commandList); void CopyToTexture(Texture::Texture2D* sourceTexture, Texture::Texture2D* texture, diff --git a/src/engine/renderer/helper/RayTracingHelper.cpp b/src/engine/renderer/helper/RayTracingHelper.cpp index dd51dd5e0..beb645ef7 100644 --- a/src/engine/renderer/helper/RayTracingHelper.cpp +++ b/src/engine/renderer/helper/RayTracingHelper.cpp @@ -454,7 +454,7 @@ namespace Atlas { uint32_t data = 0; - auto& prop = light.transformedProperties; + const auto& prop = light.transformedProperties; // Parse individual light information based on type if (light.type == LightType::DirectionalLight) { data |= (DIRECTIONAL_LIGHT << 28u); diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index 4b7c74e0c..9ebc23e39 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -85,7 +85,7 @@ namespace Atlas { AE_ASSERT(type == LightType::PointLight && "Component must be of type point light"); - shadow = CreateRef(transformedProperties.point.radius, bias, resolution, 0.005f, true); + shadow = CreateRef(200.0f, bias, resolution, 0.005f, true); } @@ -93,7 +93,7 @@ namespace Atlas { AE_ASSERT(type == LightType::SpotLight && "Component must be of type spot light"); - shadow = CreateRef(transformedProperties.spot.radius, bias, resolution, 0.005f, false); + shadow = CreateRef(200.0f, bias, resolution, 0.005f, false); } @@ -168,7 +168,7 @@ namespace Atlas { else if (type == LightType::PointLight) { vec3 position = transformedProperties.point.position; - mat4 projectionMatrix = clipMatrix * glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, shadow->distance); + mat4 projectionMatrix = clipMatrix * glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, transformedProperties.point.radius); vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; @@ -187,7 +187,7 @@ namespace Atlas { else if (type == LightType::SpotLight) { auto viewMatrix = glm::lookAt(transformedProperties.spot.position, transformedProperties.spot.position + transformedProperties.spot.direction, vec3(1e-12f, 1.0f, 1e-12f)); - auto projectionMatrix = glm::perspective(2.0f * transformedProperties.spot.outerConeAngle, 1.0f, 0.1f, shadow->distance); + auto projectionMatrix = glm::perspective(2.0f * transformedProperties.spot.outerConeAngle, 1.0f, 0.1f, transformedProperties.spot.radius); shadow->views[0].viewMatrix = viewMatrix; shadow->views[0].projectionMatrix = clipMatrix * projectionMatrix; shadow->views[0].frustumMatrix = clipMatrix * projectionMatrix * viewMatrix; From 8c5269bdb94045cf2760d3405dc844e9f84e4932 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Mon, 16 Sep 2024 00:23:44 +0200 Subject: [PATCH 43/66] Try to fix remaining issues --- src/engine/graphics/DescriptorSetLayout.cpp | 5 ++++- src/engine/renderer/PostProcessRenderer.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/engine/graphics/DescriptorSetLayout.cpp b/src/engine/graphics/DescriptorSetLayout.cpp index c18031f1a..8a69ef36f 100644 --- a/src/engine/graphics/DescriptorSetLayout.cpp +++ b/src/engine/graphics/DescriptorSetLayout.cpp @@ -9,9 +9,12 @@ namespace Atlas { DescriptorSetLayout::DescriptorSetLayout(GraphicsDevice* device, const DescriptorSetLayoutDesc& desc) : device(device) { + // We need this flag to support arrays of descriptors even in non-bindless mode (e.g. array of textures, where only one index is bound) + VkDescriptorBindingFlags defaultBindingFlags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + bindings.resize(desc.bindingCount); layoutBindings.resize(desc.bindingCount); - layoutBindingFlags.resize(desc.bindingCount); + layoutBindingFlags.resize(desc.bindingCount, defaultBindingFlags); bool bindlessAllowed = true; bool bindlessNeeded = false; diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index 4dcc2d6d0..eb57a9238 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -33,7 +33,7 @@ namespace Atlas { const auto& vignette = postProcessing.vignette; const auto& taa = postProcessing.taa; auto& sharpen = postProcessing.sharpen; - auto& bloom = postProcessing.bloom; + const auto& bloom = postProcessing.bloom; ivec2 resolution = ivec2(target->GetWidth(), target->GetHeight()); From d9f64d9dd7bf8c2f65bd5f85815fc1f8ce1e0129 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Mon, 16 Sep 2024 15:41:36 +0200 Subject: [PATCH 44/66] Update DescriptorSetLayout.cpp --- src/engine/graphics/DescriptorSetLayout.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engine/graphics/DescriptorSetLayout.cpp b/src/engine/graphics/DescriptorSetLayout.cpp index 8a69ef36f..c059fce9a 100644 --- a/src/engine/graphics/DescriptorSetLayout.cpp +++ b/src/engine/graphics/DescriptorSetLayout.cpp @@ -76,13 +76,13 @@ namespace Atlas { layoutBindingFlags[i] = bindingFlags; } + } - extendedInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; - extendedInfo.bindingCount = desc.bindingCount; - extendedInfo.pBindingFlags = desc.bindingCount ? layoutBindingFlags.data() : VK_NULL_HANDLE; + extendedInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; + extendedInfo.bindingCount = desc.bindingCount; + extendedInfo.pBindingFlags = desc.bindingCount ? layoutBindingFlags.data() : VK_NULL_HANDLE; - setInfo.pNext = &extendedInfo; - } + setInfo.pNext = &extendedInfo; VK_CHECK(vkCreateDescriptorSetLayout(device->device, &setInfo, nullptr, &layout)) @@ -143,4 +143,4 @@ namespace Atlas { } -} \ No newline at end of file +} From c9d2a287a78a585985228cdcc6ac7e4d690a1e26 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 17 Sep 2024 22:55:52 +0200 Subject: [PATCH 45/66] Initial light culling code --- CMakeLists.txt | 9 +- data/shader/common/light.hsh | 13 ++ data/shader/deferred/direct.csh | 58 +++++-- data/shader/deferred/lightCulling.csh | 110 +++++++++++++ data/shader/deferred/lightCulling.hsh | 12 ++ data/shader/deferred/point.fsh | 151 ------------------ data/shader/deferred/point.vsh | 21 --- data/shader/raytracer/common.hsh | 6 +- data/shader/raytracer/direct.hsh | 4 +- data/shader/structures.hsh | 4 +- libs/ImguiExtension/CMakeLists.txt | 2 +- libs/fsr2/CMakeLists.txt | 2 +- src/demo/CMakeLists.txt | 4 +- src/editor/CMakeLists.txt | 4 +- src/editor/tools/CopyPasteHelper.h | 2 +- src/engine/CMakeLists.txt | 2 +- src/engine/raytracing/RayTracingWorld.cpp | 4 +- src/engine/renderer/DirectLightRenderer.cpp | 61 +++++-- src/engine/renderer/DirectLightRenderer.h | 7 +- .../renderer/helper/RayTracingHelper.cpp | 6 +- src/engine/scene/SceneRenderState.cpp | 3 +- 21 files changed, 263 insertions(+), 222 deletions(-) create mode 100644 data/shader/deferred/lightCulling.csh create mode 100644 data/shader/deferred/lightCulling.hsh delete mode 100644 data/shader/deferred/point.fsh delete mode 100644 data/shader/deferred/point.vsh diff --git a/CMakeLists.txt b/CMakeLists.txt index 6934ba5b1..c7a8ae9db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,10 @@ if(COMMAND cmake_policy) cmake_policy(SET CMP0074 NEW) cmake_policy(SET CMP0011 NEW) cmake_policy(SET CMP0042 NEW) + cmake_policy(SET CMP0141 NEW) endif(COMMAND cmake_policy) -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.25) project(AtlasEngine VERSION 0.2.1) @@ -31,6 +32,7 @@ option(ATLAS_ASSIMP "Activate Assimp integration" ON) option(ATLAS_HEADLESS "Activate support for running the engine in headless mode" OFF) option(ATLAS_BINDLESS "Activate support for running the engine with bindless resources turned on" ON) option(ATLAS_BUNDLE "Allows the applications to be bundled and installed on MacOS" OFF) +option(ATLAS_MSVC_HOT_RELOAD "Configures all targets to be hot-reloadable" OFF) if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) option(ATLAS_TESTS "Activate support for running the engine with bindless resources turned on" ON) @@ -38,6 +40,11 @@ else() option(ATLAS_TESTS "Activate support for running the engine with bindless resources turned on" OFF) endif() +# Hot reloading in Windows, enabled for all targets +if ((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND ATLAS_MSVC_HOT_RELOAD) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$:EditAndContinue>") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /INCREMENTAL:YES" ) +endif() if (ATLAS_DEMO) set (ATLAS_IMGUI ON) diff --git a/data/shader/common/light.hsh b/data/shader/common/light.hsh index e69de29bb..886cf6d4d 100644 --- a/data/shader/common/light.hsh +++ b/data/shader/common/light.hsh @@ -0,0 +1,13 @@ +#include + +float GetDistanceAttenuation(float dist, float radius) { + + return saturate(1.0 - pow(dist / radius, 4.0)) / (dist * dist); + +} + +float GetAngleAttenuation() { + + + +} \ No newline at end of file diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index a084b9240..7ac72e698 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -4,6 +4,7 @@ #define SHADOW_CASCADE_BLENDING #include +#include #include <../structures.hsh> #include <../shadow.hsh> @@ -15,7 +16,7 @@ #include <../common/octahedron.hsh> #include <../clouds/shadow.hsh> -layout (local_size_x = 8, local_size_y = 8) in; +layout (local_size_x = 16, local_size_y = 16) in; layout(set = 3, binding = 0, rgba16f) uniform image2D image; @@ -26,28 +27,45 @@ layout(set = 3, binding = 1) uniform sampler2D sssTexture; layout(set = 3, binding = 2) uniform sampler2D cloudMap; #endif -layout(std140, set = 3, binding = 4) uniform CloudShadowUniformBuffer { +layout(std140, set = 3, binding = 5) uniform CloudShadowUniformBuffer { CloudShadow cloudShadow; } cloudShadowUniforms; -layout(set = 3, binding = 5) uniform sampler shadowSampler; +layout(set = 3, binding = 4) uniform sampler shadowSampler; -layout(set = 3, binding = 6) uniform texture2DArray cascadeMaps[8]; -layout(set = 3, binding = 14) uniform textureCube cubeMaps[8]; +layout(set = 3, binding = 7) uniform texture2DArray cascadeMaps[8]; +layout(set = 3, binding = 15) uniform textureCube cubeMaps[8]; layout(push_constant) uniform constants { int lightCount; - int padding0; + int lightBucketCount; int padding1; int padding2; int mapIndices[16]; } pushConstants; +shared int sharedLightBuckets[lightBucketCount]; + vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMain); float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain); +void LoadGroupSharedData() { + + int lightBucketOffset = GetLightBucketsGroupOffset(); + + int localOffset = int(gl_LocalInvocationIndex); + for (int i = localOffset; i < pushConstants.lightBucketCount; i++) { + sharedLightBuckets[i] = lightBuckets[lightBucketOffset + i]; + } + + barrier(); + +} + void main() { + LoadGroupSharedData(); + ivec2 resolution = imageSize(image); ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); @@ -63,21 +81,34 @@ void main() { direct = vec3(.0); - for (int i = 0; i < pushConstants.lightCount; i++) { - Light light = lights[i]; + int visibleCount = 0; + + for (int i = 0; i < pushConstants.lightBucketCount; i++) { + int lightBucket = sharedLightBuckets[i]; + + for (int j = 0; j < 32; j++) { + + bool lightVisible = (lightBucket & (1 << j)) > 0; + if (!lightVisible) continue; + + visibleCount += 1; + Light light = lights[i + j]; #ifndef AE_BINDLESS - light.shadow.mapIdx = pushConstants.mapIndices[i]; + light.shadow.mapIdx = pushConstants.mapIndices[i + j]; #endif - bool isMain = i == 0 ? true : false; - direct += EvaluateLight(light, surface, geometryNormal, isMain); + bool isMain = i == 0 ? true : false; + direct += EvaluateLight(light, surface, geometryNormal, isMain); + } } + if (dot(surface.material.emissiveColor, vec3(1.0)) > 0.01) { direct += surface.material.emissiveColor; } } + imageStore(image, pixel, vec4(direct, 1.0)); } @@ -93,6 +124,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai uint lightType = GetLightType(light); float lightMultiplier = 1.0; + float radius = light.direction.w; if (lightType == DIRECTIONAL_LIGHT) { surface.L = normalize(-light.direction.xyz); @@ -101,7 +133,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai vec3 pointToLight = light.location.xyz - surface.P; float sqrDistance = dot(pointToLight, pointToLight); float dist = sqrt(sqrDistance); - lightMultiplier = saturate(1.0 - pow(dist / light.radius, 4.0)) / sqrDistance; + lightMultiplier = saturate(1.0 - pow(dist / radius, 4.0)) / sqrDistance; surface.L = pointToLight / dist; } @@ -113,7 +145,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai surface.L = pointToLight / dist; float strength = dot(surface.L, normalize(-light.direction.xyz)); - float attenuation = saturate(strength * light.radius + light.specific); + float attenuation = saturate(strength * light.specific0 + light.specific1); lightMultiplier = sqr(attenuation) / sqrDistance; } diff --git a/data/shader/deferred/lightCulling.csh b/data/shader/deferred/lightCulling.csh new file mode 100644 index 000000000..e40db4dbf --- /dev/null +++ b/data/shader/deferred/lightCulling.csh @@ -0,0 +1,110 @@ +#include +#include + +#include <../structures.hsh> +#include <../shadow.hsh> +#include <../globals.hsh> + +#include <../common/convert.hsh> +#include <../common/utility.hsh> + +layout (local_size_x = 16, local_size_y = 16) in; + +layout(push_constant) uniform constants { + int lightCount; +} pushConstants; + +const int groupSize = int(gl_WorkGroupSize.x * gl_WorkGroupSize.y); + +// Results in 32 * 128 = 4096 possible lights in the tile +shared int sharedLightBuckets[lightBucketCount]; +shared uint sharedDepthMin; +shared uint sharedDepthMax; + +void main() { + + ivec2 resolution = textureSize(depthTexture, 0); + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + + vec2 texCoord = (vec2(pixel) + 0.5) / vec2(resolution); + + float depth = texelFetch(depthTexture, pixel, 0).r; + float viewDepth = ConvertDepthToViewSpaceDepth(depth); + + if (gl_LocalInvocationIndex == 0u) { + sharedDepthMin = floatBitsToUint(viewDepth); + sharedDepthMax = floatBitsToUint(viewDepth); + } + + int localOffset = int(gl_LocalInvocationIndex); + for (int i = localOffset; i < lightBucketCount; i += groupSize) { + sharedLightBuckets[i] = 0; + } + + barrier(); + + atomicMin(sharedDepthMin, floatBitsToUint(viewDepth)); + atomicMax(sharedDepthMax, floatBitsToUint(viewDepth)); + + barrier(); + + float depthMin = uintBitsToFloat(sharedDepthMin); + float depthMax = uintBitsToFloat(sharedDepthMax); + + vec3 viewPos = ConvertDepthToViewSpace(depth, texCoord); + + for (int i = localOffset; i < pushConstants.lightCount; i += groupSize) { + int lightBucketIdx = i / lightBucketCount; + int lightBuckedBit = i % lightBucketCount; + + bool visible = true; + + Light light = lights[i]; + float radius = light.direction.w; + + uint lightType = floatBitsToUint(light.color.a); + + // Remember: Forward is in -z direction + if (lightType == POINT_LIGHT) { + /* + vec3 pointToLight = light.location.xyz - viewPos; + float sqrDistance = dot(pointToLight, pointToLight); + float dist = sqrt(sqrDistance); + lightMultiplier = saturate(1.0 - pow(dist / radius, 4.0)) / sqrDistance; + + surface.L = pointToLight / dist; + */ + visible = depthMin > light.location.z - radius && + depthMax < light.location.z + radius; + } + else if (lightType == SPOT_LIGHT) { + /* + vec3 pointToLight = light.location.xyz - surface.P; + float sqrDistance = dot(pointToLight, pointToLight); + float dist = sqrt(sqrDistance); + + surface.L = pointToLight / dist; + + float strength = dot(surface.L, normalize(-light.direction.xyz)); + float attenuation = saturate(strength * light.specific0 + light.specific1); + lightMultiplier = sqr(attenuation) / sqrDistance; + */ + visible = depthMin > light.location.z - radius && + depthMax < light.location.z + radius; + } + + + + if (visible) { + atomicOr(sharedLightBuckets[lightBucketIdx], 1 << lightBuckedBit); + } + } + + barrier(); + + int lightBucketOffset = GetLightBucketsGroupOffset(); + for (int i = localOffset; i < lightBucketCount; i += groupSize) { + lightBuckets[i + lightBucketOffset] = sharedLightBuckets[i]; + } + +} \ No newline at end of file diff --git a/data/shader/deferred/lightCulling.hsh b/data/shader/deferred/lightCulling.hsh new file mode 100644 index 000000000..73398c98d --- /dev/null +++ b/data/shader/deferred/lightCulling.hsh @@ -0,0 +1,12 @@ +const int lightBucketCount = 128; + +layout(std430, set = 3, binding = 6) buffer LightBucketsBuffer { + int lightBuckets[]; +}; + +int GetLightBucketsGroupOffset() { + + int groupOffset = int(gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x); + return groupOffset * lightBucketCount; + +} \ No newline at end of file diff --git a/data/shader/deferred/point.fsh b/data/shader/deferred/point.fsh deleted file mode 100644 index 3586ca4f5..000000000 --- a/data/shader/deferred/point.fsh +++ /dev/null @@ -1,151 +0,0 @@ -#include <../structures.hsh> -#include <../common/convert.hsh> -#include <../common/material.hsh> - -in vec3 fTexCoordProj; -in vec3 viewSpacePosition; -out vec4 fragColor; - -layout(binding = 0) uniform sampler2D diffuseTexture; -layout(binding = 1) uniform sampler2D normalTexture; -layout(binding = 2) uniform sampler2D geometryNormalTexture; -layout(binding = 3) uniform sampler2D specularTexture; -layout(binding = 4) uniform usampler2D materialIdxTexture; -layout(binding = 5) uniform sampler2D depthTexture; -layout(binding = 6) uniform samplerCubeShadow shadowCubemap; - -uniform Light light; -uniform vec3 viewSpaceLightLocation; -uniform mat4 lvMatrix; -uniform mat4 lpMatrix; - -uniform bool shadowEnabled; - -// Improved filtering: https://kosmonautblog.wordpress.com/2017/03/25/shadow-filtering-for-pointlights/ - -vec3 sampleOffsetDirections[20] = vec3[] -( - vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), - vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), - vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), - vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), - vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) -); - -void main() { - - vec2 texCoord = ((fTexCoordProj.xy / fTexCoordProj.z) + 1.0) / 2.0; - - float depth = texture(depthTexture, texCoord).r; - - vec3 fragPos = ConvertDepthToViewSpace(depth, texCoord); - - if (fragPos.z - viewSpaceLightLocation.z > light.radius) - discard; - - vec3 fragToLight = viewSpaceLightLocation.xyz - fragPos.xyz; - float fragToLightDistance = length(fragToLight); - - uint materialIdx = texture(materialIdxTexture, texCoord).r; - Material material = UnpackMaterial(materialIdx); - - vec3 normal = normalize(2.0 * texture(normalTexture, texCoord).rgb - 1.0); - vec3 reconstructedNormal = normalize(2.0 * texture(geometryNormalTexture, texCoord).rgb - 1.0); - - normal = material.normalMap ? normal : reconstructedNormal; - - vec3 surfaceColor = texture(diffuseTexture, texCoord).rgb; - - // Specular properties - float specularIntensity = 0.0; - float specularHardness = 1.0; - - if (material.specularMap) { - vec2 specularProp = texture(specularTexture, texCoord).rg; - specularIntensity = max(specularProp.r, 0.0); - specularHardness = max(specularProp.g, 1.0); - } - else { - specularIntensity = material.specularIntensity; - specularHardness = material.specularHardness; - } - - float shadowFactor = 0.0; - - vec3 specular = vec3(0.0); - vec3 diffuse = vec3(1.0); - vec3 ambient = vec3(light.ambient * surfaceColor); - vec3 volumetric = 0.0 * vec3(light.color); - - float occlusionFactor = 1.0; - - vec3 lightDir = fragToLight / fragToLightDistance; - - vec4 lsPosition = lvMatrix * vec4(fragPos, 1.0); - vec4 absPosition = abs(lsPosition); - depth = -max(absPosition.x, max(absPosition.y, absPosition.z)); - vec4 clip = lpMatrix * vec4(0.0, 0.0, depth, 1.0); - depth = (clip.z - 0.005) / clip.w * 0.5 + 0.5; - - int samples = 20; - float diskRadius = 0.0075; - - if (shadowEnabled) { - for(int i = 0; i < samples; i++) { - shadowFactor += clamp(texture(shadowCubemap, vec4(surface.P + sampleOffsetDirections[i] * diskRadius, depth)), 0.0, 1.0); - } - shadowFactor /= float(samples + 1); - } - - diffuse = max(dot(normal, lightDir), 0.0) * light.color * shadowFactor * surfaceColor; - - fragColor = vec4(max((diffuse + ambient) * (light.radius - fragToLightDistance) / light.radius, 0.0) + volumetric, 1.0); - -} - - - - -float ComputeScattering(vec3 fragPos) { - - // We also need to consider that we shouldn't use the radius of the sphere when we're inside - // the volume but should use the distance of the viewSpacePosition to the camera. - const int sampleCount = 100; - const float offset = 0.5f; // Because of geometry getting cut off by near plane (offset = 2 * nearPlane) - - float positionLength = length(viewSpacePosition); - float fragLength = length(fragPos); - - vec3 rayDirection = viewSpacePosition / positionLength; - - vec3 rayEnd = vec3(viewSpacePosition.xyz) - rayDirection * offset / 2.0f; - - vec3 rayStart = positionLength < light.radius - offset / 2.0f ? vec3(0.0f) : - vec3(viewSpacePosition.xyz) - rayDirection * (light.radius - offset / 2.0f); - - float rayLength = distance(rayStart, rayEnd); - - float stepLength = rayLength / float(sampleCount); - vec3 stepVector = rayDirection * stepLength; - - float foginess = 0.0f; - float scattering = 0.15f; - - vec3 currentPosition = vec3(rayStart); - - for (int i = 0; i < sampleCount; i++) { - - // Normally we should take a shadow map into consideration - float fragToLightDistance = length(viewSpaceLightLocation - currentPosition); - float shadowValue = fragToLightDistance < light.radius ? 1.0f : 0.0f; - shadowValue = fragLength < length(currentPosition) ? 0.0f : shadowValue; - - foginess += max(scattering * shadowValue * (light.radius - fragToLightDistance - 0.25f) / (light.radius- 0.25f), 0.0f); - - currentPosition += stepVector; - - } - - return foginess / float(sampleCount); - -} \ No newline at end of file diff --git a/data/shader/deferred/point.vsh b/data/shader/deferred/point.vsh deleted file mode 100644 index 293b16be0..000000000 --- a/data/shader/deferred/point.vsh +++ /dev/null @@ -1,21 +0,0 @@ -#include <../structures.hsh> - -layout(location=0)in vec3 vPosition; - -out vec3 fTexCoordProj; -out vec3 viewSpacePosition; - -uniform mat4 vMatrix; -uniform mat4 pMatrix; -uniform Light light; - -void main() { - - vec4 position = vMatrix * vec4(vPosition * light.radius + light.location, 1.0); - - viewSpacePosition = position.xyz; - gl_Position = pMatrix * position; - - fTexCoordProj = gl_Position.xyw; - -} \ No newline at end of file diff --git a/data/shader/raytracer/common.hsh b/data/shader/raytracer/common.hsh index 8e16b81c4..360bca5cd 100644 --- a/data/shader/raytracer/common.hsh +++ b/data/shader/raytracer/common.hsh @@ -104,7 +104,7 @@ Light UnpackLight(PackedLight compressed) { Light light; light.P = compressed.P.xyz; - light.N = compressed.N.xyz; + light.N = normalize(compressed.N.xyz); light.radiance = compressed.color.rgb; @@ -115,8 +115,8 @@ Light UnpackLight(PackedLight compressed) { light.instanceIdx = floatBitsToInt(compressed.data.w); light.pdf = compressed.data.y; - light.area = compressed.data.z; - light.radius = compressed.data.z; + light.area = compressed.N.w; + light.radius = compressed.N.w; light.angleScale = compressed.data.z; light.angleOffset = compressed.data.w; light.brightness = dot(light.radiance, vec3(0.33333)); diff --git a/data/shader/raytracer/direct.hsh b/data/shader/raytracer/direct.hsh index 1d2f894fc..22d190681 100644 --- a/data/shader/raytracer/direct.hsh +++ b/data/shader/raytracer/direct.hsh @@ -96,7 +96,7 @@ void SampleLight(Light light, inout Surface surface, float seed0, float seed1, else { // Punctual lights solidAngle = 1.0; if (light.type == uint(DIRECTIONAL_LIGHT)) { - surface.L = normalize(-light.N); + surface.L = -light.N; UpdateSurface(surface); solidAngle = 1.0; dist = INF; @@ -118,7 +118,7 @@ void SampleLight(Light light, inout Surface surface, float seed0, float seed1, dist = sqrt(sqrDistance); surface.L = pointToLight / dist; - float strength = dot(surface.L, normalize(-light.N)); + float strength = dot(surface.L, -light.N); float attenuation = saturate(strength * light.angleScale + light.angleOffset); solidAngle = sqr(attenuation) / sqrDistance; diff --git a/data/shader/structures.hsh b/data/shader/structures.hsh index 15aaaf547..4507a556d 100644 --- a/data/shader/structures.hsh +++ b/data/shader/structures.hsh @@ -15,8 +15,8 @@ struct Light { float scatteringFactor; - float radius; - float specific; + float specific0; + float specific1; Shadow shadow; diff --git a/libs/ImguiExtension/CMakeLists.txt b/libs/ImguiExtension/CMakeLists.txt index b5e477cde..d792b3a74 100644 --- a/libs/ImguiExtension/CMakeLists.txt +++ b/libs/ImguiExtension/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.25) project(ImguiExtension) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../src/engine) diff --git a/libs/fsr2/CMakeLists.txt b/libs/fsr2/CMakeLists.txt index 2161467be..f44844e54 100644 --- a/libs/fsr2/CMakeLists.txt +++ b/libs/fsr2/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.25) project(fsr2) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ffx-fsr2-api) diff --git a/src/demo/CMakeLists.txt b/src/demo/CMakeLists.txt index 17309753a..9377dd597 100644 --- a/src/demo/CMakeLists.txt +++ b/src/demo/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.25) -project(AtlasEngineDemo VERSION 0.2.0) +project(AtlasEngineDemo VERSION 0.2.1) # Note: For this project, the root CMakeLists.txt turns # the ATLAS_IMGUI and ATLAS_EXPORT_MAIN options on. diff --git a/src/editor/CMakeLists.txt b/src/editor/CMakeLists.txt index 08638f88f..340f53453 100644 --- a/src/editor/CMakeLists.txt +++ b/src/editor/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 3.7) -project(AtlasEngineEditor VERSION 0.2.0) +cmake_minimum_required(VERSION 3.25) +project(AtlasEngineEditor VERSION 0.2.1) # Note: For this project, the root CMakeLists.txt turns # the ATLAS_IMGUI and ATLAS_EXPORT_MAIN options on. diff --git a/src/editor/tools/CopyPasteHelper.h b/src/editor/tools/CopyPasteHelper.h index 963913c4f..f1e4dd93d 100644 --- a/src/editor/tools/CopyPasteHelper.h +++ b/src/editor/tools/CopyPasteHelper.h @@ -57,8 +57,8 @@ namespace Atlas::Editor { if (data != nullptr) { auto ptr = static_cast(data); for (int32_t i = 0; i < elementCount; i++) { - ptr += elementSize; destructor(static_cast(ptr)); + ptr += elementSize; } std::free(data); } diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index 6d51a7c6c..32a15b277 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -3,7 +3,7 @@ if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) endif() project(AtlasEngine) -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.25) # Validate options ################################################################################ if (ATLAS_NO_APP AND ATLAS_EXPORT_MAIN) diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index f56728a79..75dee35ea 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -390,9 +390,9 @@ namespace Atlas { GPULight light; light.P = vec4(P, 1.0f); - light.N = vec4(N, 0.0f); + light.N = vec4(N, area); light.color = vec4(Common::ColorConverter::ConvertSRGBToLinear(radiance) * material->emissiveIntensity, 0.0f); - light.data = vec4(cd, weight, area, 0.0f); + light.data = vec4(cd, weight, 0.0, 0.0f); meshInfo.triangleLights.push_back(light); } diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index 6c6cd1994..fe41d3e61 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -8,6 +8,7 @@ namespace Atlas { this->device = device; + lightCullingBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit, sizeof(uint32_t)); cloudShadowUniformBuffer = Buffer::UniformBuffer(sizeof(CloudShadow)); pipelineConfig = PipelineConfig("deferred/direct.csh"); @@ -24,21 +25,56 @@ namespace Atlas { void DirectLightRenderer::Render(Ref target, Ref scene, Graphics::CommandList* commandList) { - auto mainLightEntity = GetMainLightEntity(scene); - if (!mainLightEntity.IsValid()) return; - auto renderState = &scene->renderState; + if (renderState->lightEntities.empty()) return; Graphics::Profiler::BeginQuery("Direct lighting"); + auto mainLightEntity = GetMainLightEntity(scene); auto& camera = scene->GetMainCamera(); auto& light = mainLightEntity.GetComponent(); auto sss = scene->sss; auto clouds = scene->sky.clouds; + ivec2 res = ivec2(target->GetScaledWidth(), target->GetScaledHeight()); + int32_t groupSize = 16; + ivec2 groupCount = res / groupSize; + groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); + groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); + + if (lightCullingBuffer.GetElementCount() < groupCount.x * groupCount.y * 128) { + lightCullingBuffer.SetSize(groupCount.x * groupCount.y * 128); + } + + Graphics::Profiler::BeginQuery("Light culling"); + + commandList->BufferMemoryBarrier(lightCullingBuffer.Get(), VK_ACCESS_SHADER_WRITE_BIT); + + CullingPushConstants cullingPushConstants; +#ifdef AE_BINDLESS + cullingPushConstants.lightCount = std::min(4096, int32_t(renderState->lightEntities.size())); +#else + cullingPushConstants.lightCount = std::min(8, int32_t(renderState->lightEntities.size())); +#endif + + lightCullingBuffer.Bind(commandList, 3, 6); + + auto cullingPipelineConfig = PipelineConfig("deferred/lightCulling.csh"); + auto pipeline = PipelineManager::GetPipeline(cullingPipelineConfig); + commandList->BindPipeline(pipeline); + + commandList->PushConstants("constants", &cullingPushConstants); + + commandList->Dispatch(groupCount.x, groupCount.y, 1); + + commandList->BufferMemoryBarrier(lightCullingBuffer.Get(), VK_ACCESS_SHADER_READ_BIT); + + Graphics::Profiler::EndAndBeginQuery("Lighting"); + PushConstants pushConstants; #ifdef AE_BINDLESS pushConstants.lightCount = std::min(4096, int32_t(renderState->lightEntities.size())); + pushConstants.lightBucketCount = 1; #else std::vector> cascadeMaps; std::vector> cubeMaps; @@ -60,13 +96,13 @@ namespace Atlas { } } - commandList->BindSampledImages(cascadeMaps, 3, 6); - commandList->BindSampledImages(cubeMaps, 3, 14); + commandList->BindSampledImages(cascadeMaps, 3, 7); + commandList->BindSampledImages(cubeMaps, 3, 15); #endif pipelineConfig.ManageMacro("SCREEN_SPACE_SHADOWS", sss && sss->enable); pipelineConfig.ManageMacro("CLOUD_SHADOWS", clouds && clouds->enable && clouds->castShadow); - auto pipeline = PipelineManager::GetPipeline(pipelineConfig); + pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); commandList->BindImage(target->lightingTexture.image, 3, 0); @@ -75,6 +111,8 @@ namespace Atlas { commandList->BindImage(target->sssTexture.image, target->sssTexture.sampler, 3, 1); } + commandList->BindSampler(shadowSampler, 3, 4); + CloudShadow cloudShadowUniform; if (clouds && clouds->enable && clouds->castShadow) { clouds->shadowTexture.Bind(commandList, 3, 2); @@ -89,21 +127,14 @@ namespace Atlas { } cloudShadowUniformBuffer.SetData(&cloudShadowUniform, 0); - cloudShadowUniformBuffer.Bind(commandList, 3, 4); - - commandList->BindSampler(shadowSampler, 3, 5); + cloudShadowUniformBuffer.Bind(commandList, 3, 5); commandList->PushConstants("constants", &pushConstants); - ivec2 res = ivec2(target->GetScaledWidth(), target->GetScaledHeight()); - int32_t groupSize = 8; - ivec2 groupCount = res / groupSize; - groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); - groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - commandList->Dispatch(groupCount.x, groupCount.y, 1); Graphics::Profiler::EndQuery(); + Graphics::Profiler::EndQuery(); } diff --git a/src/engine/renderer/DirectLightRenderer.h b/src/engine/renderer/DirectLightRenderer.h index d27bdb331..3cac24ea9 100644 --- a/src/engine/renderer/DirectLightRenderer.h +++ b/src/engine/renderer/DirectLightRenderer.h @@ -17,9 +17,13 @@ namespace Atlas { Graphics::CommandList* commandList); private: + struct alignas(16) CullingPushConstants { + int32_t lightCount; + }; + struct alignas(16) PushConstants { int32_t lightCount; - int32_t padding0; + int32_t lightBucketCount; int32_t padding1; int32_t padding2; int32_t mapIndices[16]; @@ -27,6 +31,7 @@ namespace Atlas { PipelineConfig pipelineConfig; + Buffer::Buffer lightCullingBuffer; Buffer::UniformBuffer cloudShadowUniformBuffer; Ref shadowSampler; diff --git a/src/engine/renderer/helper/RayTracingHelper.cpp b/src/engine/renderer/helper/RayTracingHelper.cpp index beb645ef7..4cb00a05b 100644 --- a/src/engine/renderer/helper/RayTracingHelper.cpp +++ b/src/engine/renderer/helper/RayTracingHelper.cpp @@ -449,6 +449,7 @@ namespace Atlas { vec3 P = vec3(0.0f); vec3 N = vec3(0.0f); float weight = 0.0f; + float radius = 1.0f; float specific0 = 0.0f; float specific1 = 0.0f; @@ -465,13 +466,14 @@ namespace Atlas { data |= (POINT_LIGHT << 28u); weight = brightness; P = light.transformedProperties.point.position; - specific0 = light.transformedProperties.point.radius; + radius = light.transformedProperties.point.radius; } else if (light.type == LightType::SpotLight) { data |= (SPOT_LIGHT << 28u); weight = brightness; P = light.transformedProperties.spot.position; N = light.transformedProperties.spot.direction; + radius = light.transformedProperties.spot.radius; auto cosOuter = cosf(prop.spot.outerConeAngle); auto cosInner = cosf(prop.spot.innerConeAngle); @@ -487,7 +489,7 @@ namespace Atlas { GPULight gpuLight; gpuLight.P = vec4(P, 1.0f); - gpuLight.N = vec4(N, 0.0f); + gpuLight.N = vec4(N, radius); gpuLight.color = vec4(radiance, 0.0f); gpuLight.data = vec4(cd, weight, specific0, specific1); diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 929600cc0..9ed7eef3f 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -436,11 +436,12 @@ namespace Atlas::Scene { } else if (light.type == LightType::PointLight) { lightUniform.location = camera.viewMatrix * vec4(prop.point.position, 1.0f); - lightUniform.typeSpecific0 = prop.point.radius; + lightUniform.direction.w = prop.point.radius; } else if (light.type == LightType::SpotLight) { lightUniform.location = camera.viewMatrix * vec4(prop.spot.position, 1.0f); lightUniform.direction = camera.viewMatrix * vec4(prop.spot.direction, 0.0f); + lightUniform.direction.w = prop.spot.radius; auto cosOuter = cosf(prop.spot.outerConeAngle); auto cosInner = cosf(prop.spot.innerConeAngle); From f24b046fe6bfc8cc580b82bb9a5bb585df416635 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Fri, 20 Sep 2024 17:53:01 +0200 Subject: [PATCH 46/66] Bunch of fixes and improvements --- data/shader/deferred/direct.csh | 20 +-- data/shader/deferred/geometry.fsh | 4 +- data/shader/deferred/lightCulling.csh | 134 +++++++++++++----- data/shader/deferred/sss.csh | 32 +++-- data/shader/raytracer/common.hsh | 2 +- data/shader/reflection/rtreflection.csh | 4 +- data/shader/rtgi/rtgi.csh | 2 +- data/shader/shadow.hsh | 8 +- libs/ImguiExtension/panels/FogPanel.cpp | 2 +- libs/ImguiExtension/panels/MaterialPanel.cpp | 2 +- libs/ImguiExtension/panels/SSSPanel.cpp | 4 +- src/editor/ui/panels/ResourceSelectionPanel.h | 4 +- .../panels/components/LightComponentPanel.cpp | 4 +- .../panels/components/MeshComponentPanel.cpp | 4 + src/editor/ui/windows/LogWindow.cpp | 14 +- src/engine/lighting/SSS.h | 6 +- src/engine/mesh/DataComponent.h | 26 ++++ src/engine/mesh/Mesh.cpp | 13 ++ src/engine/mesh/Mesh.h | 2 + src/engine/renderer/DirectLightRenderer.cpp | 2 +- src/engine/renderer/ImpostorRenderer.cpp | 2 +- .../renderer/ImpostorShadowRenderer.cpp | 4 +- src/engine/renderer/ImpostorShadowRenderer.h | 2 +- src/engine/renderer/MainRenderer.cpp | 7 +- src/engine/renderer/OpaqueRenderer.cpp | 2 +- src/engine/renderer/PostProcessRenderer.h | 6 +- src/engine/renderer/SSSRenderer.cpp | 3 + src/engine/renderer/SSSRenderer.h | 1 + src/engine/renderer/ShadowRenderer.cpp | 15 +- src/engine/renderer/ShadowRenderer.h | 3 +- src/engine/renderer/helper/RenderList.cpp | 29 ++-- src/engine/renderer/helper/RenderList.h | 8 +- src/engine/scene/SceneRenderState.cpp | 10 +- .../scripting/bindings/LightingBindings.cpp | 31 ++++ .../scripting/bindings/SceneBindings.cpp | 18 ++- 35 files changed, 313 insertions(+), 117 deletions(-) diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 7ac72e698..61eb356c9 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -79,25 +79,26 @@ void main() { // We don't have any light direction, that's why we use vec3(0.0, -1.0, 0.0) as a placeholder Surface surface = GetSurface(texCoord, depth, vec3(0.0, -1.0, 0.0), geometryNormal); - direct = vec3(.0); + direct = vec3(0.0); int visibleCount = 0; for (int i = 0; i < pushConstants.lightBucketCount; i++) { int lightBucket = sharedLightBuckets[i]; + if (lightBucket == 0) continue; for (int j = 0; j < 32; j++) { - bool lightVisible = (lightBucket & (1 << j)) > 0; + bool lightVisible = (lightBucket & (1 << j)) != 0; if (!lightVisible) continue; visibleCount += 1; - Light light = lights[i + j]; + Light light = lights[i * 32 + j]; #ifndef AE_BINDLESS - light.shadow.mapIdx = pushConstants.mapIndices[i + j]; + light.shadow.mapIdx = pushConstants.mapIndices[i * 32 + j]; #endif - bool isMain = i == 0 ? true : false; + bool isMain = i + j == 0 ? true : false; direct += EvaluateLight(light, surface, geometryNormal, isMain); } } @@ -145,8 +146,9 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai surface.L = pointToLight / dist; float strength = dot(surface.L, normalize(-light.direction.xyz)); - float attenuation = saturate(strength * light.specific0 + light.specific1); - lightMultiplier = sqr(attenuation) / sqrDistance; + float angleAttenuation = saturate(strength * light.specific0 + light.specific1); + float distAttenuation = saturate(1.0 - pow(dist / radius, 4.0)) / sqrDistance; + lightMultiplier = distAttenuation * sqr(angleAttenuation); } UpdateSurface(surface); @@ -207,10 +209,10 @@ float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometr else if (lightType == POINT_LIGHT) { #ifdef AE_BINDLESS shadowFactor = CalculatePointShadow(light.shadow, bindlessCubemaps[nonuniformEXT(light.shadow.mapIdx)], - shadowSampler, surface.P); + shadowSampler, surface.P, shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); #else shadowFactor = CalculatePointShadow(light.shadow, cubeMaps[nonuniformEXT(light.shadow.mapIdx)], - shadowSampler, surface.P); + shadowSampler, surface.P, shadowNormal, saturate(dot(-light.direction.xyz, shadowNormal))); #endif } else if (lightType == SPOT_LIGHT) { diff --git a/data/shader/deferred/geometry.fsh b/data/shader/deferred/geometry.fsh index f5c1341f1..8c570cbfb 100644 --- a/data/shader/deferred/geometry.fsh +++ b/data/shader/deferred/geometry.fsh @@ -145,7 +145,7 @@ void main() { // We want the normal always to face the camera for two sided materials geometryNormal *= PushConstants.twoSided > 0 ? gl_FrontFacing ? 1.0 : -1.0 : 1.0; normal *= dot(geometryNormal, normal) < 0.0 ? -1.0 : 1.0; - normal *= normalInversionVS; + //normal *= normalInversionVS; normalFS = EncodeNormal(normal); #else @@ -153,7 +153,7 @@ void main() { geometryNormal *= PushConstants.twoSided > 0 ? gl_FrontFacing ? 1.0 : -1.0 : 1.0; #endif - geometryNormal *= normalInversionVS; + //geometryNormal *= normalInversionVS; geometryNormalFS = EncodeNormal(geometryNormal); diff --git a/data/shader/deferred/lightCulling.csh b/data/shader/deferred/lightCulling.csh index e40db4dbf..db867eeb0 100644 --- a/data/shader/deferred/lightCulling.csh +++ b/data/shader/deferred/lightCulling.csh @@ -20,6 +20,63 @@ const int groupSize = int(gl_WorkGroupSize.x * gl_WorkGroupSize.y); shared int sharedLightBuckets[lightBucketCount]; shared uint sharedDepthMin; shared uint sharedDepthMax; +shared int depthMask; + +struct AABB { + vec3 center; + vec3 extent; +}; + +struct Sphere { + vec3 center; + float radius; +}; + +void GetFrustumCorners(out vec3 frustumCorners[8]) { + + ivec2 resolution = textureSize(depthTexture, 0); + + ivec2 basePixel = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize); + vec2 baseTexCoord = vec2(basePixel) / vec2(resolution); + vec2 texCoordSpan = vec2(basePixel + ivec2(gl_WorkGroupSize)) / vec2(resolution) - baseTexCoord; + + float depthMin = uintBitsToFloat(sharedDepthMin); + float depthMax = uintBitsToFloat(sharedDepthMax); + + frustumCorners[0] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(0.0, 0.0)); + frustumCorners[1] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(texCoordSpan.x, 0.0)); + frustumCorners[2] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(0.0, texCoordSpan.y)); + frustumCorners[3] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(texCoordSpan.x, texCoordSpan.y)); + frustumCorners[4] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(0.0, 0.0)); + frustumCorners[5] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(texCoordSpan.x, 0.0)); + frustumCorners[6] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(0.0, texCoordSpan.y)); + frustumCorners[7] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(texCoordSpan.x, texCoordSpan.y)); + +} + +AABB CalculateAABB(vec3 corners[8]) { + + vec3 aabbMin = corners[0]; + vec3 aabbMax = corners[0]; + + for (int i = 1; i < 8; i++) { + aabbMin = min(corners[i], aabbMin); + aabbMax = max(corners[i], aabbMax); + } + + AABB aabb; + aabb.center = (aabbMax + aabbMin) * 0.5; + aabb.extent = aabbMax - aabb.center; + return aabb; + +} + +bool SphereAABBIntersection(Sphere sphere, AABB aabb) { + + vec3 diff = max(vec3(0.0), abs(aabb.center - sphere.center) - aabb.extent); + return dot(diff, diff) <= sphere.radius * sphere.radius; + +} void main() { @@ -32,8 +89,9 @@ void main() { float viewDepth = ConvertDepthToViewSpaceDepth(depth); if (gl_LocalInvocationIndex == 0u) { - sharedDepthMin = floatBitsToUint(viewDepth); - sharedDepthMax = floatBitsToUint(viewDepth); + sharedDepthMin = floatBitsToUint(depth); + sharedDepthMax = floatBitsToUint(depth); + depthMask = 0; } int localOffset = int(gl_LocalInvocationIndex); @@ -43,19 +101,31 @@ void main() { barrier(); - atomicMin(sharedDepthMin, floatBitsToUint(viewDepth)); - atomicMax(sharedDepthMax, floatBitsToUint(viewDepth)); + atomicMin(sharedDepthMin, floatBitsToUint(depth)); + atomicMax(sharedDepthMax, floatBitsToUint(depth)); barrier(); - float depthMin = uintBitsToFloat(sharedDepthMin); - float depthMax = uintBitsToFloat(sharedDepthMax); + float depthMin = ConvertDepthToViewSpaceDepth(uintBitsToFloat(sharedDepthMin)); + float depthMax = ConvertDepthToViewSpaceDepth(uintBitsToFloat(sharedDepthMax)); + + float depthRange = depthMax - depthMin; + float invBinSize = 32.0 / depthRange; + int depthBin = clamp(int((viewDepth - depthMin) * invBinSize), 0, 31); + atomicOr(depthMask, 1 << depthBin); + + barrier(); + + vec3 frustumCorners[8]; + GetFrustumCorners(frustumCorners); + + AABB frustumAABB = CalculateAABB(frustumCorners); vec3 viewPos = ConvertDepthToViewSpace(depth, texCoord); for (int i = localOffset; i < pushConstants.lightCount; i += groupSize) { - int lightBucketIdx = i / lightBucketCount; - int lightBuckedBit = i % lightBucketCount; + int lightBucketIdx = i / 32; + int lightBuckedBit = i % 32; bool visible = true; @@ -64,38 +134,36 @@ void main() { uint lightType = floatBitsToUint(light.color.a); + int startBin = 0; + int endBin = 31; + // Remember: Forward is in -z direction if (lightType == POINT_LIGHT) { - /* - vec3 pointToLight = light.location.xyz - viewPos; - float sqrDistance = dot(pointToLight, pointToLight); - float dist = sqrt(sqrDistance); - lightMultiplier = saturate(1.0 - pow(dist / radius, 4.0)) / sqrDistance; - - surface.L = pointToLight / dist; - */ - visible = depthMin > light.location.z - radius && - depthMax < light.location.z + radius; + Sphere sphere; + sphere.center = light.location.xyz; + sphere.radius = radius; + + visible = SphereAABBIntersection(sphere, frustumAABB); + + startBin = clamp(int((light.location.z + radius - depthMin) * invBinSize), 0, 31); + endBin = clamp(int((light.location.z - radius - depthMin) * invBinSize), 0, 31); } else if (lightType == SPOT_LIGHT) { - /* - vec3 pointToLight = light.location.xyz - surface.P; - float sqrDistance = dot(pointToLight, pointToLight); - float dist = sqrt(sqrDistance); - - surface.L = pointToLight / dist; - - float strength = dot(surface.L, normalize(-light.direction.xyz)); - float attenuation = saturate(strength * light.specific0 + light.specific1); - lightMultiplier = sqr(attenuation) / sqrDistance; - */ - visible = depthMin > light.location.z - radius && - depthMax < light.location.z + radius; + Sphere sphere; + sphere.center = light.location.xyz; + sphere.radius = radius; + + visible = SphereAABBIntersection(sphere, frustumAABB); + + startBin = clamp(int((light.location.z + radius - depthMin) * invBinSize), 0, 31); + endBin = clamp(int((light.location.z - radius - depthMin) * invBinSize), 0, 31); } - + int shiftCount = 31 - endBin + startBin; + int downShift = (0xFFFFFFFF >> shiftCount); + int lightMask = downShift << startBin; - if (visible) { + if (visible && (lightMask & depthMask) != 0) { atomicOr(sharedLightBuckets[lightBucketIdx], 1 << lightBuckedBit); } } diff --git a/data/shader/deferred/sss.csh b/data/shader/deferred/sss.csh index f7cf29c28..4b1d1af7a 100644 --- a/data/shader/deferred/sss.csh +++ b/data/shader/deferred/sss.csh @@ -8,8 +8,6 @@ #include <../common/utility.hsh> #include <../common/normalencode.hsh> -#define TRACE_WORLD_SPACE - layout (local_size_x = 8, local_size_y = 8) in; layout(set = 3, binding = 0, r16f) uniform image2D image; @@ -20,6 +18,7 @@ layout(push_constant) uniform constants { vec4 lightDirection; int sampleCount; float maxLength; + float minLengthWorldSpace; float thickness; } pushConstants; @@ -63,23 +62,28 @@ void main() { vec2 texCoord = (vec2(pixel) + 0.5) / vec2(resolution); - vec3 rayPos = ConvertDepthToViewSpace(depth, texCoord); + vec3 rayPos = ConvertDepthToViewSpace(depth, texCoord) + normal * 0.01; float startDepth = -rayPos.z; vec3 rayDir = normalize(-pushConstants.lightDirection.xyz); float stepLength = pushConstants.maxLength / (float(pushConstants.sampleCount)); #ifdef TRACE_WORLD_SPACE - float depthThickness = pushConstants.thickness; - vec3 rayEndPos = rayPos + pushConstants.maxLength * rayDir; + stepLength *= 100.0; + float depthThickness = pushConstants.thickness * 100.0; + vec3 rayEndPos = rayPos + pushConstants.maxLength * 100.0 * rayDir; #else float depthThickness = pushConstants.thickness; vec2 stepPos = PosToUV(rayPos + rayDir); float stepPosLength = length(stepPos - texCoord); - vec3 rayEndPos = rayPos + (pushConstants.maxLength / max(0.01, stepPosLength)) * rayDir; - depthThickness *= stepPosLength; - depthThickness = max(abs(rayPos.z), abs(rayPos.z - rayEndPos.z)) * pushConstants.thickness; - vec2 uvDir = normalize(stepPos - texCoord); + float worldSpaceRayLength = (pushConstants.maxLength / max(0.000001, stepPosLength)); + + float worldSpaceCorrection = clamp(pushConstants.minLengthWorldSpace / worldSpaceRayLength, 1.0, 1000.0); + + vec3 rayEndPos = rayPos + worldSpaceRayLength * worldSpaceCorrection * rayDir; + stepLength *= worldSpaceCorrection; + + depthThickness = max(abs(rayPos.z), abs(rayPos.z - rayEndPos.z)) * pushConstants.thickness * worldSpaceCorrection; #endif float resultDelta = 0.0; @@ -90,15 +94,12 @@ void main() { float rayLength = distance(rayPos, rayEndPos); - //depthThickness = abs(rayPos.z - rayEndPos.z) * stepLength; - vec2 uvPos = texCoord; float noiseOffset = GetInterleavedGradientNoise(texCoord * vec2(resolution)); #ifdef TRACE_WORLD_SPACE rayPos += noiseOffset * stepLength * rayDir; #else - uvPos += noiseOffset * stepLength * uvDir; rayPos += noiseOffset * stepLength * rayDir / stepPosLength; #endif @@ -113,8 +114,11 @@ void main() { offset.xyz /= offset.w; uvPos = offset.xy * 0.5 + 0.5; #else - uvPos += uvDir * stepLength; rayPos += rayDir * stepLength / stepPosLength; + + vec4 offset = globalData.pMatrix * vec4(rayPos, 1.0); + offset.xyz /= offset.w; + uvPos = offset.xy * 0.5 + 0.5; #endif if (uvPos.x < 0.0 || uvPos.x > 1.0 || uvPos.y < 0.0 || uvPos.y > 1.0) continue; @@ -133,7 +137,7 @@ void main() { // Check if the camera can't "see" the ray (ray depth must be larger than the camera depth, so positive depth_delta) if (depthDelta > 0.0 && depthDelta < depthThickness && - depthDelta < 0.5 * rayLength && depthDelta > 0.2 * depthThickness) { + depthDelta < 0.5 * rayLength) { // Mark as occluded occlusion = 1.0; resultDelta = depthDelta; diff --git a/data/shader/raytracer/common.hsh b/data/shader/raytracer/common.hsh index 360bca5cd..09a82cf9c 100644 --- a/data/shader/raytracer/common.hsh +++ b/data/shader/raytracer/common.hsh @@ -6,7 +6,7 @@ #include <../common/octahedron.hsh> #define INF 1000000000000.0 -#define EPSILON 0.1 +#define EPSILON 0.001 #define DIRECTIONAL_LIGHT 0 #define TRIANGLE_LIGHT 1 diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index 3c7ddcc27..1fe3e31f0 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -133,8 +133,8 @@ void main() { if (isRayValid) { // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore - float viewOffset = max(1.0, length(viewPos)) * 0.1; - ray.origin = worldPos + ray.direction * EPSILON * 0.1 * viewOffset + worldNorm * EPSILON * viewOffset * 0.1; + float viewOffset = max(1.0, length(viewPos)); + ray.origin = worldPos + ray.direction * EPSILON * viewOffset + worldNorm * EPSILON * viewOffset; ray.hitID = -1; ray.hitDistance = 0.0; diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index 5606582f2..f319d5c77 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -130,7 +130,7 @@ void main() { // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore float viewOffset = max(1.0, length(viewPos)); - ray.origin = worldPos + ray.direction * EPSILON * viewOffset * 0.01 + worldNorm * EPSILON * 0.01 * viewOffset; + ray.origin = worldPos + ray.direction * EPSILON * viewOffset + worldNorm * EPSILON * viewOffset; ray.hitID = -1; ray.hitDistance = 0.0; diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh index c8c6edab7..a1e8e0027 100644 --- a/data/shader/shadow.hsh +++ b/data/shader/shadow.hsh @@ -574,10 +574,14 @@ vec3 sampleOffsetDirections[20] = vec3[] ( ); -float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSampler, vec3 position) { +float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSampler, vec3 position, + vec3 normal, float cosTheta) { int samples = 20; float diskRadius = shadow.edgeSoftness; + + vec3 bias = shadow.bias * (1.0 / 2048.0) * normal / max(cosTheta * cosTheta, 0.01); + position += bias; vec4 shadowCoords = shadow.cascades[1].cascadeSpace * vec4(position, 1.0); shadowCoords.y *= -1.0; @@ -589,7 +593,7 @@ float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSam float shadowFactor = 0.0; for(int i = 0; i < samples; i++) { shadowFactor += clamp(texture(samplerCubeShadow(cubeMap, shadowSampler), - vec4(shadowCoords.xyz + sampleOffsetDirections[i] * diskRadius, depth - shadow.bias * 0.001)), 0.0, 1.0); + vec4(shadowCoords.xyz + sampleOffsetDirections[i] * diskRadius, depth - 0.0001)), 0.0, 1.0); } shadowFactor /= float(samples + 1); diff --git a/libs/ImguiExtension/panels/FogPanel.cpp b/libs/ImguiExtension/panels/FogPanel.cpp index 2b8935f92..3598cadfb 100644 --- a/libs/ImguiExtension/panels/FogPanel.cpp +++ b/libs/ImguiExtension/panels/FogPanel.cpp @@ -22,7 +22,7 @@ namespace Atlas::ImguiExtension { "%.3f", ImGuiSliderFlags_Logarithmic); ImGui::Text("Volumetric"); ImGui::Checkbox("Raymarching", &fog->rayMarching); - ImGui::SliderInt("Raymarch step count", &fog->rayMarchStepCount, 1, 32); + ImGui::DragInt("Raymarch step count", &fog->rayMarchStepCount, 1, 128); ImGui::SliderFloat("Intensity", &fog->volumetricIntensity, 0.0f, 1.0f); ImGui::PopID(); diff --git a/libs/ImguiExtension/panels/MaterialPanel.cpp b/libs/ImguiExtension/panels/MaterialPanel.cpp index 4eda7eb7a..3d8a8b22a 100644 --- a/libs/ImguiExtension/panels/MaterialPanel.cpp +++ b/libs/ImguiExtension/panels/MaterialPanel.cpp @@ -26,7 +26,7 @@ namespace Atlas::ImguiExtension { } else { if (textureSelector.has_value()) - textureSelector.value()(texture); + texture = textureSelector.value()(texture); } element(); if (texture.IsLoaded() && !textureSelector.has_value()) diff --git a/libs/ImguiExtension/panels/SSSPanel.cpp b/libs/ImguiExtension/panels/SSSPanel.cpp index fe0a1b8b8..0798bd61f 100644 --- a/libs/ImguiExtension/panels/SSSPanel.cpp +++ b/libs/ImguiExtension/panels/SSSPanel.cpp @@ -7,8 +7,10 @@ namespace Atlas::ImguiExtension { ImGui::PushID(GetNameID()); ImGui::Checkbox("Enable", &sss->enable); - ImGui::SliderInt("Sample count", &sss->sampleCount, 2.0, 16.0); + ImGui::Checkbox("Trace in world space", &sss->traceWorldSpace); + ImGui::DragInt("Sample count", &sss->sampleCount, 2, 64); ImGui::SliderFloat("Max length", &sss->maxLength, 0.01f, 1.0f); + ImGui::SliderFloat("Min length world space", &sss->minLengthWorldSpace, 0.01f, 1.0f); ImGui::SliderFloat("Thickness", &sss->thickness, 0.001f, 1.0f, "%.3f", ImGuiSliderFlags_Logarithmic); ImGui::PopID(); diff --git a/src/editor/ui/panels/ResourceSelectionPanel.h b/src/editor/ui/panels/ResourceSelectionPanel.h index 5a744c530..acf47ec6a 100644 --- a/src/editor/ui/panels/ResourceSelectionPanel.h +++ b/src/editor/ui/panels/ResourceSelectionPanel.h @@ -34,9 +34,9 @@ namespace Atlas::Editor::UI { auto buttonName = resourceHandle.IsValid() ? resourceHandle.GetResource()->GetFileName() : "Drop resource here##" + std::to_string(counter++); - ImGui::PushID(resourceHandle.GetID()); + ImGui::PushID(resourceHandle.IsValid() ? resourceHandle.GetID() : counter); - popup.SetID(resourceHandle.GetID()); + popup.SetID(resourceHandle.IsValid() ? resourceHandle.GetID() : counter); if (ImGui::Button(buttonName.c_str(), { resourceButtonSize, 0 })) popup.Open(); diff --git a/src/editor/ui/panels/components/LightComponentPanel.cpp b/src/editor/ui/panels/components/LightComponentPanel.cpp index 51187bf8d..21d57d056 100644 --- a/src/editor/ui/panels/components/LightComponentPanel.cpp +++ b/src/editor/ui/panels/components/LightComponentPanel.cpp @@ -55,10 +55,10 @@ namespace Atlas::Editor::UI { lightComponent.AddDirectionalShadow(300.0f, 3.0f, 1024, 0.05f, 3, 0.95f, true, 2048.0f); } if (lightComponent.type == LightType::PointLight) { - lightComponent.AddPointShadow(0.1f, 1024); + lightComponent.AddPointShadow(0.25f, 1024); } if (lightComponent.type == LightType::SpotLight) { - lightComponent.AddSpotShadow(0.1f, 1024); + lightComponent.AddSpotShadow(2.0f, 1024); } } else if (lightComponent.shadow && !castShadow) { diff --git a/src/editor/ui/panels/components/MeshComponentPanel.cpp b/src/editor/ui/panels/components/MeshComponentPanel.cpp index 9f13c8124..9e767c85c 100644 --- a/src/editor/ui/panels/components/MeshComponentPanel.cpp +++ b/src/editor/ui/panels/components/MeshComponentPanel.cpp @@ -34,6 +34,10 @@ namespace Atlas::Editor::UI { ImGui::Checkbox("Cast shadow", &mesh->castShadow); ImGui::SliderInt("Shadow cascades", &mesh->allowedShadowCascades, 1, 6); + auto region = ImGui::GetContentRegionAvail(); + if (ImGui::Button("Invert normals", { region.x, 0.0 })) + mesh->InvertNormals(); + ImGui::Separator(); ImGui::Text("Culling settings"); ImGui::DragFloat("Distance culling", &mesh->distanceCulling, 1.0f); diff --git a/src/editor/ui/windows/LogWindow.cpp b/src/editor/ui/windows/LogWindow.cpp index 1fee0554b..19aaaca35 100644 --- a/src/editor/ui/windows/LogWindow.cpp +++ b/src/editor/ui/windows/LogWindow.cpp @@ -3,6 +3,8 @@ #include "Log.h" #include "../../Singletons.h" +#include + namespace Atlas::Editor::UI { void LogWindow::Render() { @@ -15,11 +17,13 @@ namespace Atlas::Editor::UI { auto entries = Atlas::Log::GetLatestEntries(10000); for (auto& entry : entries) { - ImGui::Text(""); - if (!ImGui::IsItemVisible()) - continue; - - ImGui::SameLine(); + bool hasNewLine = entry.message.find_first_of('\n') != std::string::npos; + if (!hasNewLine) { + ImGui::TextUnformatted(""); + if (!ImGui::IsItemVisible()) + continue; + ImGui::SameLine(); + } std::string logText; logText.append("[" + std::to_string(entry.time) + "] "); diff --git a/src/engine/lighting/SSS.h b/src/engine/lighting/SSS.h index 1b773b3b8..8c86f39e7 100644 --- a/src/engine/lighting/SSS.h +++ b/src/engine/lighting/SSS.h @@ -12,10 +12,12 @@ namespace Atlas { SSS() = default; int sampleCount = 8; - float maxLength = 0.5f; - float thickness = 0.3f; + float maxLength = 0.04f; + float minLengthWorldSpace = 0.5f; + float thickness = 0.02f; bool enable = true; + bool traceWorldSpace = false; }; diff --git a/src/engine/mesh/DataComponent.h b/src/engine/mesh/DataComponent.h index 50717f143..a34d95a08 100644 --- a/src/engine/mesh/DataComponent.h +++ b/src/engine/mesh/DataComponent.h @@ -156,6 +156,18 @@ namespace Atlas { */ const T& operator[](std::size_t idx) const; + /** + * + * @return + */ + typename std::vector::iterator begin(); + + /** + * + * @return + */ + typename std::vector::iterator end(); + /** * * @return @@ -416,6 +428,20 @@ namespace Atlas { } + template + typename std::vector::iterator DataComponent::begin() { + + return data.begin(); + + } + + template + typename std::vector::iterator DataComponent::end() { + + return data.end(); + + } + template typename std::vector::const_iterator DataComponent::begin() const { diff --git a/src/engine/mesh/Mesh.cpp b/src/engine/mesh/Mesh.cpp index 6d8814b86..8d5c827fd 100644 --- a/src/engine/mesh/Mesh.cpp +++ b/src/engine/mesh/Mesh.cpp @@ -82,6 +82,19 @@ namespace Atlas { } + void Mesh::InvertNormals() { + + if (!data.normals.ContainsData()) + return; + + for (auto& normal : data.normals) + normal = vec4(-vec3(normal.x, normal.y, normal.z), normal.w); + + UpdateData(); + isBvhBuilt = false; + + } + void Mesh::BuildBVH(bool parallelBuild) { auto device = Graphics::GraphicsDevice::DefaultDevice; diff --git a/src/engine/mesh/Mesh.h b/src/engine/mesh/Mesh.h index ca380072c..cc66a7a0d 100644 --- a/src/engine/mesh/Mesh.h +++ b/src/engine/mesh/Mesh.h @@ -59,6 +59,8 @@ namespace Atlas { */ void UpdateVertexArray(); + void InvertNormals(); + /** * Builds up BVH and fills raytracing related buffers */ diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index fe41d3e61..d94bf2e19 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -74,7 +74,7 @@ namespace Atlas { PushConstants pushConstants; #ifdef AE_BINDLESS pushConstants.lightCount = std::min(4096, int32_t(renderState->lightEntities.size())); - pushConstants.lightBucketCount = 1; + pushConstants.lightBucketCount = int32_t(std::ceil(float(pushConstants.lightCount) / 32.0f)); #else std::vector> cascadeMaps; std::vector> cubeMaps; diff --git a/src/engine/renderer/ImpostorRenderer.cpp b/src/engine/renderer/ImpostorRenderer.cpp index c9c370d44..02fca947a 100644 --- a/src/engine/renderer/ImpostorRenderer.cpp +++ b/src/engine/renderer/ImpostorRenderer.cpp @@ -32,7 +32,7 @@ namespace Atlas { auto meshId = item.first; auto instance = item.second; - auto mesh = mainPass->meshIdToMeshMap[meshId]; + auto mesh = renderList->meshIdToMeshMap[meshId]; // If there aren't any impostors there won't be a buffer if (!instance.impostorCount) diff --git a/src/engine/renderer/ImpostorShadowRenderer.cpp b/src/engine/renderer/ImpostorShadowRenderer.cpp index aad4c7c6e..8813167f5 100644 --- a/src/engine/renderer/ImpostorShadowRenderer.cpp +++ b/src/engine/renderer/ImpostorShadowRenderer.cpp @@ -15,7 +15,7 @@ namespace Atlas { } void ImpostorShadowRenderer::Render(Ref& frameBuffer, - Graphics::CommandList* commandList, RenderList::Pass* renderPass, + Graphics::CommandList* commandList, RenderList* renderList, RenderList::Pass* renderPass, mat4 lightViewMatrix, mat4 lightProjectionMatrix, vec3 lightLocation) { struct alignas(16) PushConstants { @@ -34,7 +34,7 @@ namespace Atlas { auto meshId = item.first; auto instance = item.second; - auto mesh = renderPass->meshIdToMeshMap[meshId]; + auto mesh = renderList->meshIdToMeshMap[meshId]; // If there aren't any impostors there won't be a buffer if (!instance.impostorCount) diff --git a/src/engine/renderer/ImpostorShadowRenderer.h b/src/engine/renderer/ImpostorShadowRenderer.h index c4648ceba..0cb5e2456 100644 --- a/src/engine/renderer/ImpostorShadowRenderer.h +++ b/src/engine/renderer/ImpostorShadowRenderer.h @@ -15,7 +15,7 @@ namespace Atlas { void Init(Graphics::GraphicsDevice* device); void Render(Ref& frameBuffer, - Graphics::CommandList* commandList, RenderList::Pass* renderPass, + Graphics::CommandList* commandList, RenderList* renderList, RenderList::Pass* renderPass, mat4 lightViewMatrix, mat4 lightProjectionMatrix, vec3 lightLocation); private: diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 832170ff3..0f6a01e99 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -510,7 +510,7 @@ namespace Atlas { else { Graphics::Profiler::BeginQuery("Post processing"); - if (device->swapChain->isComplete) { + if (device->swapChain->isComplete && !texture) { commandList->BeginRenderPass(device->swapChain, true); textureRenderer.RenderTexture2D(commandList, viewport, &target->outputTexture, @@ -518,6 +518,11 @@ namespace Atlas { commandList->EndRenderPass(); } + else if (texture) { + postProcessRenderer.CopyToTexture(&target->outputTexture, texture, commandList); + } + + target->Swap(); Graphics::Profiler::EndQuery(); } diff --git a/src/engine/renderer/OpaqueRenderer.cpp b/src/engine/renderer/OpaqueRenderer.cpp index 84a7f2633..c6ba82eaf 100644 --- a/src/engine/renderer/OpaqueRenderer.cpp +++ b/src/engine/renderer/OpaqueRenderer.cpp @@ -38,7 +38,7 @@ namespace Atlas { for (const auto& [meshId, instances] : mainPass->meshToInstancesMap) { if (!instances.count) continue; - auto& mesh = mainPass->meshIdToMeshMap[meshId]; + auto& mesh = renderList->meshIdToMeshMap[meshId]; for (auto& subData : mesh->data.subData) { if (!subData.material.IsLoaded()) continue; diff --git a/src/engine/renderer/PostProcessRenderer.h b/src/engine/renderer/PostProcessRenderer.h index 899ba4bc6..87ae3014c 100644 --- a/src/engine/renderer/PostProcessRenderer.h +++ b/src/engine/renderer/PostProcessRenderer.h @@ -17,6 +17,9 @@ namespace Atlas { void Render(Ref target, Ref scene, Graphics::CommandList* commandList, Texture::Texture2D* texture = nullptr); + void CopyToTexture(Texture::Texture2D* sourceTexture, Texture::Texture2D* texture, + Graphics::CommandList* commandList); + private: struct alignas(16) Uniforms { float exposure; @@ -38,9 +41,6 @@ namespace Atlas { void GenerateBloom(const PostProcessing::Bloom& bloom, Texture::Texture2D* hdrTexture, Texture::Texture2D* bloomTexture, Graphics::CommandList* commandList); - void CopyToTexture(Texture::Texture2D* sourceTexture, Texture::Texture2D* texture, - Graphics::CommandList* commandList); - void SetUniforms(const CameraComponent& camera, Ref scene); PipelineConfig GetMainPipelineConfig(); diff --git a/src/engine/renderer/SSSRenderer.cpp b/src/engine/renderer/SSSRenderer.cpp index 8c81987cc..3b5d650b7 100644 --- a/src/engine/renderer/SSSRenderer.cpp +++ b/src/engine/renderer/SSSRenderer.cpp @@ -40,6 +40,8 @@ namespace Atlas { auto lightDirection = glm::normalize(vec3(camera.viewMatrix * vec4( light.transformedProperties.directional.direction, 0.0f))); + pipelineConfig.ManageMacro("TRACE_WORLD_SPACE", sss->traceWorldSpace); + auto pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); @@ -54,6 +56,7 @@ namespace Atlas { .lightDirection = vec4(lightDirection, 0.0), .sampleCount = sss->sampleCount, .maxLength = sss->maxLength, + .minLengthWorldSpace = sss->minLengthWorldSpace, .thickness = sss->thickness }; commandList->PushConstants("constants", &constants); diff --git a/src/engine/renderer/SSSRenderer.h b/src/engine/renderer/SSSRenderer.h index d16332e0f..5a2964765 100644 --- a/src/engine/renderer/SSSRenderer.h +++ b/src/engine/renderer/SSSRenderer.h @@ -20,6 +20,7 @@ namespace Atlas { vec4 lightDirection; int sampleCount; float maxLength; + float minLengthWorldSpace; float thickness; }; diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index 2e6f724aa..6cce24a63 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -29,7 +29,7 @@ namespace Atlas { continue; } - ProcessPass(target, scene, commandList, shadowPass); + ProcessPass(target, scene, commandList, renderList, shadowPass); shadowPass = renderList->PopPassFromQueue(RenderList::RenderPassType::Shadow); } @@ -38,7 +38,7 @@ namespace Atlas { // another push to the queue has been happening. So check again here shadowPass = renderList->PopPassFromQueue(RenderList::RenderPassType::Shadow); if (shadowPass != nullptr) { - ProcessPass(target, scene, commandList, shadowPass); + ProcessPass(target, scene, commandList, renderList, shadowPass); } // Need to also keep track of non processed layer (e.g. long range layers) @@ -60,7 +60,10 @@ namespace Atlas { } - void ShadowRenderer::ProcessPass(Ref target, Ref scene, Graphics::CommandList* commandList, Ref shadowPass) { + void ShadowRenderer::ProcessPass(Ref target, Ref scene, Graphics::CommandList* commandList, + RenderList* renderList, Ref shadowPass) { + + Graphics::Profiler::BeginQuery("Entity pass " + std::to_string(shadowPass->lightEntity) + " layer " + std::to_string(shadowPass->layer)); auto lightEntity = shadowPass->lightEntity; auto& light = lightEntity.GetComponent(); @@ -111,7 +114,7 @@ namespace Atlas { for (auto& [meshId, instances] : shadowPass->meshToInstancesMap) { if (!instances.count) continue; - auto& mesh = shadowPass->meshIdToMeshMap[meshId]; + auto& mesh = renderList->meshIdToMeshMap[meshId]; for (auto& subData : mesh->data.subData) { if (!subData.material.IsLoaded()) continue; @@ -187,11 +190,13 @@ namespace Atlas { } - impostorRenderer.Render(frameBuffer, commandList, + impostorRenderer.Render(frameBuffer, commandList, renderList, shadowPass.get(), component->viewMatrix, component->projectionMatrix, lightLocation); commandList->EndRenderPass(); + Graphics::Profiler::EndQuery(); + } Ref ShadowRenderer::GetOrCreateFrameBuffer(Scene::Entity entity) { diff --git a/src/engine/renderer/ShadowRenderer.h b/src/engine/renderer/ShadowRenderer.h index b74fff1d0..e31118aae 100644 --- a/src/engine/renderer/ShadowRenderer.h +++ b/src/engine/renderer/ShadowRenderer.h @@ -23,7 +23,8 @@ namespace Atlas { void Render(Ref target, Ref scene, Graphics::CommandList* commandList, RenderList* renderList); private: - void ProcessPass(Ref target, Ref scene, Graphics::CommandList* commandList, Ref shadowPass); + void ProcessPass(Ref target, Ref scene, Graphics::CommandList* commandList, + RenderList* renderList, Ref shadowPass); Ref GetOrCreateFrameBuffer(Scene::Entity entity); diff --git a/src/engine/renderer/helper/RenderList.cpp b/src/engine/renderer/helper/RenderList.cpp index 6c45d309e..67433feb1 100644 --- a/src/engine/renderer/helper/RenderList.cpp +++ b/src/engine/renderer/helper/RenderList.cpp @@ -30,6 +30,15 @@ namespace Atlas { JobSystem::Wait(clearJob); + auto meshes = scene->GetMeshes(); + meshIdToMeshMap.reserve(meshes.size()); + + // Fill in missing meshes since they are cleared at the end of each frame + for (const auto& mesh : meshes) { + auto id = mesh.GetID(); + meshIdToMeshMap[id] = mesh; + } + } Ref RenderList::NewMainPass() { @@ -128,13 +137,15 @@ namespace Atlas { JobSystem::Execute(clearJob, [&](JobData&) { std::erase_if(passes, [](const auto& item) { return item->wasUsed != true; }); + meshIdToMeshMap.clear(); for (auto& pass : passes) pass->Reset(); }); } - void RenderList::Pass::NewFrame(Scene::Scene* scene, const std::vector>& meshes) { + void RenderList::Pass::NewFrame(Scene::Scene* scene, const std::vector>& meshes, + const std::unordered_map>& meshIdToMeshMap) { this->scene = scene; @@ -150,14 +161,6 @@ namespace Atlas { impostorMatrices.clear(); if (lastSize) impostorMatrices.reserve(lastSize); - meshIdToMeshMap.reserve(meshes.size()); - - // Fill in missing meshes since they are cleared at the end of each frame - for (const auto& mesh : meshes) { - auto id = mesh.GetID(); - meshIdToMeshMap[id] = mesh; - } - std::erase_if(meshToEntityMap, [&](const auto& item) { return !meshIdToMeshMap.contains(item.first); }); std::erase_if(meshToInstancesMap, [&](const auto& item) { return !meshIdToMeshMap.contains(item.first); }); @@ -179,18 +182,17 @@ namespace Atlas { batch.Add(entity); meshToEntityMap[id] = batch; - meshIdToMeshMap[id] = meshComponent.mesh; } } - void RenderList::Pass::Update(vec3 cameraLocation) { + void RenderList::Pass::Update(vec3 cameraLocation, const std::unordered_map>& meshIdToMeshMap) { size_t maxActorCount = 0; size_t maxImpostorCount = 0; for (auto& [meshId, batch] : meshToEntityMap) { - auto mesh = meshIdToMeshMap[meshId]; + auto mesh = meshIdToMeshMap.at(meshId); if (!mesh->castShadow && type == RenderPassType::Shadow) continue; @@ -200,7 +202,7 @@ namespace Atlas { } for (auto& [meshId, batch] : meshToEntityMap) { - auto mesh = meshIdToMeshMap[meshId]; + auto mesh = meshIdToMeshMap.at(meshId); if (!batch.count) continue; if (!mesh->castShadow && type == RenderPassType::Shadow) continue; @@ -314,7 +316,6 @@ namespace Atlas { } // Need to clear this to free the references - meshIdToMeshMap.clear(); meshToInstancesMap.clear(); wasUsed = false; diff --git a/src/engine/renderer/helper/RenderList.h b/src/engine/renderer/helper/RenderList.h index 0ef893f02..e0c290078 100644 --- a/src/engine/renderer/helper/RenderList.h +++ b/src/engine/renderer/helper/RenderList.h @@ -58,7 +58,6 @@ namespace Atlas { std::unordered_map meshToEntityMap; std::unordered_map meshToInstancesMap; - std::unordered_map> meshIdToMeshMap; bool wasUsed = false; @@ -70,11 +69,12 @@ namespace Atlas { Ref lastMatricesBuffer; Ref impostorMatricesBuffer; - void NewFrame(Scene::Scene* scene, const std::vector>& meshes); + void NewFrame(Scene::Scene* scene, const std::vector>& meshes, + const std::unordered_map>& meshIdToMeshMap); void Add(const ECS::Entity& entity, const MeshComponent& meshComponent); - void Update(vec3 cameraLocation); + void Update(vec3 cameraLocation, const std::unordered_map>& meshIdToMeshMap); void FillBuffers(); @@ -110,6 +110,8 @@ namespace Atlas { std::mutex mutex; std::atomic_bool doneProcessingShadows; + std::unordered_map> meshIdToMeshMap; + JobGroup clearJob { JobPriority::High }; }; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 9ed7eef3f..fba00e272 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -331,7 +331,7 @@ namespace Atlas::Scene { auto meshes = scene->GetMeshes(); renderList.NewFrame(scene); - JobGroup group; + JobGroup group{ JobPriority::High }; for (auto& lightEntity : lightSubset) { auto& light = lightEntity.GetComponent(); @@ -352,9 +352,9 @@ namespace Atlas::Scene { if (shadowPass == nullptr) shadowPass = renderList.NewShadowPass(lightEntity, data.idx); - shadowPass->NewFrame(scene, meshes); + shadowPass->NewFrame(scene, meshes, renderList.meshIdToMeshMap); scene->GetRenderList(frustum, shadowPass); - shadowPass->Update(camera.GetLocation()); + shadowPass->Update(camera.GetLocation(), renderList.meshIdToMeshMap); shadowPass->FillBuffers(); renderList.FinishPass(shadowPass); }); @@ -366,9 +366,9 @@ namespace Atlas::Scene { if (mainPass == nullptr) mainPass = renderList.NewMainPass(); - mainPass->NewFrame(scene, meshes); + mainPass->NewFrame(scene, meshes, renderList.meshIdToMeshMap); scene->GetRenderList(camera.frustum, mainPass); - mainPass->Update(camera.GetLocation()); + mainPass->Update(camera.GetLocation(), renderList.meshIdToMeshMap); mainPass->FillBuffers(); renderList.FinishPass(mainPass); diff --git a/src/engine/scripting/bindings/LightingBindings.cpp b/src/engine/scripting/bindings/LightingBindings.cpp index c477c72a1..d1b630dc2 100644 --- a/src/engine/scripting/bindings/LightingBindings.cpp +++ b/src/engine/scripting/bindings/LightingBindings.cpp @@ -126,6 +126,37 @@ namespace Atlas::Scripting::Bindings { "probe", &Lighting::Sky::probe ); + ns->new_usertype("ShadowView", + "nearDistance", &Lighting::ShadowView::nearDistance, + "farDistance", &Lighting::ShadowView::farDistance, + "viewMatrix", &Lighting::ShadowView::viewMatrix, + "projectionMatrix", &Lighting::ShadowView::projectionMatrix, + "frustumMatrix", &Lighting::ShadowView::frustumMatrix, + "terrainFrustumMatrix", &Lighting::ShadowView::terrainFrustumMatrix, + "orthoSize", &Lighting::ShadowView::orthoSize + ); + + ns->new_usertype("Shadow", + "SetResolution", &Lighting::Shadow::SetResolution, + "Update", &Lighting::Shadow::Update, + "center", &Lighting::Shadow::center, + "distance", &Lighting::Shadow::distance, + "longRangeDistance", &Lighting::Shadow::longRangeDistance, + "bias", &Lighting::Shadow::bias, + "splitCorrection", &Lighting::Shadow::splitCorrection, + "edgeSoftness", &Lighting::Shadow::edgeSoftness, + "cascadeBlendDistance", &Lighting::Shadow::cascadeBlendDistance, + "resolution", &Lighting::Shadow::resolution, + "views", &Lighting::Shadow::views, + "viewCount", &Lighting::Shadow::viewCount, + "isCascaded", &Lighting::Shadow::isCascaded, + "followMainCamera", &Lighting::Shadow::followMainCamera, + "useCubemap", &Lighting::Shadow::useCubemap, + "allowTerrain", &Lighting::Shadow::allowTerrain, + "longRange", &Lighting::Shadow::longRange, + "update", &Lighting::Shadow::update + ); + } } \ No newline at end of file diff --git a/src/engine/scripting/bindings/SceneBindings.cpp b/src/engine/scripting/bindings/SceneBindings.cpp index 32452d714..4aea14096 100644 --- a/src/engine/scripting/bindings/SceneBindings.cpp +++ b/src/engine/scripting/bindings/SceneBindings.cpp @@ -171,12 +171,28 @@ namespace Atlas::Scripting::Bindings { "spot", &TypeProperties::spot ); - // TODO: Extend this + ns->new_enum("LightType", { + { "DirectionalLight", LightType::DirectionalLight }, + { "PointLight", LightType::PointLight }, + { "SpotLight", LightType::SpotLight } + }); + + ns->new_enum("LightMobility", { + { "StationaryLight", LightMobility::StationaryLight }, + { "MovableLight", LightMobility::MovableLight } + }); + ns->new_usertype("LightComponent", + "AddPointShadow", &LightComponent::AddPointShadow, + "AddSpotShadow", &LightComponent::AddSpotShadow, + "IsVisible", &LightComponent::IsVisible, + "type", &LightComponent::type, + "mobility", &LightComponent::mobility, "color", &LightComponent::color, "intensity", &LightComponent::intensity, "properties", &LightComponent::properties, "transformedProperties", &LightComponent::transformedProperties, + "shadow", &LightComponent::shadow, "isMain", &LightComponent::isMain, "volumetric", &LightComponent::volumetric ); From 39f6eb27eefff8795aed06b82ae06b50a4cdd4db Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Fri, 20 Sep 2024 21:44:19 +0200 Subject: [PATCH 47/66] Fixed some shaders --- data/shader/impostor/impostor.fsh | 5 +++-- data/shader/terrain/terrain.fsh | 5 +++-- data/shader/vegetation/vegetation.fsh | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/data/shader/impostor/impostor.fsh b/data/shader/impostor/impostor.fsh index 494b6ab55..a2f1b7d08 100644 --- a/data/shader/impostor/impostor.fsh +++ b/data/shader/impostor/impostor.fsh @@ -5,8 +5,9 @@ layout (location = 0) out vec4 baseColorFS; layout (location = 1) out vec2 normalFS; layout (location = 2) out vec2 geometryNormalFS; layout (location = 3) out vec3 roughnessMetalnessAoFS; -layout (location = 4) out uint materialIdxFS; -layout (location = 5) out vec2 velocityFS; +layout (location = 4) out vec3 emissiveFS; +layout (location = 5) out uint materialIdxFS; +layout (location = 6) out vec2 velocityFS; layout(location=0) in vec3 positionVS; layout(location=1) in vec2 texCoordVS; diff --git a/data/shader/terrain/terrain.fsh b/data/shader/terrain/terrain.fsh index ac577dba8..556b01c96 100644 --- a/data/shader/terrain/terrain.fsh +++ b/data/shader/terrain/terrain.fsh @@ -9,8 +9,9 @@ layout (location = 0) out vec3 baseColorFS; layout (location = 1) out vec2 normalFS; layout (location = 2) out vec2 geometryNormalFS; layout (location = 3) out vec3 roughnessMetalnessAoFS; -layout (location = 4) out uint materialIdxFS; -layout (location = 5) out vec2 velocityFS; +layout (location = 4) out vec3 emissiveFS; +layout (location = 5) out uint materialIdxFS; +layout (location = 6) out vec2 velocityFS; layout (set = 3, binding = 1) uniform sampler2D normalMap; layout (set = 3, binding = 2) uniform usampler2D splatMap; diff --git a/data/shader/vegetation/vegetation.fsh b/data/shader/vegetation/vegetation.fsh index e0f47c8dc..a4997a72e 100644 --- a/data/shader/vegetation/vegetation.fsh +++ b/data/shader/vegetation/vegetation.fsh @@ -6,8 +6,9 @@ layout (location = 0) out vec3 baseColorFS; layout (location = 1) out vec2 normalFS; layout (location = 2) out vec2 geometryNormalFS; layout (location = 3) out vec3 roughnessMetalnessAoFS; -layout (location = 4) out uint materialIdxFS; -layout (location = 5) out vec2 velocityFS; +layout (location = 4) out vec3 emissiveFS; +layout (location = 5) out uint materialIdxFS; +layout (location = 6) out vec2 velocityFS; #ifdef BASE_COLOR_MAP layout(set = 3, binding = 0) uniform sampler2D baseColorMap; From 058c12f58787f0e5d493d765a0488520c97dae56 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Fri, 20 Sep 2024 23:12:21 +0200 Subject: [PATCH 48/66] Working on some improvements --- src/engine/jobsystem/Worker.cpp | 11 ++++++++--- src/engine/raytracing/RayTracingManager.cpp | 4 ++++ src/engine/renderer/MainRenderer.cpp | 3 ++- src/engine/renderer/helper/RenderList.cpp | 12 ++++++++++-- src/engine/resource/Resource.h | 17 ++++++++++++++++- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/engine/jobsystem/Worker.cpp b/src/engine/jobsystem/Worker.cpp index e83f40352..33cc05102 100644 --- a/src/engine/jobsystem/Worker.cpp +++ b/src/engine/jobsystem/Worker.cpp @@ -31,9 +31,14 @@ namespace Atlas { HANDLE threadHandle = static_cast(thread.native_handle()); switch (priority) { case JobPriority::High: success &= SetThreadPriority(threadHandle, THREAD_PRIORITY_HIGHEST); break; - case JobPriority::Low: success &= SetThreadPriority(threadHandle, THREAD_PRIORITY_LOWEST); break; - default: break; - } + case JobPriority::Low: success &= SetThreadPriority(threadHandle, THREAD_BASE_PRIORITY_IDLE); break; + default: success &= SetThreadPriority(threadHandle, THREAD_BASE_PRIORITY_IDLE); break; + } + std::wstring threadName = L"Atlas worker " + std::to_wstring(workerId) + L" priority " + std::to_wstring(static_cast(priority)); + SetThreadDescription( + threadHandle, + threadName.c_str() + ); #endif #if defined(AE_OS_MACOS) || defined(AE_OS_LINUX) auto minPriority = sched_get_priority_min(SCHED_RR); diff --git a/src/engine/raytracing/RayTracingManager.cpp b/src/engine/raytracing/RayTracingManager.cpp index a21150ebe..3bf5f2b6f 100644 --- a/src/engine/raytracing/RayTracingManager.cpp +++ b/src/engine/raytracing/RayTracingManager.cpp @@ -21,7 +21,11 @@ namespace Atlas::RayTracing { continue; if (mesh->IsBVHBuilt() || !mesh->rayTrace) continue; + if (mesh->data.GetIndexCount() == 0 || + mesh->data.GetVertexCount() == 0) + continue; JobSystem::Execute(bvhUpdateGroup, [mesh](JobData&) { + mesh->BuildBVH(false); }); } diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 0f6a01e99..72a0ced77 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -136,7 +136,8 @@ namespace Atlas { volumetricCloudRenderer.RenderShadow(target, scene, commandList); JobSystem::WaitSpin(renderState->materialUpdateJob); - renderState->materialBuffer.Bind(commandList, 1, 15); + if (renderState->materialBuffer.GetElementCount()) + renderState->materialBuffer.Bind(commandList, 1, 15); // Wait as long as possible for this to finish JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); diff --git a/src/engine/renderer/helper/RenderList.cpp b/src/engine/renderer/helper/RenderList.cpp index 67433feb1..f5913476a 100644 --- a/src/engine/renderer/helper/RenderList.cpp +++ b/src/engine/renderer/helper/RenderList.cpp @@ -192,7 +192,11 @@ namespace Atlas { size_t maxImpostorCount = 0; for (auto& [meshId, batch] : meshToEntityMap) { - auto mesh = meshIdToMeshMap.at(meshId); + auto item = meshIdToMeshMap.find(meshId); + // This happens when meshes are loaded async + if (item == meshIdToMeshMap.end()) + continue; + auto mesh = item->second; if (!mesh->castShadow && type == RenderPassType::Shadow) continue; @@ -202,7 +206,11 @@ namespace Atlas { } for (auto& [meshId, batch] : meshToEntityMap) { - auto mesh = meshIdToMeshMap.at(meshId); + auto item = meshIdToMeshMap.find(meshId); + // This happens when meshes are loaded async + if (item == meshIdToMeshMap.end()) + continue; + auto mesh = item->second; if (!batch.count) continue; if (!mesh->castShadow && type == RenderPassType::Shadow) continue; diff --git a/src/engine/resource/Resource.h b/src/engine/resource/Resource.h index 48ceaa0bc..2a226af72 100644 --- a/src/engine/resource/Resource.h +++ b/src/engine/resource/Resource.h @@ -148,7 +148,21 @@ namespace Atlas { public: ResourceHandle() = default; - ResourceHandle(Ref>& resource) : resource(resource) {} + ResourceHandle(const Ref& data) : isGenerated(true) { + + Hash hash; + HashCombine(hash, static_cast(data.get())); + + auto path = "generated/" + std::to_string(hash); + resource = CreateRef>(path, ResourceOrigin::User, data); + + } + + ResourceHandle(const Ref>& resource) : resource(resource) {} + + inline bool IsGenerated() const { + return isGenerated; + } inline bool IsValid() const { return resource != nullptr; @@ -205,6 +219,7 @@ namespace Atlas { private: Ref> resource = nullptr; + bool isGenerated = false; }; From 62b471d32eb6a5fe3e315bcc370c3af77c58c442 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 21 Sep 2024 19:04:26 +0200 Subject: [PATCH 49/66] Made some adjustments --- src/engine/jobsystem/JobSystem.cpp | 2 +- src/engine/jobsystem/Worker.cpp | 13 +++++-------- src/engine/mesh/Mesh.cpp | 2 +- src/engine/raytracing/RayTracingManager.cpp | 3 +-- src/engine/renderer/helper/RenderList.cpp | 2 ++ src/engine/renderer/helper/RenderList.h | 1 + src/engine/scene/SceneRenderState.cpp | 7 +++++-- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/engine/jobsystem/JobSystem.cpp b/src/engine/jobsystem/JobSystem.cpp index 40e5cf15b..575ce24e6 100644 --- a/src/engine/jobsystem/JobSystem.cpp +++ b/src/engine/jobsystem/JobSystem.cpp @@ -28,7 +28,7 @@ namespace Atlas { // Need to set our own main thread priority, otherwise we will loose when in contention with other threads #ifdef AE_OS_WINDOWS auto threadHandle = GetCurrentThread(); - success = SetThreadPriority(threadHandle, THREAD_PRIORITY_HIGHEST) > 0; + success = SetThreadPriority(threadHandle, THREAD_PRIORITY_TIME_CRITICAL) > 0; #endif #if defined(AE_OS_MACOS) || defined(AE_OS_LINUX) auto maxPriority = sched_get_priority_max(SCHED_RR); diff --git a/src/engine/jobsystem/Worker.cpp b/src/engine/jobsystem/Worker.cpp index 33cc05102..26e684b26 100644 --- a/src/engine/jobsystem/Worker.cpp +++ b/src/engine/jobsystem/Worker.cpp @@ -30,15 +30,12 @@ namespace Atlas { #ifdef AE_OS_WINDOWS HANDLE threadHandle = static_cast(thread.native_handle()); switch (priority) { - case JobPriority::High: success &= SetThreadPriority(threadHandle, THREAD_PRIORITY_HIGHEST); break; - case JobPriority::Low: success &= SetThreadPriority(threadHandle, THREAD_BASE_PRIORITY_IDLE); break; - default: success &= SetThreadPriority(threadHandle, THREAD_BASE_PRIORITY_IDLE); break; + case JobPriority::High: success &= SetThreadPriority(threadHandle, THREAD_PRIORITY_TIME_CRITICAL) > 0; break; + case JobPriority::Low: success &= SetThreadPriority(threadHandle, THREAD_PRIORITY_IDLE) > 0; break; + default: success &= SetThreadPriority(threadHandle, THREAD_PRIORITY_NORMAL) > 0; break; } - std::wstring threadName = L"Atlas worker " + std::to_wstring(workerId) + L" priority " + std::to_wstring(static_cast(priority)); - SetThreadDescription( - threadHandle, - threadName.c_str() - ); + std::wstring threadName = L"Worker " + std::to_wstring(workerId) + L" priority " + std::to_wstring(static_cast(priority)); + SetThreadDescription(threadHandle, threadName.c_str()); #endif #if defined(AE_OS_MACOS) || defined(AE_OS_LINUX) auto minPriority = sched_get_priority_min(SCHED_RR); diff --git a/src/engine/mesh/Mesh.cpp b/src/engine/mesh/Mesh.cpp index 8d5c827fd..a4cd92af6 100644 --- a/src/engine/mesh/Mesh.cpp +++ b/src/engine/mesh/Mesh.cpp @@ -103,7 +103,7 @@ namespace Atlas { AE_ASSERT(data.indexCount > 0 && "There is no data in this mesh"); - if (data.indexCount == 0 || !bindless) return; + if (data.indexCount == 0 || !bindless || !vertexBuffer.elementCount || !indexBuffer.elementCount) return; data.BuildBVH(parallelBuild); diff --git a/src/engine/raytracing/RayTracingManager.cpp b/src/engine/raytracing/RayTracingManager.cpp index 3bf5f2b6f..712d98429 100644 --- a/src/engine/raytracing/RayTracingManager.cpp +++ b/src/engine/raytracing/RayTracingManager.cpp @@ -24,8 +24,7 @@ namespace Atlas::RayTracing { if (mesh->data.GetIndexCount() == 0 || mesh->data.GetVertexCount() == 0) continue; - JobSystem::Execute(bvhUpdateGroup, [mesh](JobData&) { - + JobSystem::Execute(bvhUpdateGroup, [mesh](JobData&) { mesh->BuildBVH(false); }); } diff --git a/src/engine/renderer/helper/RenderList.cpp b/src/engine/renderer/helper/RenderList.cpp index f5913476a..bc99b5bf7 100644 --- a/src/engine/renderer/helper/RenderList.cpp +++ b/src/engine/renderer/helper/RenderList.cpp @@ -29,6 +29,7 @@ namespace Atlas { processedPasses.clear(); JobSystem::Wait(clearJob); + wasCleared = false; auto meshes = scene->GetMeshes(); meshIdToMeshMap.reserve(meshes.size()); @@ -132,6 +133,7 @@ namespace Atlas { void RenderList::Clear() { // We can reset the scene now and delete the reference + wasCleared = true; scene = nullptr; JobSystem::Execute(clearJob, diff --git a/src/engine/renderer/helper/RenderList.h b/src/engine/renderer/helper/RenderList.h index e0c290078..047151fe7 100644 --- a/src/engine/renderer/helper/RenderList.h +++ b/src/engine/renderer/helper/RenderList.h @@ -109,6 +109,7 @@ namespace Atlas { std::mutex mutex; std::atomic_bool doneProcessingShadows; + std::atomic_bool wasCleared = false; std::unordered_map> meshIdToMeshMap; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index fba00e272..ce22c6f1b 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -327,7 +327,8 @@ namespace Atlas::Scene { auto lightSubset = scene->GetSubset(); auto camera = scene->GetMainCamera(); - JobSystem::Execute(fillRenderListJob, [&, lightSubset, camera](JobData&) { + JobSystem::Execute(fillRenderListJob, [&, lightSubset, camera](JobData&) { + auto meshes = scene->GetMeshes(); renderList.NewFrame(scene); @@ -371,7 +372,6 @@ namespace Atlas::Scene { mainPass->Update(camera.GetLocation(), renderList.meshIdToMeshMap); mainPass->FillBuffers(); renderList.FinishPass(mainPass); - }); } @@ -536,6 +536,9 @@ namespace Atlas::Scene { JobSystem::Wait(fillRenderListJob); JobSystem::Wait(cullAndSortLightsJob); + if (!renderList.wasCleared) + renderList.Clear(); + } } From 05dd18dab6d378f214b79a13dc4ddadfeee46986 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Wed, 25 Sep 2024 17:33:11 +0200 Subject: [PATCH 50/66] Fixed issues --- data/shader/deferred/geometry.fsh | 5 +++- data/shader/deferred/geometry.vsh | 12 +++++++--- data/shader/pathtracer/temporal.csh | 24 +++++++++++++++---- data/shader/reflection/rtreflection.csh | 1 + data/shader/rtgi/rtgi.csh | 1 + libs/ImguiExtension/panels/MaterialPanel.cpp | 5 ++++ src/editor/ui/panels/SceneStatisticsPanel.cpp | 3 +++ src/engine/Material.h | 2 ++ src/engine/ecs/EntityManager.h | 17 +++++++++++-- src/engine/ecs/Pool.h | 9 +++++++ src/engine/lighting/LightingSerializer.cpp | 5 ++++ src/engine/loader/ModelImporter.cpp | 14 +++++++---- src/engine/mesh/MeshSerializer.cpp | 4 ++++ src/engine/renderer/FSR2Renderer.cpp | 3 ++- src/engine/renderer/MainRenderer.cpp | 3 --- src/engine/renderer/OpaqueRenderer.cpp | 3 +++ src/engine/renderer/OpaqueRenderer.h | 3 +++ .../renderer/helper/RayTracingHelper.cpp | 2 +- src/engine/renderer/target/RenderTarget.cpp | 19 ++++++++------- src/engine/scene/Scene.cpp | 2 +- src/engine/scene/Scene.h | 10 ++++++++ src/engine/scene/SceneRenderState.cpp | 8 +++---- src/engine/texture/Texture.cpp | 2 +- 23 files changed, 124 insertions(+), 33 deletions(-) diff --git a/data/shader/deferred/geometry.fsh b/data/shader/deferred/geometry.fsh index 8c570cbfb..5a4c8af0d 100644 --- a/data/shader/deferred/geometry.fsh +++ b/data/shader/deferred/geometry.fsh @@ -24,7 +24,7 @@ layout(location=4) in vec3 ndcLastVS; layout(location=5) in vec4 vertexColorsVS; #endif -layout(location=6) in float normalInversionVS; +// layout(location=6) in float normalInversionVS; #if defined(NORMAL_MAP) || defined(HEIGHT_MAP) layout(location=7) in mat3 TBN; @@ -41,6 +41,9 @@ layout(push_constant) uniform constants { float windTextureLod; float windBendScale; float windWiggleScale; + float uvAnimationX; + float uvAnimationY; + float uvTiling; uint baseColorTextureIdx; uint opacityTextureIdx; uint normalTextureIdx; diff --git a/data/shader/deferred/geometry.vsh b/data/shader/deferred/geometry.vsh index f4f0d18dd..ef7a1da35 100644 --- a/data/shader/deferred/geometry.vsh +++ b/data/shader/deferred/geometry.vsh @@ -46,7 +46,7 @@ layout(location=4) out vec3 ndcLastVS; layout(location=5) out vec4 vertexColorsVS; #endif -layout(location=6) out float normalInversionVS; +// layout(location=6) out float normalInversionVS; // Matrix is several locations #if defined(NORMAL_MAP) || defined(HEIGHT_MAP) @@ -66,6 +66,9 @@ layout(push_constant) uniform constants { float windTextureLod; float windBendScale; float windWiggleScale; + float uvAnimationX; + float uvAnimationY; + float uvTiling; uint baseColorTextureIdx; uint opacityTextureIdx; uint normalTextureIdx; @@ -73,6 +76,7 @@ layout(push_constant) uniform constants { uint metalnessTextureIdx; uint aoTextureIdx; uint heightTextureIdx; + uint emissiveTextureIdx; } PushConstants; // Functions @@ -81,10 +85,12 @@ void main() { mat4 mMatrix = mat4(transpose(currentMatrices[gl_InstanceIndex])); mat4 mMatrixLast = PushConstants.staticMesh > 0 ? mMatrix : mat4(transpose(lastMatrices[gl_InstanceIndex])); - normalInversionVS = determinant(mMatrix) > 0.0 ? 1.0 : -1.0; + // normalInversionVS = determinant(mMatrix) > 0.0 ? 1.0 : -1.0; #ifdef TEX_COORDS - texCoordVS = PushConstants.invertUVs > 0 ? vec2(vTexCoord.x, 1.0 - vTexCoord.y) : vTexCoord; + texCoordVS = PushConstants.invertUVs > 0 ? vec2(vTexCoord.x, 1.0 - vTexCoord.y) : vTexCoord; + texCoordVS += vec2(PushConstants.uvAnimationX, PushConstants.uvAnimationY) * globalData.time; + texCoordVS *= PushConstants.uvTiling; #endif mat4 mvMatrix = globalData.vMatrix * mMatrix; diff --git a/data/shader/pathtracer/temporal.csh b/data/shader/pathtracer/temporal.csh index a2740d559..9401b866e 100644 --- a/data/shader/pathtracer/temporal.csh +++ b/data/shader/pathtracer/temporal.csh @@ -105,7 +105,7 @@ void LoadGroupSharedData() { texel = clamp(texel, ivec2(0), ivec2(resolution) - ivec2(1)); - sharedRadianceDepth[i].rgb = FetchTexel(texel); + sharedRadianceDepth[i].rgb = RGBToYCoCg(FetchTexel(texel)); sharedRadianceDepth[i].a = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, texel, 0).r); } @@ -334,6 +334,7 @@ void ComputeVarianceMinMax(out vec3 mean, out vec3 std) { ivec2 pixel = ivec2(gl_GlobalInvocationID); float depth = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, pixel, 0).r); + uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; float linearDepth = depth; float totalWeight = 0.0; @@ -342,11 +343,15 @@ void ComputeVarianceMinMax(out vec3 mean, out vec3 std) { for (int j = -radius; j <= radius; j++) { int sharedMemoryIdx = GetSharedMemoryIndex(ivec2(i, j)); - vec3 sampleRadiance = RGBToYCoCg(FetchCurrentRadiance(sharedMemoryIdx)); + vec3 sampleRadiance = FetchCurrentRadiance(sharedMemoryIdx); float sampleLinearDepth = FetchDepth(sharedMemoryIdx); - float depthPhi = max(1.0, abs(0.025 * linearDepth)); - float weight = min(1.0 , exp(-abs(linearDepth - sampleLinearDepth) / depthPhi)); + uint sampleMaterialIdx = texelFetch(materialIdxTexture, pixel + ivec2(i, j), 0).r; + + float depthPhi = 16.0 / abs(linearDepth); + float weight = min(1.0 , exp(-abs(linearDepth - sampleLinearDepth) * depthPhi)); + + weight = sampleMaterialIdx != materialIdx ? 0.0 : weight; m1 += sampleRadiance * weight; m2 += sampleRadiance * sampleRadiance * weight; @@ -424,6 +429,17 @@ void main() { factor = min(factor, historyLength / (historyLength + 1.0)); + /* + const vec3 luma = vec3(0.299, 0.587, 0.114); + float weightHistory = factor / (1.0 + dot(historyRadiance.rgb, luma)); + float weightCurrent = (1.0 - factor) / (1.0 + dot(currentRadiance.rgb, luma)); + + vec3 resolve = historyRadiance.rgb * weightHistory + + currentRadiance.rgb * weightCurrent; + + resolve /= (weightHistory + weightCurrent); + */ + vec3 resolve = mix(currentRadiance, historyRadiance, factor); imageStore(outAccumImage, pixel, vec4(resolve, historyLength + 1.0)); diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index 1fe3e31f0..63cc3d3d9 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -195,6 +195,7 @@ vec3 EvaluateHit(inout Ray ray) { // Evaluate direct light for (int i = 0; i < uniforms.lightSampleCount; i++) { radiance += EvaluateDirectLight(surface, curSeed); + curSeed += 1.0 / float(uniforms.lightSampleCount); } radiance /= float(uniforms.lightSampleCount); diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index f319d5c77..b63a14123 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -182,6 +182,7 @@ vec3 EvaluateHit(inout Ray ray) { // Evaluate direct light for (int i = 0; i < uniforms.lightSampleCount; i++) { radiance += EvaluateDirectLight(surface, curSeed); + curSeed += 1.0 / float(uniforms.lightSampleCount); } radiance /= float(uniforms.lightSampleCount); diff --git a/libs/ImguiExtension/panels/MaterialPanel.cpp b/libs/ImguiExtension/panels/MaterialPanel.cpp index 3d8a8b22a..3ed4c7ab7 100644 --- a/libs/ImguiExtension/panels/MaterialPanel.cpp +++ b/libs/ImguiExtension/panels/MaterialPanel.cpp @@ -78,8 +78,13 @@ namespace Atlas::ImguiExtension { ImGui::ColorEdit3("Transmissive color", glm::value_ptr(material->transmissiveColor)); + ImGui::DragFloat2("UV animation", glm::value_ptr(material->uvAnimation), 0.01f, -1.0f, 1.0f); + ImGui::DragFloat("UV tiling", &material->tiling, 0.01f, 0.01f, 100.0f); + ImGui::Checkbox("Two sided", &material->twoSided); + + ImGui::PopID(); } diff --git a/src/editor/ui/panels/SceneStatisticsPanel.cpp b/src/editor/ui/panels/SceneStatisticsPanel.cpp index ca113927d..4d40da6ab 100644 --- a/src/editor/ui/panels/SceneStatisticsPanel.cpp +++ b/src/editor/ui/panels/SceneStatisticsPanel.cpp @@ -22,6 +22,8 @@ namespace Atlas::Editor::UI { auto meshes = scene->GetMeshes(); auto materials = scene->GetMaterials(); + auto lightCount = scene->GetComponentCount(); + ImGui::SeparatorText("Dimensions"); ImGui::Text("Min: %.2f, %.2f, %.2f", min.x, min.y, min.z); ImGui::Text("Max: %.2f, %.2f, %.2f", max.x, max.y, max.z); @@ -31,6 +33,7 @@ namespace Atlas::Editor::UI { ImGui::Text("Entity count: %d", int32_t(scene->GetEntityCount())); ImGui::Text("Mesh count: %d", int32_t(meshes.size())); ImGui::Text("Material count: %d", int32_t(materials.size())); + ImGui::Text("Light count: %d", int32_t(lightCount)); ImGui::Text("Physics body count: %d", scene->physicsWorld->GetBodyCount()); } diff --git a/src/engine/Material.h b/src/engine/Material.h index c0a8015a4..828b64d7a 100644 --- a/src/engine/Material.h +++ b/src/engine/Material.h @@ -59,6 +59,8 @@ namespace Atlas { bool twoSided = false; bool vertexColors = false; + vec2 uvAnimation = vec2(0.0f); + uint32_t uvChannel = 0; }; diff --git a/src/engine/ecs/EntityManager.h b/src/engine/ecs/EntityManager.h index 2ed672422..190cd07c9 100644 --- a/src/engine/ecs/EntityManager.h +++ b/src/engine/ecs/EntityManager.h @@ -200,7 +200,13 @@ namespace Atlas { * to create a copy instead of a reference. */ template - std::vector& GetComponents(); + std::vector& GetAll(); + + /* + * Returns the amount of components for a type Comp + */ + template + size_t GetCount(); template size_t SubscribeToTopic(const Topic topic, std::function function); @@ -296,12 +302,19 @@ namespace Atlas { } template - std::vector& EntityManager::GetComponents() { + std::vector& EntityManager::GetAll() { return pools.Get().GetAll(); } + template + size_t EntityManager::GetCount() { + + return pools.Get().GetCount(); + + } + template size_t EntityManager::SubscribeToTopic(const Topic topic, std::function function) { diff --git a/src/engine/ecs/Pool.h b/src/engine/ecs/Pool.h index 73b216bd6..31846cfc1 100644 --- a/src/engine/ecs/Pool.h +++ b/src/engine/ecs/Pool.h @@ -28,6 +28,8 @@ namespace Atlas { std::vector& GetAll(); + size_t GetCount() const; + size_t Subscribe(const Topic topic, std::function function); private: @@ -106,6 +108,13 @@ namespace Atlas { } + template + size_t Pool::GetCount() const { + + return components.size(); + + } + template size_t Pool::Subscribe(const Topic topic, std::function function) { diff --git a/src/engine/lighting/LightingSerializer.cpp b/src/engine/lighting/LightingSerializer.cpp index 10c889de1..44e877cce 100644 --- a/src/engine/lighting/LightingSerializer.cpp +++ b/src/engine/lighting/LightingSerializer.cpp @@ -306,8 +306,10 @@ namespace Atlas::Lighting { j = json { {"sampleCount", p.sampleCount}, {"maxLength", p.maxLength}, + {"minLengthWorldSpace", p.minLengthWorldSpace}, {"thickness", p.thickness}, {"enable", p.enable}, + {"traceWorldSpace", p.traceWorldSpace}, }; } @@ -316,6 +318,9 @@ namespace Atlas::Lighting { j.at("maxLength").get_to(p.maxLength); j.at("thickness").get_to(p.thickness); j.at("enable").get_to(p.enable); + + try_get_json(j, "minLengthWorldSpace", p.minLengthWorldSpace); + try_get_json(j, "traceWorldSpace", p.traceWorldSpace); } void to_json(json& j, const VolumetricClouds::Scattering& p) { diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index e12471973..8018a5393 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -419,6 +419,8 @@ namespace Atlas { traverseNodeTree = [&](aiNode* node, Scene::Entity parentEntity) { auto nodeTransform = glm::transpose(glm::make_mat4(&node->mTransformation.a1)); + auto& parentNameComp = parentEntity.GetComponent(); + for (uint32_t i = 0; i < node->mNumMeshes; i++) { auto meshId = node->mMeshes[i]; auto& meshInfo = meshes[meshId]; @@ -434,7 +436,7 @@ namespace Atlas { parentEntity.GetComponent().AddChild(entity); } - if (lightMap.contains(node->mName.C_Str())) { + if (lightMap.contains(node->mName.C_Str()) && node->mNumChildren == 0) { auto light = lightMap[node->mName.C_Str()]; auto lightType = LightType::DirectionalLight; @@ -445,13 +447,16 @@ namespace Atlas { } auto& lightComp = parentEntity.AddComponent(lightType, LightMobility::StationaryLight); - lightComp.color = Common::ColorConverter::ConvertLinearToSRGB(vec3(light->mColorDiffuse.r, light->mColorDiffuse.g, light->mColorDiffuse.b)); + lightComp.color = vec3(light->mColorDiffuse.r, light->mColorDiffuse.g, light->mColorDiffuse.b); lightComp.intensity = std::max(lightComp.color.r, std::max(lightComp.color.g, lightComp.color.b)); lightComp.color /= std::max(lightComp.intensity, 1e-9f); + lightComp.color = Common::ColorConverter::ConvertLinearToSRGB(lightComp.color); + + float intensityRadius = glm::sqrt(lightComp.intensity / 0.15f); if (lightType == LightType::PointLight) { lightComp.properties.point.position = vec3(light->mPosition.x, light->mPosition.y, light->mPosition.z); - lightComp.properties.point.radius = glm::sqrt(100.0f * light->mAttenuationQuadratic); + lightComp.properties.point.radius = std::max(glm::sqrt(100.0f * light->mAttenuationQuadratic), intensityRadius); lightComp.AddPointShadow(3.0f, 1024); } if (lightType == LightType::SpotLight) { @@ -459,9 +464,10 @@ namespace Atlas { lightComp.properties.spot.direction = vec3(light->mDirection.x, light->mDirection.y, light->mDirection.z); lightComp.properties.spot.innerConeAngle = light->mAngleInnerCone; lightComp.properties.spot.outerConeAngle = light->mAngleOuterCone; + lightComp.properties.point.radius = std::max(glm::sqrt(100.0f * light->mAttenuationQuadratic), intensityRadius); lightComp.AddSpotShadow(3.0f, 1024); } - } + } for (uint32_t i = 0; i < node->mNumChildren; i++) { auto nodeEntity = scene->CreatePrefab(node->mChildren[i]->mName.C_Str(), nodeTransform); diff --git a/src/engine/mesh/MeshSerializer.cpp b/src/engine/mesh/MeshSerializer.cpp index ffd5fbfb1..3d3dad9e5 100644 --- a/src/engine/mesh/MeshSerializer.cpp +++ b/src/engine/mesh/MeshSerializer.cpp @@ -195,6 +195,7 @@ namespace Atlas { {"twoSided", p.twoSided}, {"vertexColors", p.vertexColors}, {"uvChannel", p.uvChannel}, + {"uvAnimation", p.uvAnimation}, }; if (p.baseColorMap.IsValid()) @@ -231,10 +232,13 @@ namespace Atlas { j.at("normalScale").get_to(p.normalScale); j.at("displacementScale").get_to(p.displacementScale); j.at("tiling").get_to(p.tiling); + j.at("tiling").get_to(p.tiling); j.at("twoSided").get_to(p.twoSided); j.at("vertexColors").get_to(p.vertexColors); j.at("uvChannel").get_to(p.uvChannel); + try_get_json(j, "uvAnimation", p.uvAnimation); + auto getTextureHandle = [](const std::string& path, bool colorSpaceConversion) -> auto { return ResourceManager::GetOrLoadResource(path, colorSpaceConversion, Texture::Wrapping::Repeat, Texture::Filtering::Anisotropic, 0); diff --git a/src/engine/renderer/FSR2Renderer.cpp b/src/engine/renderer/FSR2Renderer.cpp index efa7d6b4b..71081e545 100644 --- a/src/engine/renderer/FSR2Renderer.cpp +++ b/src/engine/renderer/FSR2Renderer.cpp @@ -841,7 +841,8 @@ namespace Atlas::Renderer { dispatchParameters.color = GetResource(colorImage, L"FSR2_InputColor", FFX_RESOURCE_STATE_COMPUTE_READ); dispatchParameters.depth = GetResource(depthImage, L"FSR2_InputDepth", FFX_RESOURCE_STATE_COMPUTE_READ); dispatchParameters.motionVectors = GetResource(velocityImage, L"FSR2_InputMotionVectors", FFX_RESOURCE_STATE_COMPUTE_READ); - //dispatchParameters.reactive = GetResource(reactiveMaskImage, L"FSR2_EmptyInputReactiveMap", FFX_RESOURCE_STATE_COMPUTE_READ); + if (!target->IsUsedForPathTracing()) + dispatchParameters.reactive = GetResource(reactiveMaskImage, L"FSR2_EmptyInputReactiveMap", FFX_RESOURCE_STATE_COMPUTE_READ); //dispatchParameters.exposure = GetTextureResource(&context, nullptr, nullptr, 1, 1, VK_FORMAT_UNDEFINED, L"FSR2_InputExposure", FFX_RESOURCE_STATE_COMPUTE_READ); //dispatchParameters.reactive = GetTextureResource(&context, nullptr, nullptr, 1, 1, VK_FORMAT_UNDEFINED, L"FSR2_EmptyInputReactiveMap", FFX_RESOURCE_STATE_COMPUTE_READ); //dispatchParameters.transparencyAndComposition = GetTextureResource(&context, nullptr, nullptr, 1, 1, VK_FORMAT_UNDEFINED, L"FSR2_EmptyTransparencyAndCompositionMap", FFX_RESOURCE_STATE_COMPUTE_READ); diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 72a0ced77..2e2279399 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -496,8 +496,6 @@ namespace Atlas { if (pathTracingRenderer.realTime) { if (scene->postProcessing.fsr2) { - gBufferRenderer.GenerateReactiveMask(target, commandList); - fsr2Renderer.Render(target, scene, commandList); } else { @@ -535,7 +533,6 @@ namespace Atlas { device->SubmitCommandList(commandList); renderState->WaitForAsyncWorkCompletion(); - renderState->renderList.Clear(); } diff --git a/src/engine/renderer/OpaqueRenderer.cpp b/src/engine/renderer/OpaqueRenderer.cpp index c6ba82eaf..00c417629 100644 --- a/src/engine/renderer/OpaqueRenderer.cpp +++ b/src/engine/renderer/OpaqueRenderer.cpp @@ -120,6 +120,9 @@ namespace Atlas { .windTextureLod = mesh->windNoiseTextureLod, .windBendScale = mesh->windBendScale, .windWiggleScale = mesh->windWiggleScale, + .uvAnimationX = material->uvAnimation.x, + .uvAnimationY = material->uvAnimation.y, + .uvTiling = material->tiling, .baseColorTextureIdx = material->HasBaseColorMap() ? sceneState->textureToBindlessIdx[material->baseColorMap.Get()] : 0, .opacityTextureIdx = material->HasOpacityMap() ? sceneState->textureToBindlessIdx[material->opacityMap.Get()] : 0, .normalTextureIdx = material->HasNormalMap() ? sceneState->textureToBindlessIdx[material->normalMap.Get()] : 0, diff --git a/src/engine/renderer/OpaqueRenderer.h b/src/engine/renderer/OpaqueRenderer.h index 9e6274651..af4d3aa90 100644 --- a/src/engine/renderer/OpaqueRenderer.h +++ b/src/engine/renderer/OpaqueRenderer.h @@ -39,6 +39,9 @@ namespace Atlas { float windTextureLod; float windBendScale; float windWiggleScale; + float uvAnimationX; + float uvAnimationY; + float uvTiling; uint32_t baseColorTextureIdx; uint32_t opacityTextureIdx; uint32_t normalTextureIdx; diff --git a/src/engine/renderer/helper/RayTracingHelper.cpp b/src/engine/renderer/helper/RayTracingHelper.cpp index 4cb00a05b..8ee43da2d 100644 --- a/src/engine/renderer/helper/RayTracingHelper.cpp +++ b/src/engine/renderer/helper/RayTracingHelper.cpp @@ -19,7 +19,7 @@ namespace Atlas { RayTracingHelper::RayTracingHelper() { - const size_t lightCount = 128; + const size_t lightCount = 256; indirectDispatchBuffer = Buffer::Buffer(Buffer::BufferUsageBits::IndirectBufferBit | Buffer::BufferUsageBits::HighPriorityMemoryBit, 3 * sizeof(uint32_t), 0); diff --git a/src/engine/renderer/target/RenderTarget.cpp b/src/engine/renderer/target/RenderTarget.cpp index f397302a0..081e47d5e 100644 --- a/src/engine/renderer/target/RenderTarget.cpp +++ b/src/engine/renderer/target/RenderTarget.cpp @@ -331,7 +331,9 @@ namespace Atlas::Renderer { void RenderTarget::UseForPathTracing(bool use) { - if (use) { + useForPathTracing = use; + + if (useForPathTracing) { ivec2 res = GetRelativeResolution(FULL_RES); targetData = RenderTargetData(res, false); targetDataSwap = RenderTargetData(res, false); @@ -359,10 +361,11 @@ namespace Atlas::Renderer { frameAccumTexture.Reset(); } + // Pathtracing is kind of tricky with the depth buffer being in a SFLOAT format, + // so we can't attach this one to render passes or frame buffers + CreateRenderPasses(); CreateFrameBuffers(); - useForPathTracing = use; - } bool RenderTarget::IsUsedForPathTracing() const { @@ -403,7 +406,7 @@ namespace Atlas::Renderer { auto gBufferRenderPassDesc = Graphics::RenderPassDesc{ .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2], colorAttachments[3], colorAttachments[4], colorAttachments[5], colorAttachments[6], colorAttachments[7]}, - .depthAttachment = depthAttachment + .depthAttachment = useForPathTracing ? Graphics::RenderPassDepthAttachment() : depthAttachment }; gBufferRenderPass = graphicsDevice->CreateRenderPass(gBufferRenderPassDesc); } @@ -429,7 +432,7 @@ namespace Atlas::Renderer { auto afterLightingRenderPassDesc = Graphics::RenderPassDesc{ .colorAttachments = {colorAttachments[0], colorAttachments[1], colorAttachments[2]}, - .depthAttachment = depthAttachment + .depthAttachment = useForPathTracing ? Graphics::RenderPassDepthAttachment() : depthAttachment }; afterLightingRenderPass = graphicsDevice->CreateRenderPass(afterLightingRenderPassDesc); } @@ -492,7 +495,7 @@ namespace Atlas::Renderer { {target->velocityTexture->image, 0, true}, {target->stencilTexture->image, 0, false}, }, - .depthAttachment = {target->depthTexture->image, 0, true}, + .depthAttachment = { useForPathTracing ? nullptr : target->depthTexture->image, 0, !useForPathTracing }, .extent = {uint32_t(scaledWidth), uint32_t(scaledHeight)} }; gBufferFrameBuffer = graphicsDevice->CreateFrameBuffer(gBufferFrameBufferDesc); @@ -504,7 +507,7 @@ namespace Atlas::Renderer { {target->velocityTexture->image, 0, true}, {target->stencilTexture->image, 0, false} }, - .depthAttachment = {target->depthTexture->image, 0, true}, + .depthAttachment = { useForPathTracing ? nullptr : target->depthTexture->image, 0, !useForPathTracing}, .extent = {uint32_t(scaledWidth), uint32_t(scaledHeight)} }; afterLightingFrameBuffer = graphicsDevice->CreateFrameBuffer(afterLightingFrameBufferDesc); @@ -516,7 +519,7 @@ namespace Atlas::Renderer { {target->velocityTexture->image, 0, true}, {target->stencilTexture->image, 0, true} }, - .depthAttachment = {target->depthTexture->image, 0, true}, + .depthAttachment = { useForPathTracing ? nullptr : target->depthTexture->image, 0, !useForPathTracing}, .extent = {uint32_t(scaledWidth), uint32_t(scaledHeight)} }; afterLightingFrameBufferWithStencil = graphicsDevice->CreateFrameBuffer(afterLightingFrameBufferDesc); diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index cb6ffdb89..aabcad3df 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -100,7 +100,7 @@ namespace Atlas { // Update scripting components (but only after the first timestep when everything else is settled) if (!firstTimestep) { // Work with a copy here - auto luaScriptComponents = entityManager.GetComponents(); + auto luaScriptComponents = entityManager.GetAll(); for (auto& luaScriptComponent : luaScriptComponents) { luaScriptComponent.Update(luaScriptManager, deltaTime); diff --git a/src/engine/scene/Scene.h b/src/engine/scene/Scene.h index e295d06c1..31a0e7479 100644 --- a/src/engine/scene/Scene.h +++ b/src/engine/scene/Scene.h @@ -87,6 +87,9 @@ namespace Atlas { template Subset GetSubset(); + template + size_t GetComponentCount(); + std::unordered_map Merge(const Ref& other); void Timestep(float deltaTime); @@ -216,6 +219,13 @@ namespace Atlas { } + template + size_t Scene::GetComponentCount() { + + return entityManager.GetCount(); + + } + template void Scene::RegisterResource(std::map>& resources, ResourceHandle resource) { diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index ce22c6f1b..c2b7905b8 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -303,13 +303,13 @@ namespace Atlas::Scene { } } - if (cubemaps.size() != cubemapToBindlessIdx.size()) - cubemaps.resize(cubemapToBindlessIdx.size()); + if (cubemaps.size() != cubemapIdx) + cubemaps.resize(cubemapIdx); for (const auto& [cubemap, idx] : cubemapToBindlessIdx) cubemaps[idx] = cubemap->image; - if (textureArrays.size() != textureArrayToBindlessIdx.size()) - textureArrays.resize(textureArrayToBindlessIdx.size()); + if (textureArrays.size() != textureArrayIdx) + textureArrays.resize(textureArrayIdx); for (const auto& [textureArray, idx] : textureArrayToBindlessIdx) textureArrays[idx] = textureArray->image; diff --git a/src/engine/texture/Texture.cpp b/src/engine/texture/Texture.cpp index cda10ef27..95b715faa 100644 --- a/src/engine/texture/Texture.cpp +++ b/src/engine/texture/Texture.cpp @@ -104,7 +104,7 @@ namespace Atlas { bool generateMipMaps = filtering == Filtering::MipMapLinear || filtering == Filtering::MipMapNearest || filtering == Filtering::Anisotropic; - bool depthFormat = format == VK_FORMAT_D32_SFLOAT || format == VK_FORMAT_D16_UNORM || + bool depthFormat = format == VK_FORMAT_D32_SFLOAT || format == VK_FORMAT_D16_UNORM || format == VK_FORMAT_D16_UNORM_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; VkImageUsageFlags additionalUsageFlags = {}; From 02c3cbafeea1d2c0a48e02cb11270c561db7878d Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 5 Oct 2024 00:03:51 +0200 Subject: [PATCH 51/66] New volumetric lighting + fixes + improvements --- .gitignore | 1 + data/shader/deferred/direct.csh | 56 ++- data/shader/deferred/geometry.fsh | 6 +- data/shader/deferred/geometry.vsh | 4 +- data/shader/deferred/lightCulling.csh | 96 ++-- data/shader/deferred/lightCulling.hsh | 126 ++++- data/shader/pathtracer/rayHit.csh | 7 +- data/shader/raytracer/common.hsh | 10 +- data/shader/raytracer/structures.hsh | 2 + data/shader/reflection/rtreflection.csh | 6 +- data/shader/rtgi/rtgi.csh | 5 +- data/shader/shadow.hsh | 84 ++-- data/shader/structures.hsh | 13 + data/shader/volumetric/fog.hsh | 14 +- data/shader/volumetric/lightCulling.csh | 127 +++++ data/shader/volumetric/volumetric.csh | 452 +++++++++++++++--- data/shader/volumetric/volumetricResolve.csh | 42 +- libs/ImguiExtension/panels/FogPanel.cpp | 1 + libs/ImguiExtension/panels/GPUProfilerPanel.h | 1 - .../ImguiExtension/panels/ReflectionPanel.cpp | 2 +- src/demo/App.cpp | 27 +- src/demo/App.h | 6 +- src/editor/tools/CopyPasteHelper.h | 1 + src/editor/tools/ResourcePayloadHelper.h | 1 + src/editor/ui/panels/SceneHierarchyPanel.cpp | 16 +- src/editor/ui/panels/SceneHierarchyPanel.h | 2 +- src/editor/ui/panels/SceneStatisticsPanel.cpp | 2 + .../components/CameraComponentPanel.cpp | 4 +- .../panels/components/LightComponentPanel.cpp | 1 + .../components/LuaScriptComponentPanel.cpp | 6 + .../panels/components/MeshComponentPanel.cpp | 1 + .../ui/windows/ContentBrowserWindow.cpp | 2 +- src/engine/Engine.cpp | 2 + src/engine/graphics/Buffer.cpp | 2 +- src/engine/graphics/Image.cpp | 4 +- src/engine/graphics/Image.h | 2 +- src/engine/graphics/MemoryManager.cpp | 16 +- src/engine/graphics/MemoryManager.h | 3 +- src/engine/input/KeyboardMap.cpp | 7 + src/engine/input/KeyboardMap.h | 2 + src/engine/lighting/Fog.h | 1 + src/engine/lighting/IrradianceVolume.cpp | 8 +- src/engine/lighting/LightingSerializer.cpp | 15 +- src/engine/loader/AssetLoader.cpp | 5 +- src/engine/loader/ModelImporter.cpp | 9 +- src/engine/mesh/MeshSerializer.cpp | 6 +- src/engine/physics/Player.cpp | 7 +- src/engine/renderer/DDGIRenderer.cpp | 4 +- src/engine/renderer/DirectLightRenderer.cpp | 7 +- src/engine/renderer/DirectLightRenderer.h | 1 - src/engine/renderer/OceanRenderer.cpp | 4 +- src/engine/renderer/PathTracingRenderer.cpp | 2 + src/engine/renderer/RTGIRenderer.cpp | 4 +- src/engine/renderer/RTReflectionRenderer.cpp | 4 +- src/engine/renderer/VolumetricRenderer.cpp | 269 ++++++----- src/engine/renderer/VolumetricRenderer.h | 12 +- src/engine/renderer/helper/CommonStructures.h | 15 +- .../renderer/helper/RayTracingHelper.cpp | 102 ++-- src/engine/renderer/helper/RayTracingHelper.h | 1 + src/engine/renderer/helper/RenderList.cpp | 1 - src/engine/renderer/target/RenderTarget.cpp | 76 +-- src/engine/renderer/target/RenderTarget.h | 20 +- src/engine/scene/Scene.cpp | 88 +++- src/engine/scene/SceneRenderState.cpp | 79 ++- src/engine/scene/SceneRenderState.h | 7 + .../scene/components/ComponentSerializer.cpp | 31 +- src/engine/scene/components/LightComponent.h | 1 + .../scene/components/LuaScriptComponent.cpp | 39 +- .../scene/components/LuaScriptComponent.h | 40 +- .../scripting/bindings/MathBindings.cpp | 22 + .../scripting/bindings/SceneBindings.cpp | 1 - src/engine/texture/Texture.cpp | 20 +- src/engine/texture/Texture.h | 9 +- src/engine/texture/Texture2D.cpp | 11 +- src/engine/texture/Texture2D.h | 11 +- src/engine/texture/Texture2DArray.cpp | 7 +- src/engine/texture/Texture2DArray.h | 3 +- src/engine/texture/Texture3D.cpp | 7 +- src/engine/texture/Texture3D.h | 3 +- 79 files changed, 1577 insertions(+), 537 deletions(-) create mode 100644 data/shader/volumetric/lightCulling.csh diff --git a/.gitignore b/.gitignore index 1bfefbe88..6c1d4816b 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ data/pirates data/meadow .vscode data/elven +data/dungeon diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 61eb356c9..085a294d6 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -3,6 +3,8 @@ #define SHADOW_FILTER_VOGEL #define SHADOW_CASCADE_BLENDING +layout (local_size_x = 16, local_size_y = 16) in; + #include #include @@ -16,8 +18,6 @@ #include <../common/octahedron.hsh> #include <../clouds/shadow.hsh> -layout (local_size_x = 16, local_size_y = 16) in; - layout(set = 3, binding = 0, rgba16f) uniform image2D image; #ifdef SCREEN_SPACE_SHADOWS @@ -27,11 +27,15 @@ layout(set = 3, binding = 1) uniform sampler2D sssTexture; layout(set = 3, binding = 2) uniform sampler2D cloudMap; #endif +layout(set = 3, binding = 4) uniform sampler shadowSampler; + layout(std140, set = 3, binding = 5) uniform CloudShadowUniformBuffer { CloudShadow cloudShadow; } cloudShadowUniforms; -layout(set = 3, binding = 4) uniform sampler shadowSampler; +layout(std430, set = 3, binding = 6) buffer LightBucketsBuffer { + int lightBuckets[]; +}; layout(set = 3, binding = 7) uniform texture2DArray cascadeMaps[8]; layout(set = 3, binding = 15) uniform textureCube cubeMaps[8]; @@ -41,10 +45,9 @@ layout(push_constant) uniform constants { int lightBucketCount; int padding1; int padding2; - int mapIndices[16]; } pushConstants; -shared int sharedLightBuckets[lightBucketCount]; +shared uint sharedLightBuckets[lightBucketCount]; vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMain); float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain); @@ -55,7 +58,7 @@ void LoadGroupSharedData() { int localOffset = int(gl_LocalInvocationIndex); for (int i = localOffset; i < pushConstants.lightBucketCount; i++) { - sharedLightBuckets[i] = lightBuckets[lightBucketOffset + i]; + sharedLightBuckets[i] = uint(lightBuckets[lightBucketOffset + i]); } barrier(); @@ -73,6 +76,8 @@ void main() { float depth = texelFetch(depthTexture, pixel, 0).r; + int lightCount = 0; + vec3 direct = imageLoad(image, pixel).rgb; if (depth < 1.0) { vec3 geometryNormal; @@ -80,25 +85,28 @@ void main() { Surface surface = GetSurface(texCoord, depth, vec3(0.0, -1.0, 0.0), geometryNormal); direct = vec3(0.0); + - int visibleCount = 0; - - for (int i = 0; i < pushConstants.lightBucketCount; i++) { - int lightBucket = sharedLightBuckets[i]; + for (uint i = 0u; i < pushConstants.lightBucketCount; i++) { + uint lightBucket = sharedLightBuckets[i]; if (lightBucket == 0) continue; - for (int j = 0; j < 32; j++) { + // Get most significant bit index + uint bucketBitCount = findMSB(lightBucket) + 1u; + + for (uint j = 0u; j < bucketBitCount; j++) { - bool lightVisible = (lightBucket & (1 << j)) != 0; + bool lightVisible = (lightBucket & (1 << j)) > 0u; if (!lightVisible) continue; - visibleCount += 1; - Light light = lights[i * 32 + j]; + lightCount++; + + Light light = lights[i * 32u + j]; #ifndef AE_BINDLESS - light.shadow.mapIdx = pushConstants.mapIndices[i * 32 + j]; + light.shadow.mapIdx = int(i * 32u + j); #endif - bool isMain = i + j == 0 ? true : false; + bool isMain = i + j == 0u ? true : false; direct += EvaluateLight(light, surface, geometryNormal, isMain); } } @@ -109,7 +117,7 @@ void main() { } } - + //direct = vec3(float(lightCount) / 64.0); imageStore(image, pixel, vec4(direct, 1.0)); } @@ -124,7 +132,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai uint lightType = GetLightType(light); - float lightMultiplier = 1.0; + float attenuation = 1.0; float radius = light.direction.w; if (lightType == DIRECTIONAL_LIGHT) { @@ -134,7 +142,8 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai vec3 pointToLight = light.location.xyz - surface.P; float sqrDistance = dot(pointToLight, pointToLight); float dist = sqrt(sqrDistance); - lightMultiplier = saturate(1.0 - pow(dist / radius, 4.0)) / sqrDistance; + + attenuation = saturate(1.0 - pow(dist / radius, 4.0)) / sqrDistance; surface.L = pointToLight / dist; } @@ -148,9 +157,12 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai float strength = dot(surface.L, normalize(-light.direction.xyz)); float angleAttenuation = saturate(strength * light.specific0 + light.specific1); float distAttenuation = saturate(1.0 - pow(dist / radius, 4.0)) / sqrDistance; - lightMultiplier = distAttenuation * sqr(angleAttenuation); + attenuation = distAttenuation * sqr(angleAttenuation); } + if (attenuation == 0.0) + return vec3(0.0); + UpdateSurface(surface); // Direct diffuse + specular BRDF @@ -161,7 +173,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai float shadowFactor = GetShadowFactor(light, surface, lightType, geometryNormal, isMain); - vec3 radiance = light.color.rgb * light.intensity * lightMultiplier; + vec3 radiance = light.color.rgb * light.intensity * attenuation; direct = direct * radiance * surface.NdotL * shadowFactor; if (surface.material.transmissive) { @@ -183,7 +195,7 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometryNormal, bool isMain) { - if (light.shadow.cascadeCount <= 0) + if (light.shadow.mapIdx < 0) return 1.0; ivec2 resolution = imageSize(image); diff --git a/data/shader/deferred/geometry.fsh b/data/shader/deferred/geometry.fsh index 5a4c8af0d..6f73d1293 100644 --- a/data/shader/deferred/geometry.fsh +++ b/data/shader/deferred/geometry.fsh @@ -24,7 +24,7 @@ layout(location=4) in vec3 ndcLastVS; layout(location=5) in vec4 vertexColorsVS; #endif -// layout(location=6) in float normalInversionVS; +layout(location=6) in float normalInversionVS; #if defined(NORMAL_MAP) || defined(HEIGHT_MAP) layout(location=7) in mat3 TBN; @@ -148,7 +148,7 @@ void main() { // We want the normal always to face the camera for two sided materials geometryNormal *= PushConstants.twoSided > 0 ? gl_FrontFacing ? 1.0 : -1.0 : 1.0; normal *= dot(geometryNormal, normal) < 0.0 ? -1.0 : 1.0; - //normal *= normalInversionVS; + normal *= normalInversionVS; normalFS = EncodeNormal(normal); #else @@ -156,7 +156,7 @@ void main() { geometryNormal *= PushConstants.twoSided > 0 ? gl_FrontFacing ? 1.0 : -1.0 : 1.0; #endif - //geometryNormal *= normalInversionVS; + geometryNormal *= normalInversionVS; geometryNormalFS = EncodeNormal(geometryNormal); diff --git a/data/shader/deferred/geometry.vsh b/data/shader/deferred/geometry.vsh index ef7a1da35..2cd3550a0 100644 --- a/data/shader/deferred/geometry.vsh +++ b/data/shader/deferred/geometry.vsh @@ -46,7 +46,7 @@ layout(location=4) out vec3 ndcLastVS; layout(location=5) out vec4 vertexColorsVS; #endif -// layout(location=6) out float normalInversionVS; +layout(location=6) out float normalInversionVS; // Matrix is several locations #if defined(NORMAL_MAP) || defined(HEIGHT_MAP) @@ -85,7 +85,7 @@ void main() { mat4 mMatrix = mat4(transpose(currentMatrices[gl_InstanceIndex])); mat4 mMatrixLast = PushConstants.staticMesh > 0 ? mMatrix : mat4(transpose(lastMatrices[gl_InstanceIndex])); - // normalInversionVS = determinant(mMatrix) > 0.0 ? 1.0 : -1.0; + normalInversionVS = determinant(mMatrix) > 0.0 ? 1.0 : -1.0; #ifdef TEX_COORDS texCoordVS = PushConstants.invertUVs > 0 ? vec2(vTexCoord.x, 1.0 - vTexCoord.y) : vTexCoord; diff --git a/data/shader/deferred/lightCulling.csh b/data/shader/deferred/lightCulling.csh index db867eeb0..ecfc44c64 100644 --- a/data/shader/deferred/lightCulling.csh +++ b/data/shader/deferred/lightCulling.csh @@ -1,3 +1,5 @@ +layout (local_size_x = 16, local_size_y = 16) in; + #include #include @@ -8,12 +10,14 @@ #include <../common/convert.hsh> #include <../common/utility.hsh> -layout (local_size_x = 16, local_size_y = 16) in; - layout(push_constant) uniform constants { int lightCount; } pushConstants; +layout(std430, set = 3, binding = 6) buffer LightBucketsBuffer { + int lightBuckets[]; +}; + const int groupSize = int(gl_WorkGroupSize.x * gl_WorkGroupSize.y); // Results in 32 * 128 = 4096 possible lights in the tile @@ -22,62 +26,6 @@ shared uint sharedDepthMin; shared uint sharedDepthMax; shared int depthMask; -struct AABB { - vec3 center; - vec3 extent; -}; - -struct Sphere { - vec3 center; - float radius; -}; - -void GetFrustumCorners(out vec3 frustumCorners[8]) { - - ivec2 resolution = textureSize(depthTexture, 0); - - ivec2 basePixel = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize); - vec2 baseTexCoord = vec2(basePixel) / vec2(resolution); - vec2 texCoordSpan = vec2(basePixel + ivec2(gl_WorkGroupSize)) / vec2(resolution) - baseTexCoord; - - float depthMin = uintBitsToFloat(sharedDepthMin); - float depthMax = uintBitsToFloat(sharedDepthMax); - - frustumCorners[0] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(0.0, 0.0)); - frustumCorners[1] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(texCoordSpan.x, 0.0)); - frustumCorners[2] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(0.0, texCoordSpan.y)); - frustumCorners[3] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(texCoordSpan.x, texCoordSpan.y)); - frustumCorners[4] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(0.0, 0.0)); - frustumCorners[5] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(texCoordSpan.x, 0.0)); - frustumCorners[6] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(0.0, texCoordSpan.y)); - frustumCorners[7] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(texCoordSpan.x, texCoordSpan.y)); - -} - -AABB CalculateAABB(vec3 corners[8]) { - - vec3 aabbMin = corners[0]; - vec3 aabbMax = corners[0]; - - for (int i = 1; i < 8; i++) { - aabbMin = min(corners[i], aabbMin); - aabbMax = max(corners[i], aabbMax); - } - - AABB aabb; - aabb.center = (aabbMax + aabbMin) * 0.5; - aabb.extent = aabbMax - aabb.center; - return aabb; - -} - -bool SphereAABBIntersection(Sphere sphere, AABB aabb) { - - vec3 diff = max(vec3(0.0), abs(aabb.center - sphere.center) - aabb.extent); - return dot(diff, diff) <= sphere.radius * sphere.radius; - -} - void main() { ivec2 resolution = textureSize(depthTexture, 0); @@ -101,8 +49,10 @@ void main() { barrier(); - atomicMin(sharedDepthMin, floatBitsToUint(depth)); - atomicMax(sharedDepthMax, floatBitsToUint(depth)); + if (depth != 1.0) { + atomicMin(sharedDepthMin, floatBitsToUint(depth)); + atomicMax(sharedDepthMax, floatBitsToUint(depth)); + } barrier(); @@ -117,7 +67,10 @@ void main() { barrier(); vec3 frustumCorners[8]; - GetFrustumCorners(frustumCorners); + GetFrustumCorners(frustumCorners, resolution, uintBitsToFloat(sharedDepthMin), uintBitsToFloat(sharedDepthMax)); + + Plane frustumPlanes[4]; + GetFrustumPlanes(frustumPlanes, frustumCorners); AABB frustumAABB = CalculateAABB(frustumCorners); @@ -137,28 +90,35 @@ void main() { int startBin = 0; int endBin = 31; + Sphere sphere; + // Remember: Forward is in -z direction if (lightType == POINT_LIGHT) { - Sphere sphere; sphere.center = light.location.xyz; sphere.radius = radius; - - visible = SphereAABBIntersection(sphere, frustumAABB); startBin = clamp(int((light.location.z + radius - depthMin) * invBinSize), 0, 31); endBin = clamp(int((light.location.z - radius - depthMin) * invBinSize), 0, 31); } else if (lightType == SPOT_LIGHT) { - Sphere sphere; - sphere.center = light.location.xyz; - sphere.radius = radius; + sphere = CalculateSphereFromSpotLight(light.location, light.direction, radius); + + vec3 lightToPoint = viewPos - light.location.xyz; + bool inFront = dot(lightToPoint, light.direction.xyz) > 0.0; - visible = SphereAABBIntersection(sphere, frustumAABB); + visible = inFront; startBin = clamp(int((light.location.z + radius - depthMin) * invBinSize), 0, 31); endBin = clamp(int((light.location.z - radius - depthMin) * invBinSize), 0, 31); } + if (lightType != DIRECTIONAL_LIGHT) { + visible = visible && SphereAABBIntersection(sphere, frustumAABB); + if (visible) { + visible = SphereFrustumIntersection(sphere, frustumPlanes); + } + } + int shiftCount = 31 - endBin + startBin; int downShift = (0xFFFFFFFF >> shiftCount); int lightMask = downShift << startBin; diff --git a/data/shader/deferred/lightCulling.hsh b/data/shader/deferred/lightCulling.hsh index 73398c98d..2edf00474 100644 --- a/data/shader/deferred/lightCulling.hsh +++ b/data/shader/deferred/lightCulling.hsh @@ -1,7 +1,22 @@ +#include <../structures.hsh> +#include <../common/convert.hsh> +#include <../common/utility.hsh> + const int lightBucketCount = 128; -layout(std430, set = 3, binding = 6) buffer LightBucketsBuffer { - int lightBuckets[]; +struct AABB { + vec3 center; + vec3 extent; +}; + +struct Sphere { + vec3 center; + float radius; +}; + +struct Plane { + vec3 normal; + float dist; }; int GetLightBucketsGroupOffset() { @@ -9,4 +24,111 @@ int GetLightBucketsGroupOffset() { int groupOffset = int(gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x); return groupOffset * lightBucketCount; +} + +void GetFrustumCorners(out vec3 frustumCorners[8], ivec2 resolution, float depthMin, float depthMax) { + + ivec2 basePixel = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize); + vec2 baseTexCoord = vec2(basePixel) / vec2(resolution); + vec2 texCoordSpan = vec2(basePixel + ivec2(gl_WorkGroupSize)) / vec2(resolution) - baseTexCoord; + + frustumCorners[0] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(0.0, 0.0)); + frustumCorners[1] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(texCoordSpan.x, 0.0)); + frustumCorners[2] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(0.0, texCoordSpan.y)); + frustumCorners[3] = ConvertDepthToViewSpace(depthMin, baseTexCoord + vec2(texCoordSpan.x, texCoordSpan.y)); + frustumCorners[4] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(0.0, 0.0)); + frustumCorners[5] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(texCoordSpan.x, 0.0)); + frustumCorners[6] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(0.0, texCoordSpan.y)); + frustumCorners[7] = ConvertDepthToViewSpace(depthMax, baseTexCoord + vec2(texCoordSpan.x, texCoordSpan.y)); + +} + +Plane CalculatePlane(vec3 v0, vec3 v1, vec3 v2) { + + Plane plane; + + v0 = v0 - v1; + v2 = v2 - v1; + + plane.normal = normalize(cross(v2, v0)); + plane.dist = -dot(plane.normal, v1); + + return plane; + +} + +void GetFrustumPlanes(out Plane planes[4], vec3 frustumCorners[8]) { + + planes[0] = CalculatePlane(frustumCorners[7], frustumCorners[6], frustumCorners[2]); + planes[1] = CalculatePlane(frustumCorners[4], frustumCorners[5], frustumCorners[1]); + planes[2] = CalculatePlane(frustumCorners[5], frustumCorners[7], frustumCorners[1]); + planes[3] = CalculatePlane(frustumCorners[6], frustumCorners[4], frustumCorners[0]); + +} + +AABB CalculateAABB(vec3 corners[8]) { + + vec3 aabbMin = corners[0]; + vec3 aabbMax = corners[0]; + + for (int i = 1; i < 8; i++) { + aabbMin = min(corners[i], aabbMin); + aabbMax = max(corners[i], aabbMax); + } + + AABB aabb; + aabb.center = (aabbMax + aabbMin) * 0.5; + aabb.extent = aabbMax - aabb.center; + return aabb; + +} + +#define COS_PI_QUATER 0.7071067811865475244008443621048490392848359376884740365883398689 + +Sphere CalculateSphereFromSpotLight(vec4 lightLocation, vec4 lightDirection, float radius) { + + Sphere sphere; + + vec2 coneTrig = unpackHalf2x16(floatBitsToUint(lightLocation.w)); + float coneCos = coneTrig.x; + float coneTan = coneTrig.y; + + if (coneCos > COS_PI_QUATER) { + sphere.radius = radius * coneTan; + } + else { + sphere.radius = radius * 0.5 / sqr(coneCos); + } + + sphere.center = lightLocation.xyz + lightDirection.xyz * sphere.radius; + + return sphere; + +} + + +bool SphereAABBIntersection(Sphere sphere, AABB aabb) { + + vec3 diff = max(vec3(0.0), abs(aabb.center - sphere.center) - aabb.extent); + return dot(diff, diff) <= sphere.radius * sphere.radius; + +} + +bool SphereBehindPlane(Sphere sphere, Plane plane) { + + return plane.dist + dot(plane.normal, sphere.center) > -sphere.radius; + +} + +bool SphereFrustumIntersection(Sphere sphere, Plane planes[4]) { + + bool intersect = true; + + intersect = intersect && SphereBehindPlane(sphere, planes[0]); + intersect = intersect && SphereBehindPlane(sphere, planes[1]); + intersect = intersect && SphereBehindPlane(sphere, planes[2]); + intersect = intersect && SphereBehindPlane(sphere, planes[3]); + + return intersect; + } \ No newline at end of file diff --git a/data/shader/pathtracer/rayHit.csh b/data/shader/pathtracer/rayHit.csh index 72bd6c77e..93634474d 100644 --- a/data/shader/pathtracer/rayHit.csh +++ b/data/shader/pathtracer/rayHit.csh @@ -177,10 +177,14 @@ Surface EvaluateBounce(inout Ray ray, inout RayPayload payload) { surface = GetSurfaceParameters(instance, tri, ray, true, 0); // If we hit an emissive surface we need to terminate the ray +#ifndef REALTIME if (dot(surface.material.emissiveColor, vec3(1.0)) > 0.0 && Uniforms.bounceCount == 0) { payload.radiance += surface.material.emissiveColor; } +#else + payload.radiance += payload.throughput * surface.material.emissiveColor; +#endif // Evaluate direct and indirect light vec3 radiance = payload.throughput * surface.material.opacity @@ -228,7 +232,8 @@ vec3 EvaluateDirectLight(inout Surface surface) { // Check for visibilty. This is important to get an // estimate of the solid angle of the light from point P // on the surface. - radiance *= CheckVisibility(surface, lightDistance); + if (light.castShadow) + radiance *= CheckVisibility(surface, lightDistance); return reflectance * radiance * surface.NdotL / lightPdf; diff --git a/data/shader/raytracer/common.hsh b/data/shader/raytracer/common.hsh index 09a82cf9c..3cfdb5b6e 100644 --- a/data/shader/raytracer/common.hsh +++ b/data/shader/raytracer/common.hsh @@ -108,12 +108,16 @@ Light UnpackLight(PackedLight compressed) { light.radiance = compressed.color.rgb; - uint data = floatBitsToUint(compressed.data.x); - light.type = ((data & 0xF0000000u) >> 28u); + uint data0 = floatBitsToUint(compressed.data.x); + uint data1 = floatBitsToUint(compressed.P.w); - light.triangleIdx = int(data & 0x0FFFFFFFu); + light.type = ((data0 & 0xF0000000u) >> 28u); + + light.triangleIdx = int(data0 & 0x0FFFFFFFu); light.instanceIdx = floatBitsToInt(compressed.data.w); + light.castShadow = data1 > 0u; + light.pdf = compressed.data.y; light.area = compressed.N.w; light.radius = compressed.N.w; diff --git a/data/shader/raytracer/structures.hsh b/data/shader/raytracer/structures.hsh index 9d46c00d2..1410eefe3 100644 --- a/data/shader/raytracer/structures.hsh +++ b/data/shader/raytracer/structures.hsh @@ -155,6 +155,8 @@ struct Light { int triangleIdx; int instanceIdx; + bool castShadow; + float pdf; float area; float radius; diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index 63cc3d3d9..5a239f9c4 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -116,6 +116,7 @@ void main() { Surface surface = CreateSurface(V, N, vec3(1.0), material); Ray ray; + ray.ID = i; blueNoiseVec.y *= (1.0 - uniforms.bias); float pdf = 1.0; @@ -191,7 +192,7 @@ vec3 EvaluateHit(inout Ray ray) { radiance += surface.material.emissiveColor; - float curSeed = float(uniforms.frameSeed) / 255.0; + float curSeed = float(uniforms.frameSeed) / 255.0 + float(ray.ID) * float(uniforms.sampleCount); // Evaluate direct light for (int i = 0; i < uniforms.lightSampleCount; i++) { radiance += EvaluateDirectLight(surface, curSeed); @@ -239,7 +240,8 @@ vec3 EvaluateDirectLight(inout Surface surface, inout float seed) { radiance *= CalculateShadowWorldSpace(uniforms.shadow, cascadeMaps, surface.P, surface.geometryNormal, saturate(dot(surface.L, surface.geometryNormal))); #else - radiance *= CheckVisibility(surface, lightDistance); + if (light.castShadow) + radiance *= CheckVisibility(surface, lightDistance); #endif return reflectance * radiance * surface.NdotL / lightPdf; diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index b63a14123..7f237fdf0 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -129,7 +129,7 @@ void main() { if (isRayValid) { // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore - float viewOffset = max(1.0, length(viewPos)); + float viewOffset = max(1.0, 4.0 * length(viewPos)); ray.origin = worldPos + ray.direction * EPSILON * viewOffset + worldNorm * EPSILON * viewOffset; ray.hitID = -1; @@ -226,7 +226,8 @@ vec3 EvaluateDirectLight(inout Surface surface, inout float seed) { radiance *= CalculateShadowWorldSpace(uniforms.shadow, cascadeMaps, surface.P, surface.geometryNormal, saturate(dot(surface.L, surface.geometryNormal))); #else - radiance *= CheckVisibility(surface, lightDistance); + if (light.castShadow) + radiance *= CheckVisibility(surface, lightDistance); #endif return reflectance * radiance * surface.NdotL / lightPdf; diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh index a1e8e0027..f2e1951ec 100644 --- a/data/shader/shadow.hsh +++ b/data/shader/shadow.hsh @@ -15,7 +15,7 @@ struct Cascade { float aligment0; float aligment1; - mat4 cascadeSpace; + mat3x4 cascadeSpace; }; @@ -152,7 +152,7 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v cascadeIndex = distance >= shadow.cascades[4].distance ? 5 : cascadeIndex; cascadeIndex = min(shadow.cascadeCount - 1, cascadeIndex); - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + mat3x4 cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; @@ -170,7 +170,7 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v fragmentPosition += bias; float visibility = cascadeLookup(shadow, cascadeMaps, float(cascadeIndex), - cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true); + mat4(transpose(cascadeMatrix)), fragmentPosition, fragmentPosition, 0.0, true); #ifdef SHADOW_CASCADE_BLENDING if (cascadeIndex < shadow.cascadeCount - 1) { @@ -190,14 +190,14 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v cascadeIndex += 1; fragmentPosition -= bias; - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; - float texelSize = shadow.cascades[0].texelSize; + texelSize = shadow.cascades[0].texelSize; texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; @@ -208,7 +208,7 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v fragmentPosition += bias; visibility = mix(cascadeLookup(shadow, cascadeMaps, float(cascadeIndex), - cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true), visibility, blend); + mat4(transpose(cascadeMatrix)), fragmentPosition, fragmentPosition, 0.0, true), visibility, blend); } } #endif @@ -234,7 +234,7 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v cascadeIndex = distance >= shadow.cascades[4].distance ? 5 : cascadeIndex; cascadeIndex = min(shadow.cascadeCount - 1, cascadeIndex); - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + mat3x4 cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; @@ -252,7 +252,7 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v fragmentPosition += bias; float visibility = cascadeLookup(shadow, cascadeMaps, float(cascadeIndex), - cascadeMatrix, fragmentPosition, position, 0.0, true); + mat4(transpose(cascadeMatrix)), fragmentPosition, position, 0.0, true); #ifdef SHADOW_CASCADE_BLENDING if (cascadeIndex < shadow.cascadeCount - 1) { @@ -272,14 +272,14 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v cascadeIndex += 1; fragmentPosition -= bias; - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; - float texelSize = shadow.cascades[0].texelSize; + texelSize = shadow.cascades[0].texelSize; texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; @@ -290,7 +290,7 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v fragmentPosition += bias; visibility = mix(cascadeLookup(shadow, cascadeMaps, float(cascadeIndex), - cascadeMatrix, fragmentPosition, position, 0.0, true), visibility, blend); + mat4(transpose(cascadeMatrix)), fragmentPosition, position, 0.0, true), visibility, blend); } } #endif @@ -299,14 +299,14 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v } float CalculateShadowWorldSpace(Shadow shadow, sampler2DArrayShadow cascadeMaps, vec3 position, vec3 normal, float cosTheta) { - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + mat3x4 cascadeMatrix = shadow.cascades[0].cascadeSpace; float texelSize = shadow.cascades[0].texelSize; vec3 bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5); position += bias; return cascadeLookup(shadow, cascadeMaps, 0.0, - cascadeMatrix, position, position, 0.0, false); + mat4(transpose(cascadeMatrix)), position, position, 0.0, false); } float offsetLookup(texture2DArray cascadeMaps, sampler shadowSampler, vec2 flooredUV, float u, float v, float cascadeIndex, @@ -346,8 +346,8 @@ float offsetLookup(texture2DArray cascadeMaps, sampler shadowSampler, vec2 uv, f } -float cascadeLookup(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, float cascadeIndex, mat4 cascadeTransform, - vec3 fragmentPosition, vec3 position, float bias, bool fade) { +float cascadeLookup(inout Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, float cascadeIndex, mat4 cascadeTransform, + vec3 fragmentPosition, vec3 position, vec2 texelSize, float bias, bool fade) { vec4 shadowCoords = cascadeTransform * vec4(fragmentPosition, 1.0); shadowCoords.xyz /= shadowCoords.w; @@ -377,7 +377,6 @@ float cascadeLookup(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSa visibility += offsetLookup(cascadeMaps, shadowSampler, shadowCoords.xy, 0.0, 0.0, float(cascadeIndex), resInv, shadowCoords.z, bias); #endif #ifdef SHADOW_FILTER_VOGEL - vec2 texelSize = vec2(shadow.cascades[int(cascadeIndex)].texelSize); for (int i = 0; i < 16; i++) { visibility += offsetLookup(cascadeMaps, shadowSampler, uv, float(cascadeIndex), shadow.edgeSoftness, texelSize, resInv, position, i, shadowCoords.z, bias); } @@ -389,7 +388,7 @@ float cascadeLookup(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSa } -float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 fragmentPosition, vec3 normal, float cosTheta) { +float CalculateCascadedShadow(inout Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 fragmentPosition, vec3 normal, float cosTheta) { // Note: The code below is actually the fastest code on every platform tested // Some platforms have problems directly indexing the cascade array. @@ -407,7 +406,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler cascadeIndex = distance >= shadow.cascades[4].distance ? 5 : cascadeIndex; cascadeIndex = min(shadow.cascadeCount - 1, cascadeIndex); - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + mat3x4 cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; @@ -425,7 +424,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler fragmentPosition += bias; float visibility = cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), - cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true); + mat4(transpose(cascadeMatrix)), fragmentPosition, fragmentPosition, vec2(texelSize), 0.0, true); #ifdef SHADOW_CASCADE_BLENDING if (cascadeIndex < shadow.cascadeCount - 1) { @@ -445,14 +444,14 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler cascadeIndex += 1; fragmentPosition -= bias; - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; - float texelSize = shadow.cascades[0].texelSize; + texelSize = shadow.cascades[0].texelSize; texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; @@ -463,7 +462,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler fragmentPosition += bias; visibility = mix(cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), - cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true), visibility, blend); + mat4(transpose(cascadeMatrix)), fragmentPosition, fragmentPosition, vec2(texelSize), 0.0, true), visibility, blend); } } #endif @@ -471,7 +470,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler return visibility; } -float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, +float CalculateCascadedShadow(inout Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 fragmentPosition, vec3 position, vec3 normal, float cosTheta) { // Note: The code below is actually the fastest code on every platform tested @@ -490,7 +489,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sample cascadeIndex = distance >= shadow.cascades[4].distance ? 5 : cascadeIndex; cascadeIndex = min(shadow.cascadeCount - 1, cascadeIndex); - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + mat3x4 cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; @@ -508,7 +507,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sample fragmentPosition += bias; float visibility = cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), - cascadeMatrix, fragmentPosition, position, -0.00005, true); + mat4(transpose(cascadeMatrix)), fragmentPosition, position, vec2(texelSize), -0.00005, true); #ifdef SHADOW_CASCADE_BLENDING if (cascadeIndex < shadow.cascadeCount - 1) { @@ -528,14 +527,14 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sample cascadeIndex += 1; fragmentPosition -= bias; - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + cascadeMatrix = shadow.cascades[0].cascadeSpace; cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix; cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix; - float texelSize = shadow.cascades[0].texelSize; + texelSize = shadow.cascades[0].texelSize; texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize; texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize; texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize; @@ -546,7 +545,7 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sample fragmentPosition += bias; visibility = mix(cascadeLookup(shadow, cascadeMaps, shadowSampler, float(cascadeIndex), - cascadeMatrix, fragmentPosition, position, -0.0001, true), visibility, blend); + mat4(transpose(cascadeMatrix)), fragmentPosition, position, vec2(texelSize), -0.0001, true), visibility, blend); } } #endif @@ -554,15 +553,15 @@ float CalculateCascadedShadow(Shadow shadow, texture2DArray cascadeMaps, sample return visibility; } -float CalculateShadowWorldSpace(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 position, vec3 normal, float cosTheta) { - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; +float CalculateShadowWorldSpace(inout Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 position, vec3 normal, float cosTheta) { + mat3x4 cascadeMatrix = shadow.cascades[0].cascadeSpace; float texelSize = shadow.cascades[0].texelSize; vec3 bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5); position += bias; return cascadeLookup(shadow, cascadeMaps, shadowSampler, 0.0, - cascadeMatrix, position, position, 0.0, false); + mat4(transpose(cascadeMatrix)), position, position, vec2(texelSize), 0.0, false); } vec3 sampleOffsetDirections[20] = vec3[] ( @@ -574,7 +573,7 @@ vec3 sampleOffsetDirections[20] = vec3[] ( ); -float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSampler, vec3 position, +float CalculatePointShadow(inout Shadow shadow, textureCube cubeMap, sampler shadowSampler, vec3 position, vec3 normal, float cosTheta) { int samples = 20; @@ -582,12 +581,18 @@ float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSam vec3 bias = shadow.bias * (1.0 / 2048.0) * normal / max(cosTheta * cosTheta, 0.01); position += bias; + + mat4 projectionMatrix; + projectionMatrix[0] = shadow.cascades[1].cascadeSpace[0]; + projectionMatrix[1] = shadow.cascades[1].cascadeSpace[1]; + projectionMatrix[2] = shadow.cascades[1].cascadeSpace[2]; + projectionMatrix[3] = shadow.cascades[2].cascadeSpace[0]; - vec4 shadowCoords = shadow.cascades[1].cascadeSpace * vec4(position, 1.0); + vec4 shadowCoords = mat4(transpose(shadow.cascades[0].cascadeSpace)) * vec4(position, 1.0); shadowCoords.y *= -1.0; vec4 absPosition = abs(shadowCoords); float depth = -max(absPosition.x, max(absPosition.y, absPosition.z)); - vec4 clip = shadow.cascades[0].cascadeSpace * vec4(0.0, 0.0, depth, 1.0); + vec4 clip = projectionMatrix * vec4(0.0, 0.0, depth, 1.0); depth = clip.z / clip.w; float shadowFactor = 0.0; @@ -601,18 +606,23 @@ float CalculatePointShadow(Shadow shadow, textureCube cubeMap, sampler shadowSam } -float CalculateSpotShadow(Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, +float CalculateSpotShadow(inout Shadow shadow, texture2DArray cascadeMaps, sampler shadowSampler, vec3 fragmentPosition, vec3 position, vec3 normal, float cosTheta) { float distance = -fragmentPosition.z; - mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace; + mat4 shadowMatrix; + shadowMatrix[0] = shadow.cascades[0].cascadeSpace[0]; + shadowMatrix[1] = shadow.cascades[0].cascadeSpace[1]; + shadowMatrix[2] = shadow.cascades[0].cascadeSpace[2]; + shadowMatrix[3] = shadow.cascades[1].cascadeSpace[0]; + float texelSize = shadow.cascades[0].texelSize; vec3 bias = shadow.bias * (1.0 / 256.0) * normal / max(cosTheta * cosTheta, 0.01); fragmentPosition += bias; return cascadeLookup(shadow, cascadeMaps, shadowSampler, 0.0, - cascadeMatrix, fragmentPosition, position, -0.0001, false); + shadowMatrix, fragmentPosition, position, vec2(texelSize), -0.0001, false); } \ No newline at end of file diff --git a/data/shader/structures.hsh b/data/shader/structures.hsh index 4507a556d..e2e55cdfa 100644 --- a/data/shader/structures.hsh +++ b/data/shader/structures.hsh @@ -22,6 +22,19 @@ struct Light { }; +struct VolumetricLight { + vec4 location; + vec4 direction; + + vec4 color; + float intensity; + + float specific0; + float specific1; + + int shadowIdx; +}; + struct CloudShadow { mat4 vMatrix; diff --git a/data/shader/volumetric/fog.hsh b/data/shader/volumetric/fog.hsh index 9b1f0e71a..e7d87370d 100644 --- a/data/shader/volumetric/fog.hsh +++ b/data/shader/volumetric/fog.hsh @@ -37,10 +37,18 @@ float GetVolumetricFogDensity(Fog fog, vec3 worldPos) { // Henyey-Greenstein phase function https://www.astro.umd.edu/~jph/HG_note.pdf float ComputeScattering(float scatteringAnisotropy, float lightDotView) { + // Range [-1;1] float g = scatteringAnisotropy; float g2 = g * g; - float result = 1.0 - g2; - result /= (4.0 * 3.14 * pow(1.0 + g2 - (2.0 * g) * lightDotView, 1.5)); - return result; + return (1.0 - g2) / (4.0 * 3.14 * pow(1.0 + g2 - (2.0 * g) * lightDotView, 1.5)); + + + /* + float g = scatteringAnisotropy; + float k = 1.55*g - 0.55*g*g*g; + float k2 = k * k; + return (1.0 - k2) / (4.0 * 3.14 * pow(1.0 - k * lightDotView, 2.0)); + */ + } diff --git a/data/shader/volumetric/lightCulling.csh b/data/shader/volumetric/lightCulling.csh new file mode 100644 index 000000000..f5519279f --- /dev/null +++ b/data/shader/volumetric/lightCulling.csh @@ -0,0 +1,127 @@ +layout (local_size_x = 16, local_size_y = 16) in; + +#include <../deferred/lightCulling.hsh> + +#include <../structures.hsh> +#include <../shadow.hsh> +#include <../globals.hsh> + +#include <../common/convert.hsh> +#include <../common/utility.hsh> + +layout(set = 3, binding = 1) uniform sampler2D depthTexture; + +layout (std430, set = 3, binding = 8) buffer VolumetricLights { + VolumetricLight volumetricLights[]; +}; + +layout(std430, set = 3, binding = 10) buffer LightIndicesBuffer { + int lightIndices[]; +}; + +layout(push_constant) uniform constants { + int lightCount; +} pushConstants; + +const int lightCountPerTile = 63; +const int groupSize = int(gl_WorkGroupSize.x * gl_WorkGroupSize.y); + +// Results in 32 * 128 = 4096 possible lights in the tile +shared int sharedLightIndices[lightCountPerTile]; +shared int sharedLightCount; +shared uint sharedDepthMax; + +int GetLightIndicesOffset() { + + int groupOffset = int(gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x); + return groupOffset * (lightCountPerTile + 1); + +} + +void main() { + + ivec2 resolution = textureSize(depthTexture, 0); + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + + vec2 texCoord = (vec2(pixel) + 0.5) / vec2(resolution); + + float depth = texelFetch(depthTexture, pixel, 0).r; + float viewDepth = ConvertDepthToViewSpaceDepth(depth); + + if (gl_LocalInvocationIndex == 0u) { + sharedDepthMax = floatBitsToUint(depth); + sharedLightCount = 0; + } + + barrier(); + + if (depth != 1.0) { + atomicMax(sharedDepthMax, floatBitsToUint(depth)); + } + + barrier(); + + float depthMin = 0.0; + float depthMax = ConvertDepthToViewSpaceDepth(uintBitsToFloat(sharedDepthMax)); + + vec3 frustumCorners[8]; + GetFrustumCorners(frustumCorners, resolution, 0.0, uintBitsToFloat(sharedDepthMax)); + + Plane frustumPlanes[4]; + GetFrustumPlanes(frustumPlanes, frustumCorners); + + AABB frustumAABB = CalculateAABB(frustumCorners); + + vec3 viewPos = ConvertDepthToViewSpace(depth, texCoord); + + int localOffset = int(gl_LocalInvocationIndex); + int lightIdx = 0; + for (int i = localOffset; i < pushConstants.lightCount && lightIdx < lightCountPerTile; i += groupSize) { + bool visible = true; + + VolumetricLight light = volumetricLights[i]; + float radius = light.direction.w; + + uint lightType = floatBitsToUint(light.color.a); + Sphere sphere; + + // Remember: Forward is in -z direction + if (lightType == POINT_LIGHT) { + sphere.center = light.location.xyz; + sphere.radius = radius; + + visible = SphereAABBIntersection(sphere, frustumAABB); + } + else if (lightType == SPOT_LIGHT) { + sphere = CalculateSphereFromSpotLight(light.location, light.direction, radius); + + vec3 lightToPoint = viewPos - light.location.xyz; + visible = dot(lightToPoint, light.direction.xyz) > 0.0; + } + + visible = visible && SphereAABBIntersection(sphere, frustumAABB); + if (visible) { + visible = SphereFrustumIntersection(sphere, frustumPlanes); + } + + if (visible) { + lightIdx = atomicAdd(sharedLightCount, 1); + + if (lightIdx < lightCountPerTile) + sharedLightIndices[lightIdx] = i; + } + } + + barrier(); + + int lightCount = min(lightCountPerTile, sharedLightCount); + int lightIndicesOffset = GetLightIndicesOffset(); + for (int i = localOffset; i < lightCount; i += groupSize) { + lightIndices[i + lightIndicesOffset + 1] = sharedLightIndices[i]; + } + + if (gl_LocalInvocationIndex == 0u) { + lightIndices[lightIndicesOffset] = lightCount; + } + +} \ No newline at end of file diff --git a/data/shader/volumetric/volumetric.csh b/data/shader/volumetric/volumetric.csh index d0cd98a6a..72d195df6 100644 --- a/data/shader/volumetric/volumetric.csh +++ b/data/shader/volumetric/volumetric.csh @@ -1,8 +1,6 @@ -#ifdef AE_TEXTURE_SHADOW_LOD -#extension GL_EXT_texture_shadow_lod : require -#endif +#extension GL_EXT_nonuniform_qualifier : require -layout (local_size_x = 8, local_size_y = 8) in; +layout (local_size_x = 16, local_size_y = 16) in; #include <../globals.hsh> #include <../structures.hsh> @@ -18,26 +16,95 @@ layout (local_size_x = 8, local_size_y = 8) in; layout(set = 3, binding = 0, rgba16f) writeonly uniform image2D volumetricImage; layout(set = 3, binding = 1) uniform sampler2D depthTexture; -layout(set = 3, binding = 2) uniform sampler2DArrayShadow cascadeMaps; -layout(set = 3, binding = 3) uniform sampler2D cloudMap; -layout(set = 3, binding = 4) uniform sampler2D oceanDepthTexture; -layout(set = 3, binding = 5) uniform usampler2D oceanStencilTexture; -layout(set = 3, binding = 6) uniform sampler2D volumetricCloudTexture; -layout(set = 3, binding = 8) uniform sampler2D scramblingRankingTexture; -layout(set = 3, binding = 9) uniform sampler2D sobolSequenceTexture; +layout(set = 3, binding = 2) uniform sampler2D cloudMap; +layout(set = 3, binding = 3) uniform sampler2D oceanDepthTexture; +layout(set = 3, binding = 4) uniform usampler2D oceanStencilTexture; +layout(set = 3, binding = 5) uniform sampler2D volumetricCloudTexture; +layout(set = 3, binding = 6) uniform sampler shadowSampler; layout(std140, set = 3, binding = 7) uniform UniformBuffer { int sampleCount; float intensity; int fogEnabled; float oceanHeight; + int lightCount; + int offsetX; + int offsetY; + int directionalLightCount; vec4 planetCenterAndRadius; Fog fog; - Light light; CloudShadow cloudShadow; } uniforms; -vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords); +layout (std430, set = 3, binding = 8) buffer VolumetricLights { + VolumetricLight volumetricLights[]; +}; + +layout (std430, set = 3, binding = 9) buffer VolumetricShadows { + Shadow volumetricShadows[]; +}; + +layout(std430, set = 3, binding = 10) buffer LightIndicesBuffer { + int lightIndices[]; +}; + +layout(set = 3, binding = 11) uniform texture2DArray cascadeMaps[8]; +layout(set = 3, binding = 19) uniform textureCube cubeMaps[8]; + +const int lightCountPerTile = 63; + +shared uint sharedLightIndices[64]; +shared int sharedLightIndicesCount; + +vec4 ComputeVolumetricDirectionalLights(vec3 fragPos, float startDepth, vec2 texCoords); +vec4 ComputeVolumetricPunctualLights(uint lightType, vec3 fragPos, float startDepth, vec2 texCoords); +float GetShadowFactorDirectionalLight(int lightIdx, int shadowIdx, uint lightType, bool isMain, vec3 currentPosition); +float GetShadowFactorPunctualLight(int lightIdx, int shadowIdx, uint lightType, bool isMain, vec3 currentPosition); + +int GetLightIndicesOffset() { + + int groupOffset = int(gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x); + return groupOffset * (lightCountPerTile + 1); + +} + +void LoadLightTypeData(uint requestedLightType) { + + barrier(); + + int groupSize = int(gl_WorkGroupSize.x * gl_WorkGroupSize.y); + int localOffset = int(gl_LocalInvocationIndex); + + if (localOffset == 0) { + sharedLightIndicesCount = 0; + } + + barrier(); + + int groupOffset = GetLightIndicesOffset(); + int lightCount = min(lightCountPerTile, lightIndices[groupOffset]); + + int lastIdx = 0; + for (int i = localOffset; i < lightCount; i += groupSize) { + uint lightIdx = lightIndices[groupOffset + i + 1]; + uint lightType = floatBitsToUint(volumetricLights[lightIdx].color.a); + if (requestedLightType != lightType) + continue; + + int idx = atomicAdd(sharedLightIndicesCount, 1); + if (idx < lightCountPerTile) + sharedLightIndices[idx] = lightIdx; + } + + barrier(); + + if (localOffset == 0) { + sharedLightIndicesCount = lightCount; + } + + barrier(); + +} void main() { @@ -67,13 +134,28 @@ void main() { } #endif + bool validPixel = pixel.x < imageSize(volumetricImage).x && + pixel.y < imageSize(volumetricImage).y; + vec4 radiance = vec4(0.0); - radiance = ComputeVolumetric(endPos, startDepth, texCoord); - imageStore(volumetricImage, pixel, radiance); + radiance = ComputeVolumetricDirectionalLights(endPos, startDepth, texCoord); + +#ifdef LOCAL_LIGHTS + LoadLightTypeData(POINT_LIGHT); + if (sharedLightIndicesCount > 0) + radiance.rgb += ComputeVolumetricPunctualLights(POINT_LIGHT, endPos, startDepth, texCoord).rgb; + + LoadLightTypeData(SPOT_LIGHT); + if (sharedLightIndicesCount > 0) + radiance.rgb += ComputeVolumetricPunctualLights(SPOT_LIGHT, endPos, startDepth, texCoord).rgb; +#endif + + if (validPixel) + imageStore(volumetricImage, pixel, radiance); } -vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { +vec4 ComputeVolumetricDirectionalLights(vec3 fragPos, float startDepth, vec2 texCoords) { vec2 resolution = vec2(imageSize(volumetricImage)); vec3 viewPosition = vec3(globalData.ivMatrix * vec4(fragPos, 1.0)); @@ -89,73 +171,192 @@ vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { vec4 extinction = vec4(1.0); vec4 extinctionWithClouds = vec4(1.0); - vec2 interleavedTexCoords = (0.5 * texCoords + 0.5) * resolution * 4.0; + vec2 interleavedTexCoords = (0.5 * texCoords + 0.5) * resolution; float noiseOffset = GetInterleavedGradientNoise(interleavedTexCoords); - - ivec2 pixel = ivec2(gl_GlobalInvocationID); - int sampleIdx = int(globalData.frameCount) % 16; - //noiseOffset = SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture); - vec3 currentPosition = stepVector * (noiseOffset + startDepth); - int cascadeIndex = 0; - int lastCascadeIndex = 0; - mat4 cascadeMatrix = uniforms.light.shadow.cascades[0].cascadeSpace; - #ifdef CLOUDS bool receivedCloudExtinction = false; float cloudExtinction = min(textureLod(volumetricCloudTexture, texCoords, 0.0).a, 1.0); #endif for (int i = 0; i < uniforms.sampleCount; i++) { + + float t0 = float(i) / float(uniforms.sampleCount); + float t1 = float(i + 1) / float(uniforms.sampleCount); + + t0 = t0 * t0; + t1 = t1 * t1; + + float delta = t1 - t0; + float t = t0 + delta * noiseOffset; + + currentPosition = rayDirection * t * rayLength + startDepth; + stepLength = delta * rayLength; + + vec3 worldPosition = vec3(globalData.ivMatrix * vec4(currentPosition, 1.0)); + + vec3 lightScattering = vec3(0.0); + vec3 lightAmbient = vec3(1.0); - float dist = -currentPosition.z; + // First all directional lights + for(int j = 0; j < uniforms.directionalLightCount; j++) { + VolumetricLight light = volumetricLights[j]; - int cascadeIndex = 0; + uint lightType = floatBitsToUint(light.color.a); + + bool isMain = j == 0 ? true : false; + float shadowValue = GetShadowFactorDirectionalLight(j, light.shadowIdx, lightType, isMain, currentPosition); + + vec3 lightPosition = currentPosition - 10000.0 * light.direction.xyz; + lightPosition = vec3(globalData.ivMatrix * vec4(lightPosition, 1.0)); + float extinctionToLight = ComputeVolumetricFog(uniforms.fog, worldPosition, lightPosition); + float NdotL = dot(normalize(rayDirection), normalize(light.direction.xyz)); - cascadeIndex = dist >= uniforms.light.shadow.cascades[0].distance ? 1 : cascadeIndex; - cascadeIndex = dist >= uniforms.light.shadow.cascades[1].distance ? 2 : cascadeIndex; - cascadeIndex = dist >= uniforms.light.shadow.cascades[2].distance ? 3 : cascadeIndex; - cascadeIndex = dist >= uniforms.light.shadow.cascades[3].distance ? 4 : cascadeIndex; - cascadeIndex = dist >= uniforms.light.shadow.cascades[4].distance ? 5 : cascadeIndex; - - cascadeIndex = min(uniforms.light.shadow.cascadeCount - 1, cascadeIndex); - - if (lastCascadeIndex != cascadeIndex) { - cascadeMatrix = uniforms.light.shadow.cascades[0].cascadeSpace; - cascadeMatrix = cascadeIndex > 0 ? uniforms.light.shadow.cascades[1].cascadeSpace : cascadeMatrix; - cascadeMatrix = cascadeIndex > 1 ? uniforms.light.shadow.cascades[2].cascadeSpace : cascadeMatrix; - cascadeMatrix = cascadeIndex > 2 ? uniforms.light.shadow.cascades[3].cascadeSpace : cascadeMatrix; - cascadeMatrix = cascadeIndex > 3 ? uniforms.light.shadow.cascades[4].cascadeSpace : cascadeMatrix; - cascadeMatrix = cascadeIndex > 4 ? uniforms.light.shadow.cascades[5].cascadeSpace : cascadeMatrix; + float phaseFunction = uniforms.fogEnabled > 0 ? + ComputeScattering(uniforms.fog.scatteringAnisotropy, NdotL) : 1.0; + + lightScattering += shadowValue * phaseFunction * light.color.rgb * light.intensity * extinctionToLight; } - lastCascadeIndex = cascadeIndex; +#ifdef CLOUDS + vec3 planetCenter = uniforms.planetCenterAndRadius.xyz; + float cloudInnerRadius = uniforms.planetCenterAndRadius.w; - float positionLength = dist; - float positionRatio = positionLength / uniforms.light.shadow.distance; - vec3 shadowPosition = positionRatio <= 1.0 ? currentPosition : currentPosition / positionRatio; - vec4 cascadeSpace = cascadeMatrix * vec4(currentPosition, 1.0); - cascadeSpace.xyz /= cascadeSpace.w; + float distToPlanetCenter = distance(worldPosition, planetCenter); +#endif - cascadeSpace.xy = cascadeSpace.xy * 0.5 + 0.5; + float density = uniforms.fog.density * GetVolumetricFogDensity(uniforms.fog, worldPosition); + + vec3 scatteringCoefficient = uniforms.fog.scatteringFactor * + uniforms.fog.extinctionCoefficients.rgb * density; + vec4 extinctionCoefficient = uniforms.fog.extinctionFactor * + uniforms.fog.extinctionCoefficients * density; + + vec4 clampedExtinction = max(extinctionCoefficient, 0.0000001); + vec4 stepExtinction = exp(-extinctionCoefficient * stepLength); + + vec3 stepScattering = scatteringCoefficient * (lightScattering + vec3(uniforms.fog.ambientFactor) * lightAmbient); + + vec3 luminanceIntegral = (stepScattering - stepScattering * stepExtinction.rgb) / clampedExtinction.rgb; +#ifdef CLOUDS + foginess += luminanceIntegral * extinctionWithClouds.rgb; - float shadowValue = 1.0; -#ifdef SHADOWS -#ifdef AE_TEXTURE_SHADOW_LOD - // This fixes issues that can occur at cascade borders - shadowValue = textureLod(cascadeMaps, - vec4(cascadeSpace.xy, cascadeIndex, cascadeSpace.z), 0); + if (distToPlanetCenter > cloudInnerRadius && !receivedCloudExtinction) { + extinctionWithClouds *= uniforms.fogEnabled > 0 ? stepExtinction * cloudExtinction : vec4(1.0); + receivedCloudExtinction = true; + } + else { + extinctionWithClouds *= uniforms.fogEnabled > 0 ? stepExtinction : vec4(1.0); + } #else - shadowValue = texture(cascadeMaps, - vec4(cascadeSpace.xy, cascadeIndex, cascadeSpace.z)); + foginess += luminanceIntegral * extinction.rgb; #endif + + extinction *= uniforms.fogEnabled > 0 ? stepExtinction : vec4(1.0); + + currentPosition += stepVector; + + } + + return vec4(foginess * uniforms.intensity, extinction.a); + +} + +vec4 ComputeVolumetricPunctualLights(uint lightType, vec3 fragPos, float startDepth, vec2 texCoords) { + + vec2 resolution = vec2(imageSize(volumetricImage)); + vec3 viewPosition = vec3(globalData.ivMatrix * vec4(fragPos, 1.0)); + + // We compute this in view space + vec3 rayVector = fragPos; + float rayLength = clamp(length(rayVector) - startDepth, 0.0, 100.0); + vec3 rayDirection = normalize(rayVector); + float stepLength = rayLength / float(uniforms.sampleCount); + vec3 stepVector = rayDirection * stepLength; + + vec3 foginess = vec3(0.0); + vec4 extinction = vec4(1.0); + vec4 extinctionWithClouds = vec4(1.0); + + vec2 interleavedTexCoords = (0.5 * texCoords + 0.5) * resolution; + + float noiseOffset = GetInterleavedGradientNoise(interleavedTexCoords); + vec3 currentPosition = stepVector * (noiseOffset + startDepth); + +#ifdef CLOUDS + bool receivedCloudExtinction = false; + float cloudExtinction = min(textureLod(volumetricCloudTexture, texCoords, 0.0).a, 1.0); #endif - //shadowValue = dist > uniforms.light.shadow.distance ? 1.0 : shadowValue; + for (int i = 0; i < uniforms.sampleCount; i++) { + + float t0 = float(i) / float(uniforms.sampleCount); + float t1 = float(i + 1) / float(uniforms.sampleCount); + + t0 = t0 * t0; + t1 = t1 * t1; + + float delta = t1 - t0; + float t = t0 + delta * noiseOffset; + + //currentPosition = rayDirection * t * rayLength + startDepth; + //stepLength = delta * rayLength; + vec3 worldPosition = vec3(globalData.ivMatrix * vec4(currentPosition, 1.0)); + vec3 lightScattering = vec3(0.0); + + // Then all punctual lights + for(int j = 0; j < sharedLightIndicesCount; j++) { + int lightIdx = int(sharedLightIndices[j]); + VolumetricLight light = volumetricLights[lightIdx]; + + float NdotL = 1.0; + float attenuation = 1.0; + float sqrDistance = 1.0; + + float shadowValue = 1.0; + + float radius = light.direction.w; + if (lightType == POINT_LIGHT) { + vec3 pointToLight = light.location.xyz - currentPosition; + sqrDistance = max(0.0, dot(pointToLight, pointToLight)); + + attenuation = saturate(1.0 - pow(sqrDistance / (radius * radius), 4.0)); + if (attenuation == 0.0) + continue; + + NdotL = dot(-normalize(light.location.xyz), rayDirection); + shadowValue = GetShadowFactorPunctualLight(lightIdx, light.shadowIdx, POINT_LIGHT, false, currentPosition); + } + else if (lightType == SPOT_LIGHT) { + vec3 pointToLight = light.location.xyz - currentPosition; + sqrDistance = dot(pointToLight, pointToLight); + + vec3 L = pointToLight / sqrt(sqrDistance); + + float strength = dot(L, normalize(-light.direction.xyz)); + float angleAttenuation = saturate(strength * light.specific0 + light.specific1); + float distAttenuation = saturate(1.0 - pow(sqrDistance / (radius * radius), 4.0)); + if (angleAttenuation == 0.0 || distAttenuation == 0.0) + continue; + + NdotL = dot(-normalize(light.location.xyz), rayDirection); + attenuation = min(distAttenuation * sqr(angleAttenuation), 1.0); + shadowValue = GetShadowFactorPunctualLight(lightIdx, light.shadowIdx, SPOT_LIGHT, false, currentPosition); + } + + // No shadows for now + // shadowValue = 1.0; + + float phaseFunction = uniforms.fogEnabled > 0 ? + ComputeScattering(uniforms.fog.scatteringAnisotropy, NdotL) : 1.0; + + lightScattering += phaseFunction * shadowValue * light.color.rgb * attenuation * light.intensity / max(sqrDistance, 0.1); + } + #ifdef CLOUDS vec3 planetCenter = uniforms.planetCenterAndRadius.xyz; float cloudInnerRadius = uniforms.planetCenterAndRadius.w; @@ -163,12 +364,6 @@ vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { float distToPlanetCenter = distance(worldPosition, planetCenter); #endif -#ifdef CLOUD_SHADOWS - float cloudShadowValue = CalculateCloudShadow(currentPosition, uniforms.cloudShadow, cloudMap); - cloudShadowValue = distToPlanetCenter < cloudInnerRadius ? cloudShadowValue : 1.0; - shadowValue = min(shadowValue, cloudShadowValue); -#endif - float density = uniforms.fog.density * GetVolumetricFogDensity(uniforms.fog, worldPosition); vec3 scatteringCoefficient = uniforms.fog.scatteringFactor * @@ -176,15 +371,10 @@ vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { vec4 extinctionCoefficient = uniforms.fog.extinctionFactor * uniforms.fog.extinctionCoefficients * density; - float NdotL = dot(rayDirection, uniforms.light.direction.xyz); - vec4 clampedExtinction = max(extinctionCoefficient, 0.0000001); vec4 stepExtinction = exp(-extinctionCoefficient * stepLength); - float phaseFunction = uniforms.fogEnabled > 0 ? - ComputeScattering(uniforms.fog.scatteringAnisotropy, NdotL) : 1.0; - vec3 stepScattering = scatteringCoefficient * (shadowValue * phaseFunction * uniforms.light.color.rgb - + vec3(uniforms.fog.ambientFactor)); + vec3 stepScattering = scatteringCoefficient * lightScattering; vec3 luminanceIntegral = (stepScattering - stepScattering * stepExtinction.rgb) / clampedExtinction.rgb; #ifdef CLOUDS @@ -209,4 +399,124 @@ vec4 ComputeVolumetric(vec3 fragPos, float startDepth, vec2 texCoords) { return vec4(foginess * uniforms.intensity, extinction.a); +} + +float GetShadowFactorDirectionalLight(int lightIdx, int shadowIdx, uint lightType, bool isMain, vec3 currentPosition) { + + float dist = -currentPosition.z; + +#ifndef AE_BINDLESS + int mapIdx = lightIdx; +#else + int mapIdx = volumetricShadows[shadowIdx].mapIdx; +#endif + + if (shadowIdx < 0 || dist > volumetricShadows[shadowIdx].distance || mapIdx < 0) + return 1.0; + + float shadowValue = 1.0; + + + int cascadeIndex = 0; + cascadeIndex = dist >= volumetricShadows[shadowIdx].cascades[0].distance ? 1 : cascadeIndex; + cascadeIndex = dist >= volumetricShadows[shadowIdx].cascades[1].distance ? 2 : cascadeIndex; + cascadeIndex = dist >= volumetricShadows[shadowIdx].cascades[2].distance ? 3 : cascadeIndex; + cascadeIndex = dist >= volumetricShadows[shadowIdx].cascades[3].distance ? 4 : cascadeIndex; + cascadeIndex = dist >= volumetricShadows[shadowIdx].cascades[4].distance ? 5 : cascadeIndex; + + cascadeIndex = min(volumetricShadows[shadowIdx].cascadeCount - 1, cascadeIndex); + + mat3x4 cascadeMatrix = volumetricShadows[shadowIdx].cascades[0].cascadeSpace; + cascadeMatrix = cascadeIndex > 0 ? volumetricShadows[shadowIdx].cascades[1].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 1 ? volumetricShadows[shadowIdx].cascades[2].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 2 ? volumetricShadows[shadowIdx].cascades[3].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 3 ? volumetricShadows[shadowIdx].cascades[4].cascadeSpace : cascadeMatrix; + cascadeMatrix = cascadeIndex > 4 ? volumetricShadows[shadowIdx].cascades[5].cascadeSpace : cascadeMatrix; + + float positionLength = dist; + float positionRatio = positionLength / volumetricShadows[shadowIdx].distance; + vec3 shadowPosition = positionRatio <= 1.0 ? currentPosition : currentPosition / positionRatio; + vec4 cascadeSpace = mat4(transpose(cascadeMatrix)) * vec4(currentPosition, 1.0); + cascadeSpace.xyz /= cascadeSpace.w; + + cascadeSpace.xy = cascadeSpace.xy * 0.5 + 0.5; + +#ifdef AE_BINDLESS + shadowValue = texture(sampler2DArrayShadow(bindlessTextureArrays[nonuniformEXT(mapIdx)], shadowSampler), + vec4(cascadeSpace.xy, cascadeIndex, cascadeSpace.z)); +#else + shadowValue = texture(sampler2DArrayShadow(cascadeMaps[nonuniformEXT(mapIdx)], shadowSampler), + vec4(cascadeSpace.xy, cascadeIndex, cascadeSpace.z)); +#endif + + vec3 worldPosition = vec3(globalData.ivMatrix * vec4(currentPosition, 1.0)); + +#ifdef CLOUD_SHADOWS + if (isMain) { + vec3 planetCenter = uniforms.planetCenterAndRadius.xyz; + float cloudInnerRadius = uniforms.planetCenterAndRadius.w; + float distToPlanetCenter = distance(worldPosition, planetCenter); + float cloudShadowValue = CalculateCloudShadow(currentPosition, uniforms.cloudShadow, cloudMap); + cloudShadowValue = distToPlanetCenter < cloudInnerRadius ? cloudShadowValue : 1.0; + shadowValue = min(shadowValue, cloudShadowValue); + } +#endif + + return min(shadowValue, 1.0); + +} + +float GetShadowFactorPunctualLight(int lightIdx, int shadowIdx, uint lightType, bool isMain, vec3 currentPosition) { + + float dist = -currentPosition.z; + +#ifndef AE_BINDLESS + int mapIdx = lightIdx; +#else + int mapIdx = volumetricShadows[shadowIdx].mapIdx; +#endif + + if (shadowIdx < 0 || dist > volumetricShadows[shadowIdx].distance || mapIdx < 0) + return 1.0; + + float shadowValue = 1.0; + if (lightType == POINT_LIGHT) { +#ifdef AE_BINDLESS + mat4 projectionMatrix; + projectionMatrix[0] = volumetricShadows[shadowIdx].cascades[1].cascadeSpace[0]; + projectionMatrix[1] = volumetricShadows[shadowIdx].cascades[1].cascadeSpace[1]; + projectionMatrix[2] = volumetricShadows[shadowIdx].cascades[1].cascadeSpace[2]; + projectionMatrix[3] = volumetricShadows[shadowIdx].cascades[2].cascadeSpace[0]; + + vec4 shadowCoords = mat4(transpose(volumetricShadows[shadowIdx].cascades[0].cascadeSpace)) * vec4(currentPosition, 1.0); + shadowCoords.y *= -1.0; + vec4 absPosition = abs(shadowCoords); + float depth = -max(absPosition.x, max(absPosition.y, absPosition.z)); + vec4 clip = projectionMatrix * vec4(0.0, 0.0, depth, 1.0); + depth = clip.z / clip.w; + + shadowValue = clamp(texture(samplerCubeShadow(bindlessCubemaps[nonuniformEXT(mapIdx)], shadowSampler), + vec4(shadowCoords.xyz , depth - 0.0001)), 0.0, 1.0); +#endif + } + else if (lightType == SPOT_LIGHT) { +#ifdef AE_BINDLESS + mat4 shadowMatrix; + shadowMatrix[0] = volumetricShadows[shadowIdx].cascades[0].cascadeSpace[0]; + shadowMatrix[1] = volumetricShadows[shadowIdx].cascades[0].cascadeSpace[1]; + shadowMatrix[2] = volumetricShadows[shadowIdx].cascades[0].cascadeSpace[2]; + shadowMatrix[3] = volumetricShadows[shadowIdx].cascades[1].cascadeSpace[0]; + + vec4 cascadeSpace = shadowMatrix * vec4(currentPosition, 1.0); + cascadeSpace.xyz /= cascadeSpace.w; + + cascadeSpace.xy = cascadeSpace.xy * 0.5 + 0.5; + + shadowValue = texture(sampler2DArrayShadow(bindlessTextureArrays[nonuniformEXT(mapIdx)], shadowSampler), + vec4(cascadeSpace.xy, 0.0, cascadeSpace.z)); +#endif + } + + return min(shadowValue, 1.0); + } \ No newline at end of file diff --git a/data/shader/volumetric/volumetricResolve.csh b/data/shader/volumetric/volumetricResolve.csh index fd02e60f7..2ad542985 100644 --- a/data/shader/volumetric/volumetricResolve.csh +++ b/data/shader/volumetric/volumetricResolve.csh @@ -70,6 +70,13 @@ const ivec2 offsets[9] = ivec2[9]( ivec2(1, 1) ); +const ivec2 pixelOffsets[4] = ivec2[4]( + ivec2(0, 0), + ivec2(1, 0), + ivec2(0, 1), + ivec2(1, 1) +); + int NearestDepth(float referenceDepth, float[9] depthVec) { int idx = 4; @@ -88,14 +95,41 @@ int NearestDepth(float referenceDepth, float[9] depthVec) { void Upsample2x(float referenceDepth, vec2 texCoord, out vec4 volumetric, out vec4 volumetricClouds) { ivec2 pixel = ivec2(gl_LocalInvocationID) / 2 + ivec2(1); + vec2 highResPixel = texCoord * vec2(imageSize(resolveImage)); - float invocationDepths[9]; + highResPixel /= 2.0; - float minWeight = 1.0; + float x = fract(highResPixel.x); + float y = fract(highResPixel.y); + + float weights[4] = { (1 - x) * (1 - y), x * (1 - y), (1 - x) * y, x * y }; referenceDepth = ConvertDepthToViewSpaceDepth(referenceDepth); float depthPhi = 128.0 / max(1.0, abs(referenceDepth)); + volumetric = vec4(0.0); + + float totalWeight = 0.0; + for (uint i = 0; i < 4; i++) { + int sharedMemoryOffset = Flatten2D(pixel + pixelOffsets[i], unflattenedDepthDataSize); + + float depth = ConvertDepthToViewSpaceDepth(depths[sharedMemoryOffset]); + + float depthDiff = abs(referenceDepth - depth); + float depthWeight = min(exp(-depthDiff * depthPhi), 1.0); + + float edgeWeight = depthWeight; + float weight = edgeWeight * weights[i]; + + volumetric += volumetrics[sharedMemoryOffset] * weight; + totalWeight += weight; + } + + volumetric /= totalWeight; + + float invocationDepths[9]; + + float minWeight = 1.0; for (uint i = 0; i < 9; i++) { int sharedMemoryOffset = Flatten2D(pixel + offsets[i], unflattenedDepthDataSize); @@ -112,7 +146,9 @@ void Upsample2x(float referenceDepth, vec2 texCoord, out vec4 volumetric, out ve int idx = NearestDepth(referenceDepth, invocationDepths); int offset = Flatten2D(pixel + offsets[idx], unflattenedDepthDataSize); - volumetric = volumetrics[offset]; + if (totalWeight < 10e-9) { + volumetric = volumetrics[offset]; + } #ifdef CLOUDS vec4 bilinearCloudScattering = texture(lowResVolumetricCloudsTexture, texCoord); volumetricClouds = mix(clouds[offset], bilinearCloudScattering, minWeight); diff --git a/libs/ImguiExtension/panels/FogPanel.cpp b/libs/ImguiExtension/panels/FogPanel.cpp index 3598cadfb..fefa1f27c 100644 --- a/libs/ImguiExtension/panels/FogPanel.cpp +++ b/libs/ImguiExtension/panels/FogPanel.cpp @@ -22,6 +22,7 @@ namespace Atlas::ImguiExtension { "%.3f", ImGuiSliderFlags_Logarithmic); ImGui::Text("Volumetric"); ImGui::Checkbox("Raymarching", &fog->rayMarching); + ImGui::Checkbox("Local lights", &fog->localLights); ImGui::DragInt("Raymarch step count", &fog->rayMarchStepCount, 1, 128); ImGui::SliderFloat("Intensity", &fog->volumetricIntensity, 0.0f, 1.0f); diff --git a/libs/ImguiExtension/panels/GPUProfilerPanel.h b/libs/ImguiExtension/panels/GPUProfilerPanel.h index b7a2ceb42..9e23e9941 100644 --- a/libs/ImguiExtension/panels/GPUProfilerPanel.h +++ b/libs/ImguiExtension/panels/GPUProfilerPanel.h @@ -15,7 +15,6 @@ namespace Atlas::ImguiExtension { void Render(); - private: void RenderTable(); void RenderGraph(); diff --git a/libs/ImguiExtension/panels/ReflectionPanel.cpp b/libs/ImguiExtension/panels/ReflectionPanel.cpp index 5b0b4f7bb..5df2dd941 100644 --- a/libs/ImguiExtension/panels/ReflectionPanel.cpp +++ b/libs/ImguiExtension/panels/ReflectionPanel.cpp @@ -28,7 +28,7 @@ namespace Atlas::ImguiExtension { ImGui::SliderFloat("Roughness cuttoff", &reflection->roughnessCutoff, 0.0f, 1.0f); ImGui::SliderInt("Texture level##Reflection", &reflection->textureLevel, 0, 10); ImGui::SliderInt("Sample count##Reflection", &reflection->sampleCount, 1, 10); - ImGui::SliderInt("Light sample count##Reflection", &reflection->lightSampleCount, 0, 10); + ImGui::SliderInt("Light sample count##Reflection", &reflection->lightSampleCount, 1, 10); ImGui::Text("Denoiser"); ImGui::SliderFloat("Spatial filter strength", &reflection->spatialFilterStrength, 0.0f, 10.0f); ImGui::SliderFloat("Temporal weight", &reflection->temporalWeight, 0.0f, 1.0f); diff --git a/src/demo/App.cpp b/src/demo/App.cpp index b040f906f..e37376ec1 100644 --- a/src/demo/App.cpp +++ b/src/demo/App.cpp @@ -218,6 +218,18 @@ void App::Update(float deltaTime) { auto& rigidBodyComponent = entity.AddComponent(bodySettings); rigidBodyComponent.SetRestitution(sphereRestitution); + if (attachLightToSphers) { + auto& lightComponent = entity.AddComponent(Atlas::LightType::PointLight); + + lightComponent.color.r = Atlas::Common::Random::SampleUniformFloat(); + lightComponent.color.g = Atlas::Common::Random::SampleUniformFloat(); + lightComponent.color.b = Atlas::Common::Random::SampleUniformFloat(); + + lightComponent.intensity = 30.0f; + + lightComponent.properties.point.radius = 5.0f; + } + entities.push_back(entity); lastSpawn = Atlas::Clock::Get(); } @@ -250,6 +262,18 @@ void App::Update(float deltaTime) { }; entity.AddComponent(bodySettings); + if (attachLightToSphers) { + auto& lightComponent = entity.AddComponent(Atlas::LightType::PointLight); + + lightComponent.color.r = Atlas::Common::Random::SampleUniformFloat(); + lightComponent.color.g = Atlas::Common::Random::SampleUniformFloat(); + lightComponent.color.b = Atlas::Common::Random::SampleUniformFloat(); + + lightComponent.intensity = 30.0f; + + lightComponent.properties.point.radius = 5.0f; + } + entities.push_back(entity); lastSpawn = Atlas::Clock::Get(); } @@ -267,7 +291,7 @@ void App::Render(float deltaTime) { static bool firstFrame = true; static bool animateLight = false; - static bool pathTrace = true; + static bool pathTrace = false; static bool debugAo = false; static bool debugReflection = false; static bool debugClouds = false; @@ -588,6 +612,7 @@ void App::Render(float deltaTime) { ImGui::SliderFloat("Sphere scale##PhysicsBody", &sphereScale, 1.0f, 10.0f); ImGui::SliderFloat("Sphere density##PhysicsBody", &sphereDensity, 1.0f, 100.0f); ImGui::SliderFloat("Sphere restitution##PhysicsBody", &sphereRestitution, 0.0f, 1.0f); + ImGui::Checkbox("Attach lights ##PhysicsBody", &attachLightToSphers); ImGui::Text("Sphere emitter"); ImGui::Checkbox("Enable##PhysicsEmitter", &emitSpheresEnabled); ImGui::SliderFloat("Spawn rate##PhysicsEmitter", &emitSpawnRate, 0.001f, 1.0f); diff --git a/src/demo/App.h b/src/demo/App.h index 502d8df59..3f730dbaf 100644 --- a/src/demo/App.h +++ b/src/demo/App.h @@ -113,8 +113,10 @@ class App : public Atlas::EngineInstance { float sphereDensity = 1.0f; float sphereRestitution = 0.2f; - bool emitSpheresEnabled = false; - float emitSpawnRate = 0.1f; + bool emitSpheresEnabled = true; + float emitSpawnRate = 0.01f; + + bool attachLightToSphers = true; bool shootSpheresEnabled = false; bool shootSphere = false; diff --git a/src/editor/tools/CopyPasteHelper.h b/src/editor/tools/CopyPasteHelper.h index f1e4dd93d..610bea178 100644 --- a/src/editor/tools/CopyPasteHelper.h +++ b/src/editor/tools/CopyPasteHelper.h @@ -84,6 +84,7 @@ namespace Atlas::Editor { T* typeData = static_cast(data); for (size_t i = 0; i < elementCount; i++) { + new (&typeData[i])T(); typeData[i] = source[i]; } diff --git a/src/editor/tools/ResourcePayloadHelper.h b/src/editor/tools/ResourcePayloadHelper.h index ac8a5686d..7e2f9aa5b 100644 --- a/src/editor/tools/ResourcePayloadHelper.h +++ b/src/editor/tools/ResourcePayloadHelper.h @@ -28,6 +28,7 @@ namespace Atlas::Editor { } if (compatible && ImGui::AcceptDragDropPayload("ContentBrowserResource")) { + Log::Warning("Valid file"); handle = FileImporter::ImportFile(resourcePath); } diff --git a/src/editor/ui/panels/SceneHierarchyPanel.cpp b/src/editor/ui/panels/SceneHierarchyPanel.cpp index 0c127a5f8..a665cb8f9 100644 --- a/src/editor/ui/panels/SceneHierarchyPanel.cpp +++ b/src/editor/ui/panels/SceneHierarchyPanel.cpp @@ -61,12 +61,15 @@ namespace Atlas::Editor::UI { ImGui::EndPopup(); } + std::string prevEntitySearch = entitySearch; ImGui::InputTextWithHint("Search", "Type to search for entity", &entitySearch); + + bool searchChanged = entitySearch != prevEntitySearch; if (ImGui::IsItemClicked()) selectionChanged = true; JobSystem::Wait(searchJob); - TraverseHierarchy(scene, root, matchSet, inFocus, &selectionChanged); + TraverseHierarchy(scene, root, matchSet, inFocus, searchChanged, &selectionChanged); RenderExtendedHierarchy(scene, &selectionChanged); @@ -79,7 +82,7 @@ namespace Atlas::Editor::UI { #endif if (inFocus && controlDown && ImGui::IsKeyPressed(ImGuiKey_D, false)) DuplicateSelectedEntity(scene); - if (inFocus && ImGui::IsKeyPressed(ImGuiKey_Delete, false)) + if (inFocus && controlDown && ImGui::IsKeyPressed(ImGuiKey_Delete, false)) DeleteSelectedEntity(scene); if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !selectionChanged) { @@ -95,7 +98,7 @@ namespace Atlas::Editor::UI { } void SceneHierarchyPanel::TraverseHierarchy(Ref& scene, Scene::Entity entity, - std::unordered_set& matchSet, bool inFocus, bool* selectionChanged) { + std::unordered_set& matchSet, bool inFocus, bool searchChanged, bool* selectionChanged) { ImGuiTreeNodeFlags baseFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; @@ -118,6 +121,11 @@ namespace Atlas::Editor::UI { if (!rootNode && !validSearch) return; + if (matchSet.contains(entity) && !entitySearch.empty() && searchChanged) + ImGui::SetNextItemOpen(true, ImGuiCond_Always); + else if (entitySearch.empty() && searchChanged || !matchSet.contains(entity) && searchChanged) + ImGui::SetNextItemOpen(false, ImGuiCond_Always); + auto nodeFlags = baseFlags; nodeFlags |= entity == selectedEntity ? ImGuiTreeNodeFlags_Selected : 0; auto entityId = static_cast(entity); @@ -171,7 +179,7 @@ namespace Atlas::Editor::UI { auto children = hierarchyComponent->GetChildren(); for (auto childEntity : children) { - TraverseHierarchy(scene, childEntity, matchSet, inFocus, selectionChanged); + TraverseHierarchy(scene, childEntity, matchSet, inFocus, searchChanged, selectionChanged); } diff --git a/src/editor/ui/panels/SceneHierarchyPanel.h b/src/editor/ui/panels/SceneHierarchyPanel.h index 9d66de77f..a0d3db3fa 100644 --- a/src/editor/ui/panels/SceneHierarchyPanel.h +++ b/src/editor/ui/panels/SceneHierarchyPanel.h @@ -35,7 +35,7 @@ namespace Atlas::Editor::UI { private: void TraverseHierarchy(Ref& scene, Scene::Entity entity, - std::unordered_set& matchSet, bool inFocus, bool* selectionChanged); + std::unordered_set& matchSet, bool inFocus, bool searchChanged, bool* selectionChanged); void RenderExtendedHierarchy(const Ref& scene, bool* selectionChanged); diff --git a/src/editor/ui/panels/SceneStatisticsPanel.cpp b/src/editor/ui/panels/SceneStatisticsPanel.cpp index 4d40da6ab..27551237e 100644 --- a/src/editor/ui/panels/SceneStatisticsPanel.cpp +++ b/src/editor/ui/panels/SceneStatisticsPanel.cpp @@ -23,6 +23,7 @@ namespace Atlas::Editor::UI { auto materials = scene->GetMaterials(); auto lightCount = scene->GetComponentCount(); + auto meshInstanceCount = scene->GetComponentCount(); ImGui::SeparatorText("Dimensions"); ImGui::Text("Min: %.2f, %.2f, %.2f", min.x, min.y, min.z); @@ -34,6 +35,7 @@ namespace Atlas::Editor::UI { ImGui::Text("Mesh count: %d", int32_t(meshes.size())); ImGui::Text("Material count: %d", int32_t(materials.size())); ImGui::Text("Light count: %d", int32_t(lightCount)); + ImGui::Text("Mesh instance count: %d", int32_t(meshInstanceCount)); ImGui::Text("Physics body count: %d", scene->physicsWorld->GetBodyCount()); } diff --git a/src/editor/ui/panels/components/CameraComponentPanel.cpp b/src/editor/ui/panels/components/CameraComponentPanel.cpp index dda85c129..2fd7d12c7 100644 --- a/src/editor/ui/panels/components/CameraComponentPanel.cpp +++ b/src/editor/ui/panels/components/CameraComponentPanel.cpp @@ -17,6 +17,8 @@ namespace Atlas::Editor::UI { ImGui::Checkbox("Third person", &cameraComponent.thirdPerson); ImGui::DragFloat("Third person distance", &cameraComponent.thirdPersonDistance, 0.1f, 0.0f, 100.0f); + ImGui::Checkbox("Main", &cameraComponent.isMain); + ImGui::Text("Lens properties"); ImGui::DragFloat("Field of view", &cameraComponent.fieldOfView, 0.1f, 1.0f, 180.0f); @@ -25,7 +27,7 @@ namespace Atlas::Editor::UI { ImGui::DragFloat("Near plane", &cameraComponent.nearPlane, 0.01f, 0.01f, 10.0f); ImGui::DragFloat("Far plane", &cameraComponent.farPlane, 1.0f, 1.0f, 2000.0f); - ImGui::Checkbox("Main", &cameraComponent.isMain); + ImGui::DragFloat("Exposure", &cameraComponent.exposure, 0.01f, 0.01f, 100.0f), ImGui::PopID(); diff --git a/src/editor/ui/panels/components/LightComponentPanel.cpp b/src/editor/ui/panels/components/LightComponentPanel.cpp index 21d57d056..c898bab97 100644 --- a/src/editor/ui/panels/components/LightComponentPanel.cpp +++ b/src/editor/ui/panels/components/LightComponentPanel.cpp @@ -49,6 +49,7 @@ namespace Atlas::Editor::UI { ImGui::Checkbox("Shadow", &castShadow); ImGui::ColorEdit3("Color", &lightComponent.color[0]); ImGui::DragFloat("Intensity", &lightComponent.intensity, 0.1f, 0.0f, 1000.0f); + ImGui::DragFloat("Volumetric intensity", &lightComponent.volumetricIntensity, 0.1f, 0.0f, 10.0f); if (!lightComponent.shadow && castShadow) { if (lightComponent.type == LightType::DirectionalLight) { diff --git a/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp b/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp index 2930a9b16..9e9f3f87a 100644 --- a/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp +++ b/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp @@ -52,6 +52,12 @@ namespace Atlas::Editor::UI case LuaScriptComponent::PropertyType::String: ImGui::InputText(name.c_str(), &property.stringValue); break; + case LuaScriptComponent::PropertyType::Vec2: + ImGui::DragFloat2(name.c_str(), glm::value_ptr(property.vec2Value)); + break; + case LuaScriptComponent::PropertyType::Vec3: + ImGui::DragFloat3(name.c_str(), glm::value_ptr(property.vec3Value)); + break; case LuaScriptComponent::PropertyType::Undefined: break; } diff --git a/src/editor/ui/panels/components/MeshComponentPanel.cpp b/src/editor/ui/panels/components/MeshComponentPanel.cpp index 9e767c85c..f9d482bdd 100644 --- a/src/editor/ui/panels/components/MeshComponentPanel.cpp +++ b/src/editor/ui/panels/components/MeshComponentPanel.cpp @@ -64,6 +64,7 @@ namespace Atlas::Editor::UI { mesh->UpdatePipelines(); } + meshSelectionPanel.Reset(); materialSelectionPanel.Reset(); textureSelectionPanel.Reset(); diff --git a/src/editor/ui/windows/ContentBrowserWindow.cpp b/src/editor/ui/windows/ContentBrowserWindow.cpp index a44f207a2..b4624d0b2 100644 --- a/src/editor/ui/windows/ContentBrowserWindow.cpp +++ b/src/editor/ui/windows/ContentBrowserWindow.cpp @@ -316,7 +316,7 @@ namespace Atlas::Editor::UI { ImGui::BeginGroup(); - ImGui::PushID(path.c_str()); + ImGui::PushID(entryIdx); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 939017d17..7ad49ba42 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -118,6 +118,8 @@ namespace Atlas { Clock::Update(); Graphics::Profiler::BeginFrame(); + // First reset keyboard state before new events + Input::KeyboardMap::Update(); Events::EventManager::Update(); PipelineManager::Update(); Audio::AudioManager::Update(); diff --git a/src/engine/graphics/Buffer.cpp b/src/engine/graphics/Buffer.cpp index f93c85512..09fed833b 100644 --- a/src/engine/graphics/Buffer.cpp +++ b/src/engine/graphics/Buffer.cpp @@ -28,7 +28,7 @@ namespace Atlas { } if (desc.priority == 1.0f) - allocationCreateInfo.pool = memoryManager->hightPriorityBufferPool; + allocationCreateInfo.pool = memoryManager->highPriorityMemoryPool; if (desc.dedicatedMemory) allocationCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; diff --git a/src/engine/graphics/Image.cpp b/src/engine/graphics/Image.cpp index 32d9744e1..9fb083fda 100644 --- a/src/engine/graphics/Image.cpp +++ b/src/engine/graphics/Image.cpp @@ -39,7 +39,9 @@ namespace Atlas { VMA_MEMORY_USAGE_AUTO; // Seems to be faster to just use that pool everywhere for all images. // My guess is it is actually faster since the memory doesn't change constantly (not many new allocations) - allocationCreateInfo.pool = memoryManager->hightPriorityBufferPool; + + if (desc.dedicatedMemoryPool != nullptr) + allocationCreateInfo.pool = *desc.dedicatedMemoryPool; VK_CHECK(vmaCreateImage(memoryManager->allocator, &imageInfo, &allocationCreateInfo, &image, &allocation, nullptr)) diff --git a/src/engine/graphics/Image.h b/src/engine/graphics/Image.h index 21a9c7941..0f95a17bf 100644 --- a/src/engine/graphics/Image.h +++ b/src/engine/graphics/Image.h @@ -43,7 +43,7 @@ namespace Atlas { void* data = nullptr; - bool dedicatedMemory = false; + VmaPool* dedicatedMemoryPool = nullptr; }; struct ImageAllocation { diff --git a/src/engine/graphics/MemoryManager.cpp b/src/engine/graphics/MemoryManager.cpp index 7e7bafcd1..df3f5367c 100644 --- a/src/engine/graphics/MemoryManager.cpp +++ b/src/engine/graphics/MemoryManager.cpp @@ -46,8 +46,19 @@ namespace Atlas { VmaPoolCreateInfo poolCreateInfo = {}; poolCreateInfo.memoryTypeIndex = memTypeIndex; + VK_CHECK(vmaCreatePool(allocator, &poolCreateInfo, &highPriorityMemoryPool)); - VK_CHECK(vmaCreatePool(allocator, &poolCreateInfo, &hightPriorityBufferPool)); + VkExtent3D imageExtent{ 1, 1, 1 }; + VkImageCreateInfo imageCreateInfo = Initializers::InitImageCreateInfo(VK_FORMAT_R16_SFLOAT, 0, imageExtent); + imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + res = vmaFindMemoryTypeIndexForImageInfo(allocator, &imageCreateInfo, + &sampleAllocCreateInfo, &memTypeIndex); + + poolCreateInfo.memoryTypeIndex = memTypeIndex; + VK_CHECK(vmaCreatePool(allocator, &poolCreateInfo, &highPriorityRenderTargetPool)); vkGetPhysicalDeviceProperties(device->physicalDevice, &deviceProperties); @@ -61,7 +72,8 @@ namespace Atlas { DestroyAllImmediate(); - vmaDestroyPool(allocator, hightPriorityBufferPool); + vmaDestroyPool(allocator, highPriorityMemoryPool); + vmaDestroyPool(allocator, highPriorityRenderTargetPool); vmaDestroyAllocator(allocator); } diff --git a/src/engine/graphics/MemoryManager.h b/src/engine/graphics/MemoryManager.h index 3a112c0b6..cbc227967 100644 --- a/src/engine/graphics/MemoryManager.h +++ b/src/engine/graphics/MemoryManager.h @@ -87,7 +87,8 @@ namespace Atlas { void DestroyAllImmediate(); VmaAllocator allocator; - VmaPool hightPriorityBufferPool; + VmaPool highPriorityMemoryPool; + VmaPool highPriorityRenderTargetPool; VkPhysicalDeviceProperties deviceProperties; diff --git a/src/engine/input/KeyboardMap.cpp b/src/engine/input/KeyboardMap.cpp index 300ed284b..0133670e8 100644 --- a/src/engine/input/KeyboardMap.cpp +++ b/src/engine/input/KeyboardMap.cpp @@ -14,6 +14,13 @@ namespace Atlas::Input { + } + + void KeyboardMap::Update() { + + for (auto& [keyCode, state] : keyMap) + state.repeat = true; + } uint8_t KeyboardMap::GetKeyState(Keycode code) { diff --git a/src/engine/input/KeyboardMap.h b/src/engine/input/KeyboardMap.h index 263d7c25f..91f438a34 100644 --- a/src/engine/input/KeyboardMap.h +++ b/src/engine/input/KeyboardMap.h @@ -13,6 +13,8 @@ namespace Atlas::Input { static void Shutdown(); + static void Update(); + static uint8_t GetKeyState(Keycode keyCode); static bool IsKeyPressed(Keycode keyCode, bool repeat = true); diff --git a/src/engine/lighting/Fog.h b/src/engine/lighting/Fog.h index df6df75ed..9861b7b23 100644 --- a/src/engine/lighting/Fog.h +++ b/src/engine/lighting/Fog.h @@ -27,6 +27,7 @@ namespace Atlas { float ambientFactor = 0.01f; bool rayMarching = true; + bool localLights = false; int32_t rayMarchStepCount = 10; float volumetricIntensity = 1.0f; diff --git a/src/engine/lighting/IrradianceVolume.cpp b/src/engine/lighting/IrradianceVolume.cpp index 621926e94..259404c76 100644 --- a/src/engine/lighting/IrradianceVolume.cpp +++ b/src/engine/lighting/IrradianceVolume.cpp @@ -143,16 +143,16 @@ namespace Atlas { probeCount.x * probeCount.y * probeCount.z * cascadeCount); irradianceArray0 = Texture::Texture2DArray(irrRes.x, irrRes.y, probeCount.y * cascadeCount, - VK_FORMAT_A2B10G10R10_UNORM_PACK32, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_A2B10G10R10_UNORM_PACK32, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); momentsArray0 = Texture::Texture2DArray(momRes.x, momRes.y, probeCount.y * cascadeCount, - VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); irradianceArray1 = Texture::Texture2DArray(irrRes.x, irrRes.y, probeCount.y * cascadeCount, - VK_FORMAT_A2B10G10R10_UNORM_PACK32, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_A2B10G10R10_UNORM_PACK32, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); momentsArray1 = Texture::Texture2DArray(momRes.x, momRes.y, probeCount.y * cascadeCount, - VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); probeDebugMaterial = CreateRef(); probeDebugActiveMaterial = CreateRef(); diff --git a/src/engine/lighting/LightingSerializer.cpp b/src/engine/lighting/LightingSerializer.cpp index 44e877cce..c165d38b1 100644 --- a/src/engine/lighting/LightingSerializer.cpp +++ b/src/engine/lighting/LightingSerializer.cpp @@ -80,6 +80,7 @@ namespace Atlas::Lighting { {"heightFalloff", p.heightFalloff}, {"scatteringAnisotropy", p.scatteringAnisotropy}, {"rayMarching", p.rayMarching}, + {"localLights", p.localLights}, {"rayMarchStepCount", p.rayMarchStepCount}, {"volumetricIntensity", p.volumetricIntensity}, }; @@ -98,6 +99,8 @@ namespace Atlas::Lighting { j.at("rayMarching").get_to(p.rayMarching); j.at("rayMarchStepCount").get_to(p.rayMarchStepCount); j.at("volumetricIntensity").get_to(p.volumetricIntensity); + + try_get_json(j, "localLights", p.localLights); } void to_json(json& j, const IrradianceVolume& p) { @@ -158,7 +161,9 @@ namespace Atlas::Lighting { {"useShadowMap", p.useShadowMap}, {"useNormalMaps", p.useNormalMaps}, {"opacityCheck", p.opacityCheck}, - {"halfResolution", p.halfResolution} + {"halfResolution", p.halfResolution}, + {"lightSampleCount", p.lightSampleCount}, + {"sampleCount", p.sampleCount}, }; } @@ -178,6 +183,8 @@ namespace Atlas::Lighting { j.at("opacityCheck").get_to(p.opacityCheck); try_get_json(j, "halfResolution", p.halfResolution); try_get_json(j, "roughnessCutoff", p.roughnessCutoff); + try_get_json(j, "lightSampleCount", p.lightSampleCount); + try_get_json(j, "sampleCount", p.sampleCount); } void to_json(json& j, const RTGI& p) { @@ -194,7 +201,9 @@ namespace Atlas::Lighting { {"useShadowMap", p.useShadowMap}, {"useNormalMap", p.useNormalMaps}, {"opacityCheck", p.opacityCheck}, - {"halfResolution", p.halfResolution} + {"halfResolution", p.halfResolution}, + {"lightSampleCount", p.lightSampleCount}, + {"sampleCount", p.sampleCount}, }; } @@ -212,6 +221,8 @@ namespace Atlas::Lighting { j.at("useNormalMap").get_to(p.useNormalMaps); j.at("opacityCheck").get_to(p.opacityCheck); try_get_json(j, "halfResolution", p.halfResolution); + try_get_json(j, "lightSampleCount", p.lightSampleCount); + try_get_json(j, "sampleCount", p.sampleCount); } void to_json(json& j, const ShadowView& p) { diff --git a/src/engine/loader/AssetLoader.cpp b/src/engine/loader/AssetLoader.cpp index d3e875e55..890335845 100644 --- a/src/engine/loader/AssetLoader.cpp +++ b/src/engine/loader/AssetLoader.cpp @@ -171,14 +171,15 @@ namespace Atlas { const int32_t tryCount = 2; + auto fileTime = defaultTime; for (int32_t i = 0; i < tryCount; i++) { try { - return std::filesystem::last_write_time(GetFullPath(path)); + fileTime = std::filesystem::last_write_time(GetFullPath(path)); } catch (...) {} } - return defaultTime; + return fileTime; } diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index 8018a5393..c046148c7 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -104,6 +104,7 @@ namespace Atlas { } + auto radius = 0.0f; auto min = vec3(std::numeric_limits::max()); auto max = vec3(-std::numeric_limits::max()); @@ -159,6 +160,7 @@ namespace Atlas { max = glm::max(vertex, max); min = glm::min(vertex, min); + radius = glm::dot(vertex, vertex); vec3 normal = vec3(matrix * vec4(mesh->mNormals[j].x, mesh->mNormals[j].y, mesh->mNormals[j].z, 0.0f)); @@ -218,7 +220,8 @@ namespace Atlas { state.importer.FreeScene(); meshData.aabb = Volume::AABB(min, max); - meshData.radius = glm::length(max - min) * 0.5; + meshData.radius = glm::sqrt(radius); + meshData.name = Common::Path::GetFileNameWithoutExtension(filename); @@ -311,6 +314,7 @@ namespace Atlas { } meshData.materials.push_back(material); + auto radius = 0.0f; auto min = vec3(std::numeric_limits::max()); auto max = vec3(-std::numeric_limits::max()); @@ -324,6 +328,7 @@ namespace Atlas { max = glm::max(vertex, max); min = glm::min(vertex, min); + radius = glm::dot(vertex, vertex); vec3 normal = vec3(assimpMesh->mNormals[j].x, assimpMesh->mNormals[j].y, assimpMesh->mNormals[j].z); @@ -374,7 +379,7 @@ namespace Atlas { } meshData.aabb = Volume::AABB(min, max); - meshData.radius = glm::length(max - min) * 0.5; + meshData.radius = glm::sqrt(radius); meshData.subData.push_back({ .indicesOffset = 0, diff --git a/src/engine/mesh/MeshSerializer.cpp b/src/engine/mesh/MeshSerializer.cpp index 3d3dad9e5..548407575 100644 --- a/src/engine/mesh/MeshSerializer.cpp +++ b/src/engine/mesh/MeshSerializer.cpp @@ -239,15 +239,15 @@ namespace Atlas { try_get_json(j, "uvAnimation", p.uvAnimation); - auto getTextureHandle = [](const std::string& path, bool colorSpaceConversion) -> auto { + auto getTextureHandle = [](const std::string& path, bool colorSpaceConversion, bool priority = false) -> auto { return ResourceManager::GetOrLoadResource(path, colorSpaceConversion, - Texture::Wrapping::Repeat, Texture::Filtering::Anisotropic, 0); + Texture::Wrapping::Repeat, Texture::Filtering::Anisotropic, 0, false, priority); }; if (j.contains("baseColorMapPath")) p.baseColorMap = getTextureHandle(j["baseColorMapPath"], false); if (j.contains("opacityMapPath")) - p.opacityMap = getTextureHandle(j["opacityMapPath"], false); + p.opacityMap = getTextureHandle(j["opacityMapPath"], false, true); if (j.contains("normalMapPath")) p.normalMap = getTextureHandle(j["normalMapPath"], false); if (j.contains("roughnessMapPath")) diff --git a/src/engine/physics/Player.cpp b/src/engine/physics/Player.cpp index e7b1473be..55f0ee291 100644 --- a/src/engine/physics/Player.cpp +++ b/src/engine/physics/Player.cpp @@ -21,8 +21,9 @@ namespace Atlas::Physics { settings.mMaxConstraintIterations = 10; settings.mShapeOffset = VecToJPHVec(shapeOffset); settings.mShape = shape->ref; - //settings.mInnerBodyShape = shape->ref; - //settings.mInnerBodyLayer = Layers::Movable; + settings.mInnerBodyShape = shape->ref; + settings.mInnerBodyLayer = Layers::Movable; + settings.mCharacterPadding = shapePadding; if (shape->type == ShapeType::Capsule) { auto shapeSettings = static_cast(shape->settings.get()); @@ -148,7 +149,7 @@ namespace Atlas::Physics { auto gravityVector = -GetUp() * glm::length(world->GetGravity()); - //character->SetEnhancedInternalEdgeRemoval(true); + character->SetEnhancedInternalEdgeRemoval(true); JPH::CharacterVirtual::ExtendedUpdateSettings settings; diff --git a/src/engine/renderer/DDGIRenderer.cpp b/src/engine/renderer/DDGIRenderer.cpp index e56f6a6ee..1b8dda19c 100644 --- a/src/engine/renderer/DDGIRenderer.cpp +++ b/src/engine/renderer/DDGIRenderer.cpp @@ -150,8 +150,8 @@ namespace Atlas { auto texelSize = glm::max(abs(corners[0].x - corners[1].x), abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; shadowUniform.cascades[i].distance = cascade->farDistance; - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix; + shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * + cascade->viewMatrix); shadowUniform.cascades[i].texelSize = texelSize; } else { auto cascade = &shadow->views[componentCount - 1]; diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index d94bf2e19..21b6e2ac2 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -76,21 +76,20 @@ namespace Atlas { pushConstants.lightCount = std::min(4096, int32_t(renderState->lightEntities.size())); pushConstants.lightBucketCount = int32_t(std::ceil(float(pushConstants.lightCount) / 32.0f)); #else + pushConstants.lightCount = std::min(8, int32_t(renderState->lightEntities.size())); + pushConstants.lightBucketCount = 1; + std::vector> cascadeMaps; std::vector> cubeMaps; - - pushConstants.lightCount = std::min(8, int32_t(renderState->lightEntities.size())); for (int32_t i = 0; i < pushConstants.lightCount; i++) { auto& comp = renderState->lightEntities[i].comp; if (comp.shadow) { auto& shadow = comp.shadow; if (shadow->useCubemap) { - pushConstants.mapIndices[i] = int32_t(cubeMaps.size()); cubeMaps.push_back(shadow->cubemap->image); } else { - pushConstants.mapIndices[i] = int32_t(cascadeMaps.size()); cascadeMaps.push_back(shadow->maps->image); } } diff --git a/src/engine/renderer/DirectLightRenderer.h b/src/engine/renderer/DirectLightRenderer.h index 3cac24ea9..d5dde85c0 100644 --- a/src/engine/renderer/DirectLightRenderer.h +++ b/src/engine/renderer/DirectLightRenderer.h @@ -26,7 +26,6 @@ namespace Atlas { int32_t lightBucketCount; int32_t padding1; int32_t padding2; - int32_t mapIndices[16]; }; PipelineConfig pipelineConfig; diff --git a/src/engine/renderer/OceanRenderer.cpp b/src/engine/renderer/OceanRenderer.cpp index 69c2fc3bc..a55dc7ad5 100644 --- a/src/engine/renderer/OceanRenderer.cpp +++ b/src/engine/renderer/OceanRenderer.cpp @@ -92,8 +92,8 @@ namespace Atlas { auto texelSize = glm::max(abs(corners[0].x - corners[1].x), abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; shadowUniform.cascades[i].distance = cascade->farDistance; - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix; + shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * + cascade->viewMatrix * camera.invViewMatrix); shadowUniform.cascades[i].texelSize = texelSize; } else { diff --git a/src/engine/renderer/PathTracingRenderer.cpp b/src/engine/renderer/PathTracingRenderer.cpp index df77d5fbb..ef35e42c8 100644 --- a/src/engine/renderer/PathTracingRenderer.cpp +++ b/src/engine/renderer/PathTracingRenderer.cpp @@ -18,6 +18,8 @@ namespace Atlas { this->device = device; + // helper.stochasticLightSelection = true; + rayGenPipelineConfig = PipelineConfig("pathtracer/rayGen.csh"); rayHitPipelineConfig = PipelineConfig("pathtracer/rayHit.csh"); diff --git a/src/engine/renderer/RTGIRenderer.cpp b/src/engine/renderer/RTGIRenderer.cpp index c0ca05810..092b0c969 100644 --- a/src/engine/renderer/RTGIRenderer.cpp +++ b/src/engine/renderer/RTGIRenderer.cpp @@ -161,8 +161,8 @@ namespace Atlas { auto texelSize = glm::max(abs(corners[0].x - corners[1].x), abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; shadowUniform.cascades[i].distance = cascade->farDistance; - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix; + shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * + cascade->viewMatrix); shadowUniform.cascades[i].texelSize = texelSize; } else { diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index e04afe1ac..d4d1a4eff 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -156,8 +156,8 @@ namespace Atlas { auto texelSize = glm::max(abs(corners[0].x - corners[1].x), abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; shadowUniform.cascades[i].distance = cascade->farDistance; - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix; + shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * + cascade->viewMatrix); shadowUniform.cascades[i].texelSize = texelSize; } else { diff --git a/src/engine/renderer/VolumetricRenderer.cpp b/src/engine/renderer/VolumetricRenderer.cpp index b9617130d..e60b97e52 100644 --- a/src/engine/renderer/VolumetricRenderer.cpp +++ b/src/engine/renderer/VolumetricRenderer.cpp @@ -31,11 +31,13 @@ namespace Atlas { resolvePipelineConfig = PipelineConfig("volumetric/volumetricResolve.csh"); + lightCullingBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit, sizeof(uint32_t)); + volumetricUniformBuffer = Buffer::UniformBuffer(sizeof(VolumetricUniforms)); resolveUniformBuffer = Buffer::UniformBuffer(sizeof(ResolveUniforms)); blurWeightsUniformBuffer = Buffer::UniformBuffer(sizeof(float) * (size_t(filterSize) + 1)); - auto samplerDesc = Graphics::SamplerDesc { + auto samplerDesc = Graphics::SamplerDesc{ .filter = VK_FILTER_NEAREST, .mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, .compareEnabled = true @@ -48,6 +50,7 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Render volumetric"); + auto renderState = &scene->renderState; auto& camera = scene->GetMainCamera(); auto fog = scene->fog; @@ -59,133 +62,155 @@ namespace Atlas { commandList->BindImage(target->volumetricTexture.image, 3, 0); commandList->BindImage(lowResDepthTexture->image, lowResDepthTexture->sampler, 3, 1); + renderState->volumetricLightBuffer.Bind(commandList, 3, 8); + renderState->volumetricShadowBuffer.Bind(commandList, 3, 9); ivec2 res = ivec2(target->volumetricTexture.width, target->volumetricTexture.height); - Graphics::Profiler::BeginQuery("Ray marching"); - auto mainLightEntity = GetMainLightEntity(scene); - auto lightSubset = scene->GetSubset(); - for (auto& lightEntity : lightSubset) { + VolumetricUniforms uniforms; + uniforms.sampleCount = fog->rayMarchStepCount; + uniforms.intensity = fog->volumetricIntensity; + uniforms.lightCount = std::min(128, int32_t(renderState->volumetricLights.size())); + uniforms.directionalLightCount = 0; + + for (const auto& lightEntity : renderState->lightEntities) { + if (lightEntity.comp.type != LightType::DirectionalLight) + break; + + uniforms.directionalLightCount++; + } - auto& light = lightEntity.GetComponent(); - if (light.type != LightType::DirectionalLight || - !light.volumetric || !fog || !fog->rayMarching) - continue; + const int32_t groupSize = 16; - auto shadow = light.shadow; + res = ivec2(target->GetScaledWidth(), target->GetScaledHeight()); - const int32_t groupSize = 8; + ivec2 groupCount = res / groupSize; + groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); + groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - res = ivec2(target->GetScaledWidth(), target->GetScaledHeight()); + if (lightCullingBuffer.GetElementCount() < groupCount.x * groupCount.y * 64) { + lightCullingBuffer.SetSize(groupCount.x * groupCount.y * 64); + } - ivec2 groupCount = res / groupSize; - groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); - groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); + Graphics::Profiler::BeginQuery("Light culling"); - vec3 direction = normalize(vec3(camera.viewMatrix * - vec4(light.transformedProperties.directional.direction, 0.0f))); - - VolumetricUniforms uniforms; - uniforms.sampleCount = fog->rayMarchStepCount; - uniforms.intensity = fog->volumetricIntensity * light.intensity; - - uniforms.light.direction = vec4(direction, 0.0); - uniforms.light.color = vec4(Common::ColorConverter::ConvertSRGBToLinear(light.color), 0.0); - - if (light.shadow) { - uniforms.light.shadow.cascadeCount = shadow->viewCount; - uniforms.light.shadow.edgeSoftness = shadow->edgeSoftness; - - commandList->BindImage(shadow->maps->image, shadowSampler, 3, 2); - - auto& shadowUniform = uniforms.light.shadow; - for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { - auto& cascadeUniform = shadowUniform.cascades[i]; - auto cascadeString = "light.shadow.cascades[" + std::to_string(i) + "]"; - if (i < shadow->viewCount) { - auto cascade = &shadow->views[i]; - cascadeUniform.distance = cascade->farDistance; - cascadeUniform.cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix; - } - else { - cascadeUniform.distance = camera.farPlane; - } - } - } + commandList->BufferMemoryBarrier(lightCullingBuffer.Get(), VK_ACCESS_SHADER_WRITE_BIT); - auto ocean = scene->ocean; - bool oceanEnabled = ocean && ocean->enable; + CullingPushConstants cullingPushConstants; +#ifdef AE_BINDLESS + cullingPushConstants.lightCount = std::min(4096, int32_t(renderState->volumetricLights.size())); +#else + cullingPushConstants.lightCount = std::min(8, int32_t(renderState->volumetricLights.size())); +#endif - if (oceanEnabled) { - // This is the full res depth buffer.. - uniforms.oceanHeight = ocean->translation.y; - target->oceanDepthTexture.Bind(commandList, 3, 4); - // Needs barrier - target->oceanStencilTexture.Bind(commandList, 3, 5); - } + lightCullingBuffer.Bind(commandList, 3, 10); - auto fog = scene->fog; - bool fogEnabled = fog && fog->enable; + auto cullingPipelineConfig = PipelineConfig("volumetric/lightCulling.csh"); + auto pipeline = PipelineManager::GetPipeline(cullingPipelineConfig); + commandList->BindPipeline(pipeline); - uniforms.fogEnabled = fogEnabled ? 1 : 0; + commandList->PushConstants("constants", &cullingPushConstants); - if (fogEnabled) { - auto& fogUniform = uniforms.fog; - fogUniform.extinctionCoefficient = fog->extinctionCoefficients; - fogUniform.scatteringFactor = fog->scatteringFactor; - fogUniform.extinctionFactor = fog->extinctionFactor; - fogUniform.density = fog->density; - fogUniform.heightFalloff = fog->heightFalloff; - fogUniform.height = fog->height; - fogUniform.ambientFactor = fog->ambientFactor; - fogUniform.scatteringAnisotropy = glm::clamp(fog->scatteringAnisotropy, -0.999f, 0.999f); - } + commandList->Dispatch(groupCount.x, groupCount.y, 1); - auto clouds = scene->sky.clouds; - bool cloudsEnabled = clouds && clouds->enable && mainLightEntity.IsValid(); - bool cloudShadowsEnabled = cloudsEnabled && clouds->castShadow; + commandList->BufferMemoryBarrier(lightCullingBuffer.Get(), VK_ACCESS_SHADER_READ_BIT); - if (cloudsEnabled) { - target->volumetricCloudsTexture.Bind(commandList, 3, 6); + Graphics::Profiler::EndAndBeginQuery("Ray marching"); - float cloudInnerRadius = scene->sky.planetRadius + clouds->minHeight; - uniforms.planetCenterAndRadius = vec4(scene->sky.planetCenter, cloudInnerRadius); - } + auto ocean = scene->ocean; + bool oceanEnabled = ocean && ocean->enable; - if (cloudShadowsEnabled) { - auto& cloudShadowUniform = uniforms.cloudShadow; + if (oceanEnabled) { + // This is the full res depth buffer.. + uniforms.oceanHeight = ocean->translation.y; + target->oceanDepthTexture.Bind(commandList, 3, 3); + // Needs barrier + target->oceanStencilTexture.Bind(commandList, 3, 4); + } - clouds->shadowTexture.Bind(commandList, 3, 3); + bool fogEnabled = fog && fog->enable; - clouds->GetShadowMatrices(camera, normalize(light.transformedProperties.directional.direction), - cloudShadowUniform.vMatrix, cloudShadowUniform.pMatrix); + uniforms.fogEnabled = fogEnabled ? 1 : 0; - cloudShadowUniform.vMatrix = cloudShadowUniform.vMatrix * camera.invViewMatrix; + if (fogEnabled) { + auto& fogUniform = uniforms.fog; + fogUniform.extinctionCoefficient = fog->extinctionCoefficients; + fogUniform.scatteringFactor = fog->scatteringFactor; + fogUniform.extinctionFactor = fog->extinctionFactor; + fogUniform.density = fog->density; + fogUniform.heightFalloff = fog->heightFalloff; + fogUniform.height = fog->height; + fogUniform.ambientFactor = fog->ambientFactor; + fogUniform.scatteringAnisotropy = glm::clamp(fog->scatteringAnisotropy, -0.999f, 0.999f); + } - cloudShadowUniform.ivMatrix = glm::inverse(cloudShadowUniform.vMatrix); - cloudShadowUniform.ipMatrix = glm::inverse(cloudShadowUniform.pMatrix); - } + auto clouds = scene->sky.clouds; + bool cloudsEnabled = clouds && clouds->enable && mainLightEntity.IsValid(); + bool cloudShadowsEnabled = cloudsEnabled && clouds->castShadow; - volumetricUniformBuffer.SetData(&uniforms, 0); - commandList->BindBuffer(volumetricUniformBuffer.Get(), 3, 7); + if (cloudsEnabled) { + target->volumetricCloudsTexture.Bind(commandList, 3, 5); - commandList->BindImage(scramblingRankingTexture.image, scramblingRankingTexture.sampler, 3, 8); - commandList->BindImage(sobolSequenceTexture.image, sobolSequenceTexture.sampler, 3, 9); + float cloudInnerRadius = scene->sky.planetRadius + clouds->minHeight; + uniforms.planetCenterAndRadius = vec4(scene->sky.planetCenter, cloudInnerRadius); + } - volumetricPipelineConfig.ManageMacro("SHADOWS", light.shadow != nullptr); - volumetricPipelineConfig.ManageMacro("CLOUDS", cloudsEnabled); - volumetricPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowsEnabled); - volumetricPipelineConfig.ManageMacro("OCEAN", oceanEnabled); - auto volumetricPipeline = PipelineManager::GetPipeline(volumetricPipelineConfig); + if (cloudShadowsEnabled) { + auto& mainLight = mainLightEntity.GetComponent(); + auto& cloudShadowUniform = uniforms.cloudShadow; - commandList->BindPipeline(volumetricPipeline); + clouds->shadowTexture.Bind(commandList, 3, 2); - commandList->Dispatch(groupCount.x, groupCount.y, 1); + clouds->GetShadowMatrices(camera, normalize(mainLight.transformedProperties.directional.direction), + cloudShadowUniform.vMatrix, cloudShadowUniform.pMatrix); + + cloudShadowUniform.vMatrix = cloudShadowUniform.vMatrix * camera.invViewMatrix; + + cloudShadowUniform.ivMatrix = glm::inverse(cloudShadowUniform.vMatrix); + cloudShadowUniform.ipMatrix = glm::inverse(cloudShadowUniform.pMatrix); } + volumetricUniformBuffer.SetData(&uniforms, 0); + commandList->BindSampler(shadowSampler, 3, 6); + + commandList->BindBuffer(volumetricUniformBuffer.Get(), 3, 7); + +#ifndef AE_BINDLESS + std::vector> cascadeMaps; + std::vector> cubeMaps; + + uniforms.lightCount = std::min(8, int32_t(renderState->lightEntities.size())); + uniforms.directionalLightCount = std::min(8, uniforms.directionalLightCount); + for (int32_t i = 0; i < uniforms.lightCount; i++) { + auto& comp = renderState->lightEntities[i].comp; + + if (comp.shadow) { + auto& shadow = comp.shadow; + if (shadow->useCubemap) { + cubeMaps.push_back(shadow->cubemap->image); + } + else { + cascadeMaps.push_back(shadow->maps->image); + } + } + } + + commandList->BindSampledImages(cascadeMaps, 3, 11); + commandList->BindSampledImages(cubeMaps, 3, 19); +#endif + + volumetricPipelineConfig.ManageMacro("CLOUDS", cloudsEnabled); + volumetricPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowsEnabled); + volumetricPipelineConfig.ManageMacro("OCEAN", oceanEnabled); + volumetricPipelineConfig.ManageMacro("LOCAL_LIGHTS", fog->localLights); + auto volumetricPipeline = PipelineManager::GetPipeline(volumetricPipelineConfig); + + commandList->BindPipeline(volumetricPipeline); + + commandList->Dispatch(groupCount.x, groupCount.y, 1); + Graphics::Profiler::EndQuery(); std::vector bufferBarriers; @@ -215,38 +240,40 @@ namespace Atlas { commandList->BindImage(lowResDepthTexture->image, lowResDepthTexture->sampler, 3, 2); commandList->BindBuffer(blurWeightsUniformBuffer.Get(), 3, 4); - ivec2 groupCount = ivec2(res.x / groupSize, res.y); - groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); - imageBarriers = { - {target->volumetricTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, - {target->swapVolumetricTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, - }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + for (int32_t j = 0; j < 3; j++) { + ivec2 groupCount = ivec2(res.x / groupSize, res.y); + groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); + imageBarriers = { + {target->volumetricTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {target->swapVolumetricTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + }; + commandList->PipelineBarrier(imageBarriers, bufferBarriers); - commandList->BindPipeline(horizontalBlurPipeline); - commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); + commandList->BindPipeline(horizontalBlurPipeline); + commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); - commandList->BindImage(target->swapVolumetricTexture.image, 3, 0); - commandList->BindImage(target->volumetricTexture.image, target->volumetricTexture.sampler, 3, 1); + commandList->BindImage(target->swapVolumetricTexture.image, 3, 0); + commandList->BindImage(target->volumetricTexture.image, target->volumetricTexture.sampler, 3, 1); - commandList->Dispatch(groupCount.x, groupCount.y, 1); + commandList->Dispatch(groupCount.x, groupCount.y, 1); - groupCount = ivec2(res.x, res.y / groupSize); - groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); + groupCount = ivec2(res.x, res.y / groupSize); + groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - imageBarriers = { - {target->swapVolumetricTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, - {target->volumetricTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, - }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + imageBarriers = { + {target->swapVolumetricTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {target->volumetricTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + }; + commandList->PipelineBarrier(imageBarriers, bufferBarriers); - commandList->BindPipeline(verticalBlurPipeline); - commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); + commandList->BindPipeline(verticalBlurPipeline); + commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); - commandList->BindImage(target->volumetricTexture.image, 3, 0); - commandList->BindImage(target->swapVolumetricTexture.image, target->swapVolumetricTexture.sampler, 3, 1); + commandList->BindImage(target->volumetricTexture.image, 3, 0); + commandList->BindImage(target->swapVolumetricTexture.image, target->swapVolumetricTexture.sampler, 3, 1); - commandList->Dispatch(groupCount.x, groupCount.y, 1); + commandList->Dispatch(groupCount.x, groupCount.y, 1); + } Graphics::Profiler::EndQuery(); } diff --git a/src/engine/renderer/VolumetricRenderer.h b/src/engine/renderer/VolumetricRenderer.h index a7e6647b9..44d984861 100644 --- a/src/engine/renderer/VolumetricRenderer.h +++ b/src/engine/renderer/VolumetricRenderer.h @@ -18,14 +18,21 @@ namespace Atlas { void Render(Ref target, Ref scene, Graphics::CommandList* commandList); private: + struct alignas(16) CullingPushConstants { + int32_t lightCount; + }; + struct alignas(16) VolumetricUniforms { int sampleCount; float intensity; int fogEnabled; float oceanHeight; + int lightCount; + int offsetX; + int offsetY; + int directionalLightCount; vec4 planetCenterAndRadius; Fog fog; - Light light; CloudShadow cloudShadow; }; @@ -56,10 +63,11 @@ namespace Atlas { Texture::Texture2D scramblingRankingTexture; Texture::Texture2D sobolSequenceTexture; + Buffer::Buffer lightCullingBuffer; Buffer::UniformBuffer volumetricUniformBuffer; Buffer::UniformBuffer blurWeightsUniformBuffer; Buffer::UniformBuffer resolveUniformBuffer; - + Ref shadowSampler; }; diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index fdacc974f..47dec739f 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -25,7 +25,7 @@ namespace Atlas { float texelSize; float aligment0; float aligment1; - mat4 cascadeSpace; + mat3x4 cascadeSpace; }; struct alignas(16) Shadow { @@ -59,6 +59,19 @@ namespace Atlas { Shadow shadow; }; + struct alignas(16) VolumetricLight { + vec4 location; + vec4 direction; + + vec4 color; + float intensity; + + float typeSpecific0; + float typeSpecific1; + + int32_t shadowIdx; + }; + struct alignas(16) CloudShadow { mat4 vMatrix; mat4 pMatrix; diff --git a/src/engine/renderer/helper/RayTracingHelper.cpp b/src/engine/renderer/helper/RayTracingHelper.cpp index 8ee43da2d..da3baf826 100644 --- a/src/engine/renderer/helper/RayTracingHelper.cpp +++ b/src/engine/renderer/helper/RayTracingHelper.cpp @@ -5,6 +5,7 @@ #include "../../volume/BVH.h" #include "../../graphics/Profiler.h" #include "../../pipeline/PipelineManager.h" +#include #define DIRECTIONAL_LIGHT 0 #define TRIANGLE_LIGHT 1 @@ -19,7 +20,7 @@ namespace Atlas { RayTracingHelper::RayTracingHelper() { - const size_t lightCount = 256; + const size_t lightCount = 128; indirectDispatchBuffer = Buffer::Buffer(Buffer::BufferUsageBits::IndirectBufferBit | Buffer::BufferUsageBits::HighPriorityMemoryBit, 3 * sizeof(uint32_t), 0); @@ -76,7 +77,7 @@ namespace Atlas { auto lightCount = lightBuffer.GetElementCount(); selectedLights.clear(); // Randomly select lights (only at image offset 0) - if (lights.size() > lightCount) { + if (lights.size() > lightCount && stochasticLightSelection) { std::vector weights; weights.reserve(lights.size()); for (auto& light : lights) { @@ -97,8 +98,24 @@ namespace Atlas { light.data.y *= float(selectedLights.size()); } } + else if (lights.size() > lightCount && !stochasticLightSelection) { + auto& camera = scene->GetMainCamera(); + auto cameraLocation = camera.GetLocation(); + + std::sort(lights.begin(), lights.end(), [&](const GPULight& light0, const GPULight& light1) { + return glm::distance2(vec3(light0.P), cameraLocation) + < glm::distance2(vec3(light1.P), cameraLocation); + }); + + for (size_t i = 0; i < lightCount; i++) { + auto& light = lights[i]; + + light.data.y = 1.0f; + selectedLights.push_back(light); + } + } else { - for (auto light : lights) { + for (auto& light : lights) { light.data.y = 1.0f; selectedLights.push_back(light); } @@ -161,7 +178,7 @@ namespace Atlas { auto lightCount = lightBuffer.GetElementCount(); selectedLights.clear(); // Randomly select lights (only at image offset 0) - if (lights.size() > lightCount) { + if (lights.size() > lightCount && stochasticLightSelection) { std::vector weights; weights.reserve(lights.size()); for (auto& light : lights) { @@ -182,8 +199,24 @@ namespace Atlas { light.data.y *= float(selectedLights.size()); } } + else if (lights.size() > lightCount && !stochasticLightSelection) { + auto& camera = scene->GetMainCamera(); + auto cameraLocation = camera.GetLocation(); + + std::sort(lights.begin(), lights.end(), [&](const GPULight& light0, const GPULight& light1) { + return glm::distance2(vec3(light0.P), cameraLocation) + < glm::distance2(vec3(light1.P), cameraLocation); + }); + + for (size_t i = 0; i < lightCount; i++) { + auto& light = lights[i]; + + light.data.y = 1.0f; + selectedLights.push_back(light); + } + } else { - for (auto light : lights) { + for (auto& light : lights) { light.data.y = 1.0f; selectedLights.push_back(light); } @@ -439,6 +472,9 @@ namespace Atlas { lights.clear(); + auto& camera = scene->GetMainCamera(); + auto cameraLocation = camera.GetLocation(); + auto lightSubset = scene->GetSubset(); for (auto& lightEntity : lightSubset) { auto& light = lightEntity.GetComponent(); @@ -453,23 +489,24 @@ namespace Atlas { float specific0 = 0.0f; float specific1 = 0.0f; - uint32_t data = 0; + uint32_t data0 = 0, data1 = 0; const auto& prop = light.transformedProperties; // Parse individual light information based on type if (light.type == LightType::DirectionalLight) { - data |= (DIRECTIONAL_LIGHT << 28u); + data0 |= (DIRECTIONAL_LIGHT << 28u); weight = brightness; + P = cameraLocation; N = light.transformedProperties.directional.direction; } else if (light.type == LightType::PointLight) { - data |= (POINT_LIGHT << 28u); + data0 |= (POINT_LIGHT << 28u); weight = brightness; P = light.transformedProperties.point.position; radius = light.transformedProperties.point.radius; } else if (light.type == LightType::SpotLight) { - data |= (SPOT_LIGHT << 28u); + data0 |= (SPOT_LIGHT << 28u); weight = brightness; P = light.transformedProperties.spot.position; N = light.transformedProperties.spot.direction; @@ -484,14 +521,19 @@ namespace Atlas { specific1 = lightAngleOffset; } - data |= uint32_t(lights.size()); - auto cd = reinterpret_cast(data); + if (light.shadow) { + data1 |= 1u; + } + + data0 |= uint32_t(lights.size()); + auto castData0 = reinterpret_cast(data0); + auto castData1 = reinterpret_cast(data1); GPULight gpuLight; - gpuLight.P = vec4(P, 1.0f); + gpuLight.P = vec4(P, castData1); gpuLight.N = vec4(N, radius); gpuLight.color = vec4(radiance, 0.0f); - gpuLight.data = vec4(cd, weight, specific0, specific1); + gpuLight.data = vec4(castData0, weight, specific0, specific1); lights.push_back(gpuLight); } @@ -500,25 +542,27 @@ namespace Atlas { const auto& rtData = scene->rayTracingWorld; lights.insert(lights.end(), rtData->triangleLights.begin(), rtData->triangleLights.end()); } - - // Find the maximum weight - auto maxWeight = 0.0f; - for (auto& light : lights) { - maxWeight = glm::max(maxWeight, light.data.y); - } + + if (stochasticLightSelection) { + // Find the maximum weight + auto maxWeight = 0.0f; + for (auto& light : lights) { + maxWeight = glm::max(maxWeight, light.data.y); + } - // Calculate min weight and adjust lights based on it - auto minWeight = 0.005f * maxWeight; - // Also calculate the total weight - auto totalWeight = 0.0f; + // Calculate min weight and adjust lights based on it + auto minWeight = 0.005f * maxWeight; + // Also calculate the total weight + auto totalWeight = 0.0f; - for (auto& light : lights) { - light.data.y = glm::max(light.data.y, minWeight); - totalWeight += light.data.y; - } + for (auto& light : lights) { + light.data.y = glm::max(light.data.y, minWeight); + totalWeight += light.data.y; + } - for (auto& light : lights) { - light.data.y /= totalWeight; + for (auto& light : lights) { + light.data.y /= totalWeight; + } } } diff --git a/src/engine/renderer/helper/RayTracingHelper.h b/src/engine/renderer/helper/RayTracingHelper.h index a75d526eb..a436036e6 100644 --- a/src/engine/renderer/helper/RayTracingHelper.h +++ b/src/engine/renderer/helper/RayTracingHelper.h @@ -43,6 +43,7 @@ namespace Atlas { void UpdateLights(Ref scene, bool useEmissivesAsLights = false); + bool stochasticLightSelection = false; private: struct alignas(16) PushConstants { diff --git a/src/engine/renderer/helper/RenderList.cpp b/src/engine/renderer/helper/RenderList.cpp index bc99b5bf7..f39110e3c 100644 --- a/src/engine/renderer/helper/RenderList.cpp +++ b/src/engine/renderer/helper/RenderList.cpp @@ -39,7 +39,6 @@ namespace Atlas { auto id = mesh.GetID(); meshIdToMeshMap[id] = mesh; } - } Ref RenderList::NewMainPass() { diff --git a/src/engine/renderer/target/RenderTarget.cpp b/src/engine/renderer/target/RenderTarget.cpp index 081e47d5e..1e10f5f7d 100644 --- a/src/engine/renderer/target/RenderTarget.cpp +++ b/src/engine/renderer/target/RenderTarget.cpp @@ -21,29 +21,29 @@ namespace Atlas::Renderer { targetDataSwapDownsampled2x = RenderTargetData(halfRes, false); historyTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); swapHistoryTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); lightingTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); reactiveMaskTexture = Texture::Texture2D(scaledWidth, scaledWidth, VK_FORMAT_R8_UNORM, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); hdrTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::MipMapLinear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::MipMapLinear, false, true); bloomTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::MipMapLinear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::MipMapLinear, false, true); outputTexture = Texture::Texture2D(width, height, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); oceanDepthTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_D32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest, false, true); oceanStencilTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R8_UINT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest, false, true); radianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyRadianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); frameAccumTexture = Texture::Texture2DArray(scaledWidth, scaledHeight, 3, VK_FORMAT_R32_UINT); CreateRenderPasses(); @@ -145,27 +145,27 @@ namespace Atlas::Renderer { giResolution = resolution; giTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); swapGiTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyGiTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); if (createMomentsTexture) { giLengthTexture.Reset(); historyGiLengthTexture.Reset(); giMomentsTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyGiMomentsTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); } else { giMomentsTexture.Reset(); historyGiMomentsTexture.Reset(); giLengthTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyGiLengthTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); } hasHistory = false; @@ -184,16 +184,16 @@ namespace Atlas::Renderer { aoResolution = resolution; aoTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); swapAoTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyAoTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); aoLengthTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyAoLengthTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); hasHistory = false; @@ -210,15 +210,17 @@ namespace Atlas::Renderer { auto res = GetRelativeResolution(resolution); volumetricResolution = resolution; - volumetricTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT); - swapVolumetricTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT); + volumetricTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); + swapVolumetricTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); volumetricCloudsTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); swapVolumetricCloudsTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyVolumetricCloudsTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); hasHistory = false; @@ -236,16 +238,16 @@ namespace Atlas::Renderer { reflectionResolution = resolution; reflectionTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); swapReflectionTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyReflectionTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); reflectionMomentsTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyReflectionMomentsTexture = Texture::Texture2D(res.x, res.y, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); hasHistory = false; @@ -331,6 +333,7 @@ namespace Atlas::Renderer { void RenderTarget::UseForPathTracing(bool use) { + hasHistory = false; useForPathTracing = use; if (useForPathTracing) { @@ -342,10 +345,11 @@ namespace Atlas::Renderer { targetDataSwapDownsampled2x = RenderTargetData(); radianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); historyRadianceTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R32G32B32A32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - frameAccumTexture = Texture::Texture2DArray(scaledWidth, scaledHeight, 3, VK_FORMAT_R32_UINT); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); + frameAccumTexture = Texture::Texture2DArray(scaledWidth, scaledHeight, 3, VK_FORMAT_R32_UINT, + Texture::Wrapping::Repeat, Texture::Filtering::Nearest, false, true); } else { ivec2 res = GetRelativeResolution(FULL_RES); diff --git a/src/engine/renderer/target/RenderTarget.h b/src/engine/renderer/target/RenderTarget.h index b38c11af8..c679760d1 100644 --- a/src/engine/renderer/target/RenderTarget.h +++ b/src/engine/renderer/target/RenderTarget.h @@ -22,28 +22,28 @@ namespace Atlas::Renderer { VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); if (useDepthFormat) { depthTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_D32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest, false, true); } else { depthTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_R32_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest, false, true); } normalTexture = std::make_shared(resolution.x, resolution.y, - VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); geometryNormalTexture = std::make_shared(resolution.x, resolution.y, - VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); roughnessMetallicAoTexture = std::make_shared(resolution.x, resolution.y, - VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); emissiveTexture = std::make_shared(resolution.x, resolution.y, - VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); offsetTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_R8_SINT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest, false, true); materialIdxTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_R16_UINT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest, false, true); stencilTexture = std::make_shared(resolution.x, resolution.y, VK_FORMAT_R8_UINT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); + Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest, false, true); velocityTexture = std::make_shared(resolution.x, resolution.y, - VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + VK_FORMAT_R16G16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); } void Resize(ivec2 resolution) { diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index aabcad3df..5299ff6fb 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -120,18 +120,25 @@ namespace Atlas { TransformComponent rootTransform = {}; - auto hierarchyTransformSubset = entityManager.GetSubset(); + auto hierarchySubset = entityManager.GetSubset(); // Update hierarchy and their entities - for (auto entity : hierarchyTransformSubset) { - const auto& [hierarchyComponent, transformComponent] = hierarchyTransformSubset.Get(entity); + for (auto entity : hierarchySubset) { + auto& hierarchyComponent = hierarchySubset.Get(entity); if (hierarchyComponent.root) { - auto parentChanged = transformComponent.changed; - transformComponent.Update(rootTransform, false); - hierarchyComponent.Update(transformComponent, parentChanged); + auto transformComponent = entityManager.TryGet(entity); + if (transformComponent) { + auto parentChanged = transformComponent->changed; + transformComponent->Update(rootTransform, false); + hierarchyComponent.Update(*transformComponent, parentChanged); + } + else { + hierarchyComponent.Update(rootTransform, false); + } } } + auto hierarchyTransformSubset = entityManager.GetSubset(); // Update hierarchy components which are not part of a root hierarchy that also has a transform component // This might be the case if there is an entity that has just a hierarchy without a tranform for, e.g. grouping entities for (auto entity : hierarchyTransformSubset) { @@ -177,6 +184,11 @@ namespace Atlas { } playerComponent.Update(deltaTime); + + auto hierarchyComponent = entityManager.TryGet(entity); + if (hierarchyComponent) { + hierarchyComponent->Update(transformComponent, true); + } } auto rigidBodySubset = entityManager.GetSubset(); @@ -190,19 +202,21 @@ namespace Atlas { } // Apply update here (transform overwrite everything else in physics simulation for now) - if (transformComponent.changed && rigidBodyComponent.IsValid()) { + if (transformComponent.changed && rigidBodyComponent.IsValid()) { rigidBodyComponent.SetMatrix(transformComponent.globalMatrix); } } // This part only needs to be executed if the simulation is running if (!physicsWorld->pauseSimulation) { - // Player update needs to be performed after normal rigid bodies, such that - // player can override rigid body behaviour - for (auto entity : playerSubset) { - const auto& [playerComponent, transformComponent] = playerSubset.Get(entity); - if (!playerComponent.IsValid()) + physicsWorld->Update(deltaTime); + + for (auto entity : rigidBodySubset) { + const auto& [rigidBodyComponent, transformComponent] = rigidBodySubset.Get(entity); + + if (!rigidBodyComponent.IsValid() || transformComponent.isStatic || + rigidBodyComponent.layer == Physics::Layers::Static) continue; // This happens if no change was triggered by the user, then we still need @@ -215,17 +229,16 @@ namespace Atlas { transformComponent.updated = true; // Physics are updated in global space, so we don't need the parent transform - transformComponent.globalMatrix = playerComponent.GetMatrix(); + transformComponent.globalMatrix = rigidBodyComponent.GetMatrix(); transformComponent.inverseGlobalMatrix = glm::inverse(transformComponent.globalMatrix); } - physicsWorld->Update(deltaTime); - - for (auto entity : rigidBodySubset) { - const auto& [rigidBodyComponent, transformComponent] = rigidBodySubset.Get(entity); + // Player update needs to be performed after normal rigid bodies, such that + // player can override rigid body behaviour + for (auto entity : playerSubset) { + const auto& [playerComponent, transformComponent] = playerSubset.Get(entity); - if (!rigidBodyComponent.IsValid() || transformComponent.isStatic || - rigidBodyComponent.layer == Physics::Layers::Static) + if (!playerComponent.IsValid()) continue; // This happens if no change was triggered by the user, then we still need @@ -238,9 +251,43 @@ namespace Atlas { transformComponent.updated = true; // Physics are updated in global space, so we don't need the parent transform - transformComponent.globalMatrix = rigidBodyComponent.GetMatrix(); + transformComponent.globalMatrix = playerComponent.GetMatrix(); transformComponent.inverseGlobalMatrix = glm::inverse(transformComponent.globalMatrix); } + + // Now we need to update all the hiearchies + auto rigidBodyHierarchySubset = entityManager.GetSubset(); + for (auto entity : rigidBodyHierarchySubset) { + auto& hierarchyComponent = entityManager.Get(entity); + + hierarchyComponent.updated = false; + } + + for (auto entity : rigidBodyHierarchySubset) { + const auto& [rigidBodyComponent, hierarchyComponent, transformComponent] = rigidBodyHierarchySubset.Get(entity); + + if (!hierarchyComponent.updated) { + auto parentChanged = transformComponent.changed; + hierarchyComponent.Update(transformComponent, parentChanged); + } + } + + // Now we need to update all the hiearchies + auto playerHierarchySubset = entityManager.GetSubset(); + for (auto entity : playerHierarchySubset) { + auto& hierarchyComponent = entityManager.Get(entity); + + hierarchyComponent.updated = false; + } + + for (auto entity : playerHierarchySubset) { + const auto& [playerComponent, hierarchyComponent, transformComponent] = playerHierarchySubset.Get(entity); + + if (!hierarchyComponent.updated) { + auto parentChanged = transformComponent.changed; + hierarchyComponent.Update(transformComponent, parentChanged); + } + } } } @@ -303,7 +350,6 @@ namespace Atlas { #endif // We also need to reset the hierarchy components as well - auto hierarchySubset = entityManager.GetSubset(); for (auto entity : hierarchySubset) { auto& hierarchyComponent = hierarchySubset.Get(entity); diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index c2b7905b8..8b51f8572 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -416,9 +416,11 @@ namespace Atlas::Scene { JobSystem::Wait(bindlessOtherTextureMapUpdateJob); - std::vector lights; if (lightEntities.size()) { - lights.reserve(lightEntities.size()); + lights.clear(); + volumetricLights.clear(); + volumetricShadows.clear(); + for (const auto& entity : lightEntities) { auto& light = entity.comp; @@ -443,6 +445,7 @@ namespace Atlas::Scene { lightUniform.direction = camera.viewMatrix * vec4(prop.spot.direction, 0.0f); lightUniform.direction.w = prop.spot.radius; + auto tanOuter = tanf(prop.spot.outerConeAngle); auto cosOuter = cosf(prop.spot.outerConeAngle); auto cosInner = cosf(prop.spot.innerConeAngle); auto angleScale = 1.0f / std::max(0.001f, cosInner - cosOuter); @@ -450,6 +453,9 @@ namespace Atlas::Scene { lightUniform.typeSpecific0 = angleScale; lightUniform.typeSpecific1 = angleOffset; + + uint32_t coneTrig = glm::packHalf2x16(vec2(cosOuter, tanOuter)); + lightUniform.location.w = reinterpret_cast(coneTrig); } if (light.shadow) { @@ -473,18 +479,8 @@ namespace Atlas::Scene { abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; shadowUniform.cascades[i].distance = cascade->farDistance; if (light.type == LightType::DirectionalLight) { - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix; - } - else if (light.type == LightType::PointLight) { - if (i == 0) - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix; - else - shadowUniform.cascades[i].cascadeSpace = glm::translate(mat4(1.0f), -prop.point.position) * camera.invViewMatrix; - } - else if (light.type == LightType::SpotLight) { - shadowUniform.cascades[i].cascadeSpace = cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix; + shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * + cascade->viewMatrix * camera.invViewMatrix); } shadowUniform.cascades[i].texelSize = texelSize; } @@ -493,16 +489,51 @@ namespace Atlas::Scene { shadowUniform.cascades[i].distance = cascade->farDistance; } } + + if (light.type == LightType::PointLight) { + auto projectionMatrix = shadow->views[0].projectionMatrix; + shadowUniform.cascades[0].cascadeSpace = glm::transpose(glm::translate(mat4(1.0f), -prop.point.position) * camera.invViewMatrix); + shadowUniform.cascades[1].cascadeSpace[0] = projectionMatrix[0]; + shadowUniform.cascades[1].cascadeSpace[1] = projectionMatrix[1]; + shadowUniform.cascades[1].cascadeSpace[2] = projectionMatrix[2]; + shadowUniform.cascades[2].cascadeSpace[0] = projectionMatrix[3]; + } + else if (light.type == LightType::SpotLight) { + auto cascadeMatrix = shadow->views[0].projectionMatrix * + shadow->views[0].viewMatrix * camera.invViewMatrix; + shadowUniform.cascades[0].cascadeSpace[0] = cascadeMatrix[0]; + shadowUniform.cascades[0].cascadeSpace[1] = cascadeMatrix[1]; + shadowUniform.cascades[0].cascadeSpace[2] = cascadeMatrix[2]; + shadowUniform.cascades[1].cascadeSpace[0] = cascadeMatrix[3]; + } + } + else { + lightUniform.shadow.mapIdx = -1; } - lights.emplace_back(lightUniform); + lights.push_back(lightUniform); + + if (light.volumetricIntensity > 0.0f) { + Renderer::VolumetricLight volumetricLightUniform{ + .location = lightUniform.location, + .direction = lightUniform.direction, + .color = lightUniform.color, + .intensity = light.volumetricIntensity * light.intensity, + .typeSpecific0 = lightUniform.typeSpecific0, + .typeSpecific1 = lightUniform.typeSpecific1, + .shadowIdx = light.shadow ? int32_t(volumetricShadows.size()) : -1 + }; + + volumetricLights.push_back(volumetricLightUniform); + volumetricShadows.push_back(lightUniform.shadow); + } } } else { // We need to have at least a fake light auto type = 0; auto packedType = reinterpret_cast(type); - lights.emplace_back(Renderer::Light { + lights.push_back(Renderer::Light { .direction = vec4(0.0f, -1.0f, 0.0f, 0.0f), .color = vec4(vec3(0.0f), packedType), .intensity = 0.0f, @@ -517,6 +548,22 @@ namespace Atlas::Scene { lightBuffer.SetData(lights.data(), 0, lights.size()); } + if (volumetricLightBuffer.GetElementCount() < volumetricLights.size()) { + volumetricLightBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit + | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Renderer::VolumetricLight), volumetricLights.size(), volumetricLights.data()); + } + else { + volumetricLightBuffer.SetData(volumetricLights.data(), 0, volumetricLights.size()); + } + + if (volumetricShadowBuffer.GetElementCount() < volumetricShadows.size()) { + volumetricShadowBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit + | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Renderer::Shadow), volumetricShadows.size(), volumetricShadows.data()); + } + else { + volumetricShadowBuffer.SetData(volumetricShadows.data(), 0, volumetricShadows.size()); + } + }); } diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index 1486d00cf..99eb5c062 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -48,6 +48,9 @@ namespace Atlas::Scene { Buffer::Buffer materialBuffer; Buffer::Buffer lightBuffer; + Buffer::Buffer volumetricLightBuffer; + Buffer::Buffer volumetricShadowBuffer; + std::vector> textures; std::vector> textureArrays; std::vector> cubemaps; @@ -62,7 +65,11 @@ namespace Atlas::Scene { std::unordered_map, uint32_t> textureArrayToBindlessIdx; std::unordered_map, uint32_t> cubemapToBindlessIdx; std::unordered_map meshIdToBindlessIdx; + std::vector lightEntities; + std::vector lights; + std::vector volumetricLights; + std::vector volumetricShadows; JobSignal mainCameraSignal; diff --git a/src/engine/scene/components/ComponentSerializer.cpp b/src/engine/scene/components/ComponentSerializer.cpp index 62ef3fac8..866c5e5a5 100644 --- a/src/engine/scene/components/ComponentSerializer.cpp +++ b/src/engine/scene/components/ComponentSerializer.cpp @@ -133,7 +133,8 @@ namespace Atlas::Scene::Components { {"intensity", p.intensity}, {"properties", typeProperties}, {"isMain", p.isMain}, - {"volumetric", p.volumetric} + {"volumetric", p.volumetric}, + {"volumetricIntensity", p.volumetricIntensity} }; if (p.shadow) @@ -152,6 +153,8 @@ namespace Atlas::Scene::Components { j.at("isMain").get_to(p.isMain); j.at("volumetric").get_to(p.volumetric); + try_get_json(j, "volumetricIntensity", p.volumetricIntensity); + p.type = static_cast(type); p.mobility = static_cast(mobility); @@ -341,8 +344,20 @@ namespace Atlas::Scene::Components { j["scriptProperties"][name]["type"] = "string"; j["scriptProperties"][name]["value"] = prop.stringValue; break; + case LuaScriptComponent::PropertyType::Vec2: + j["scriptProperties"][name]["type"] = "vec2"; + j["scriptProperties"][name]["value"] = prop.vec2Value; + break; + case LuaScriptComponent::PropertyType::Vec3: + j["scriptProperties"][name]["type"] = "vec3"; + j["scriptProperties"][name]["value"] = prop.vec3Value; + break; + case LuaScriptComponent::PropertyType::Vec4: + j["scriptProperties"][name]["type"] = "vec4"; + j["scriptProperties"][name]["value"] = prop.vec4Value; + break; default: - AE_ASSERT(false); + break; } } } @@ -381,6 +396,18 @@ namespace Atlas::Scene::Components { { p.SetPropertyValue(v.key(), value["value"].get()); } + else if (propertyTypeAsString == "vec2") + { + p.SetPropertyValue(v.key(), value["value"].get()); + } + else if (propertyTypeAsString == "vec3") + { + p.SetPropertyValue(v.key(), value["value"].get()); + } + else if (propertyTypeAsString == "vec4") + { + p.SetPropertyValue(v.key(), value["value"].get()); + } } } } diff --git a/src/engine/scene/components/LightComponent.h b/src/engine/scene/components/LightComponent.h index a2958f61d..9a6b2cc7f 100644 --- a/src/engine/scene/components/LightComponent.h +++ b/src/engine/scene/components/LightComponent.h @@ -88,6 +88,7 @@ namespace Atlas { vec3 color = vec3(1.0f); float intensity = 1.0f; + float volumetricIntensity = 1.0f; TypeProperties properties; TypeProperties transformedProperties; diff --git a/src/engine/scene/components/LuaScriptComponent.cpp b/src/engine/scene/components/LuaScriptComponent.cpp index 3a4ae3b08..fe90498fd 100644 --- a/src/engine/scene/components/LuaScriptComponent.cpp +++ b/src/engine/scene/components/LuaScriptComponent.cpp @@ -96,7 +96,7 @@ namespace Atlas::Scene::Components { return; // and then get or update the properties from the script - GetOrUpdatePropertiesFromScript(); + GetOrUpdatePropertiesFromScript(scriptWasModifiedInLastUpdate); environmentNeedsInitialization = false; } @@ -225,6 +225,15 @@ namespace Atlas::Scene::Components { else if (typeValue == "boolean") { scriptProperty.type = PropertyType::Boolean; } + else if (typeValue == "vec2") { + scriptProperty.type = PropertyType::Vec2; + } + else if (typeValue == "vec3") { + scriptProperty.type = PropertyType::Vec3; + } + else if (typeValue == "vec4") { + scriptProperty.type = PropertyType::Vec4; + } else { continue; // unknown type } @@ -254,6 +263,21 @@ namespace Atlas::Scene::Components { continue; scriptProperty.booleanValue = value.get(); break; + case PropertyType::Vec2: + if (!value.is()) + continue; + scriptProperty.vec2Value = value.get(); + break; + case PropertyType::Vec3: + if (!value.is()) + continue; + scriptProperty.vec3Value = value.get(); + break; + case PropertyType::Vec4: + if (!value.is()) + continue; + scriptProperty.vec3Value = value.get(); + break; case PropertyType::Undefined: break; } @@ -264,7 +288,7 @@ namespace Atlas::Scene::Components { return foundProperties; } - void LuaScriptComponent::GetOrUpdatePropertiesFromScript() { + void LuaScriptComponent::GetOrUpdatePropertiesFromScript(bool update) { // obtain the new properties from the script auto newProperties = GetPropertiesFromScript(); @@ -275,7 +299,7 @@ namespace Atlas::Scene::Components { continue; const auto& existingProperty = properties[name]; - if (!existingProperty.wasChanged) + if (!existingProperty.wasChanged && !update) continue; // Only update if there was a server side change of the script properties @@ -304,6 +328,15 @@ namespace Atlas::Scene::Components { case PropertyType::Boolean: state["ScriptProperties"][propertyName]["value"] = property.booleanValue; break; + case PropertyType::Vec2: + state["ScriptProperties"][propertyName]["value"] = property.vec2Value; + break; + case PropertyType::Vec3: + state["ScriptProperties"][propertyName]["value"] = property.vec3Value; + break; + case PropertyType::Vec4: + state["ScriptProperties"][propertyName]["value"] = property.vec4Value; + break; case PropertyType::Undefined: break; } diff --git a/src/engine/scene/components/LuaScriptComponent.h b/src/engine/scene/components/LuaScriptComponent.h index be2a82078..39bf31dd2 100644 --- a/src/engine/scene/components/LuaScriptComponent.h +++ b/src/engine/scene/components/LuaScriptComponent.h @@ -24,7 +24,10 @@ namespace Atlas::Scene { String, Double, Integer, - Boolean + Boolean, + Vec2, + Vec3, + Vec4 }; class ScriptProperty { @@ -44,6 +47,10 @@ namespace Atlas::Scene { int integerValue = 0; bool booleanValue = false; + vec2 vec2Value = vec2(0.0f); + vec3 vec3Value = vec3(0.0f); + vec4 vec4Value = vec4(0.0f); + bool wasChanged = false; }; @@ -88,7 +95,7 @@ namespace Atlas::Scene { bool InitScriptEnvironment(); std::map GetPropertiesFromScript(); - void GetOrUpdatePropertiesFromScript(); + void GetOrUpdatePropertiesFromScript(bool update); void SetPropertyValuesInLuaState(); }; @@ -96,7 +103,8 @@ namespace Atlas::Scene { void LuaScriptComponent::ScriptProperty::SetValue(const T value) { static_assert(std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v, "Unsupported type"); + std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v, "Unsupported type"); if constexpr (std::is_same_v) { stringValue = value; @@ -114,6 +122,18 @@ namespace Atlas::Scene { booleanValue = value; type = PropertyType::Boolean; } + else if constexpr (std::is_same_v) { + vec2Value = value; + type = PropertyType::Vec2; + } + else if constexpr (std::is_same_v) { + vec3Value = value; + type = PropertyType::Vec3; + } + else if constexpr (std::is_same_v) { + vec4Value = value; + type = PropertyType::Vec4; + } wasChanged = true; } @@ -123,8 +143,9 @@ namespace Atlas::Scene { AE_ASSERT(type != PropertyType::Undefined && "This property was most likely not defined properly"); - static_assert(std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v, "Unsupported type"); + static_assert(std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v, "Unsupported type"); if constexpr (std::is_same_v) { return stringValue; @@ -138,6 +159,15 @@ namespace Atlas::Scene { else if constexpr (std::is_same_v) { return booleanValue; } + else if constexpr (std::is_same_v) { + return vec2Value; + } + else if constexpr (std::is_same_v) { + return vec3Value; + } + else if constexpr (std::is_same_v) { + return vec4Value; + } else { } diff --git a/src/engine/scripting/bindings/MathBindings.cpp b/src/engine/scripting/bindings/MathBindings.cpp index 4257089b8..a2cb24081 100644 --- a/src/engine/scripting/bindings/MathBindings.cpp +++ b/src/engine/scripting/bindings/MathBindings.cpp @@ -72,6 +72,28 @@ namespace Atlas::Scripting::Bindings { [](const glm::quat& quat0, const glm::quat& quat1, const float factor) { return glm::mix(quat0, quat1, factor); } )); + ns->set_function("Clamp", sol::overload( + [](const float float0, const float float1, const float float2) { return glm::clamp(float0, float1, float2); }, + [](const int32_t int0, const int32_t int1, const int32_t int2) { return glm::clamp(int0, int1, int2); }, + [](const glm::vec2& vec0, const glm::vec2& vec1, const glm::vec2& vec2) { return glm::clamp(vec0, vec1, vec2); }, + [](const glm::vec3& vec0, const glm::vec3& vec1, const glm::vec3& vec2) { return glm::clamp(vec0, vec1, vec2); }, + [](const glm::vec4& vec0, const glm::vec4& vec1, const glm::vec4& vec2) { return glm::clamp(vec0, vec1, vec2); } + )); + + ns->set_function("Max", sol::overload( + [](const float float0, const float float1) { return glm::max(float0, float1); }, + [](const glm::vec2& vec0, const glm::vec2& vec1) { return glm::max(vec0, vec1); }, + [](const glm::vec3& vec0, const glm::vec3& vec1) { return glm::max(vec0, vec1); }, + [](const glm::vec4& vec0, const glm::vec4& vec1) { return glm::max(vec0, vec1); } + )); + + ns->set_function("Min", sol::overload( + [](const float float0, const float float1) { return glm::min(float0, float1); }, + [](const glm::vec2& vec0, const glm::vec2& vec1) { return glm::min(vec0, vec1); }, + [](const glm::vec3& vec0, const glm::vec3& vec1) { return glm::min(vec0, vec1); }, + [](const glm::vec4& vec0, const glm::vec4& vec1) { return glm::min(vec0, vec1); } + )); + ns->set_function("LookAt", [](const glm::vec3& eye, const glm::vec3& center, const glm::vec3& up) { return glm::lookAt(eye, center, up); } ); diff --git a/src/engine/scripting/bindings/SceneBindings.cpp b/src/engine/scripting/bindings/SceneBindings.cpp index 4aea14096..6a2c89de3 100644 --- a/src/engine/scripting/bindings/SceneBindings.cpp +++ b/src/engine/scripting/bindings/SceneBindings.cpp @@ -214,7 +214,6 @@ namespace Atlas::Scripting::Bindings { "Decompose", &TransformComponent::Decompose, "DecomposeGlobal", &TransformComponent::DecomposeGlobal, "ReconstructLocalMatrix", &TransformComponent::ReconstructLocalMatrix, - //"Compose", &TransformComponent::Compose, "matrix", &TransformComponent::matrix, "globalMatrix", &TransformComponent::globalMatrix ); diff --git a/src/engine/texture/Texture.cpp b/src/engine/texture/Texture.cpp index 95b715faa..9ca2ec3d0 100644 --- a/src/engine/texture/Texture.cpp +++ b/src/engine/texture/Texture.cpp @@ -14,10 +14,11 @@ namespace Atlas { std::unordered_map> Texture::samplerMap; Texture::Texture(int32_t width, int32_t height, int32_t depth, VkFormat format, - Wrapping wrapping, Filtering filtering) : width(width), height(height), depth(depth), + Wrapping wrapping, Filtering filtering, bool dedicatedMemory) + : width(width), height(height), depth(depth), wrapping(wrapping), filtering(filtering), format(format) { - Reallocate(Graphics::ImageType::Image2D, width, height, depth, filtering, wrapping); + Reallocate(Graphics::ImageType::Image2D, width, height, depth, filtering, wrapping, dedicatedMemory); RecreateSampler(filtering, wrapping); } @@ -93,13 +94,16 @@ namespace Atlas { } void Texture::Reallocate(Graphics::ImageType imageType, int32_t width, int32_t height, int32_t depth, - Filtering filtering, Wrapping wrapping, bool dedicatedMemory) { + Filtering filtering, Wrapping wrapping, bool dedicatedMemory, bool usedForRenderTarget) { auto graphicsDevice = Graphics::GraphicsDevice::DefaultDevice; this->width = width; this->height = height; this->depth = depth; + this->dedicatedMemory = dedicatedMemory; + this->usedForRenderTarget = usedForRenderTarget; + channels = int32_t(Graphics::GetFormatChannels(format)); bool generateMipMaps = filtering == Filtering::MipMapLinear || @@ -123,6 +127,14 @@ namespace Atlas { VkImageAspectFlags aspectFlag = depthFormat ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + VmaPool* vmaPool = nullptr; + if (usedForRenderTarget) { + vmaPool = &graphicsDevice->memoryManager->highPriorityRenderTargetPool; + } + else if (dedicatedMemory) { + vmaPool = &graphicsDevice->memoryManager->highPriorityMemoryPool; + } + auto imageDesc = Graphics::ImageDesc { .usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | additionalUsageFlags, @@ -134,7 +146,7 @@ namespace Atlas { .layers = arrayType ? uint32_t(depth) : 1, .format = format, .mipMapping = generateMipMaps, - .dedicatedMemory = true + .dedicatedMemoryPool = vmaPool }; image = graphicsDevice->CreateImage(imageDesc); diff --git a/src/engine/texture/Texture.h b/src/engine/texture/Texture.h index f30ae1406..6fa0128a8 100644 --- a/src/engine/texture/Texture.h +++ b/src/engine/texture/Texture.h @@ -45,7 +45,8 @@ namespace Atlas { * @param filtering The filtering of the texture. */ Texture(int32_t width, int32_t height, int32_t depth, VkFormat format, - Wrapping wrapping = Wrapping::Repeat, Filtering filtering = Filtering::Nearest); + Wrapping wrapping = Wrapping::Repeat, Filtering filtering = Filtering::Nearest, + bool dedicatedMemory = false); /** * Binds the image and sampler of the texture to the specified binding point @@ -124,6 +125,9 @@ namespace Atlas { Wrapping wrapping = Wrapping::Repeat; Filtering filtering = Filtering::Nearest; + bool dedicatedMemory = false; + bool usedForRenderTarget = false; + VkFormat format = {}; protected: @@ -131,7 +135,8 @@ namespace Atlas { int32_t width, int32_t height, int32_t depth); void Reallocate(Graphics::ImageType imageType, int32_t width, int32_t height, - int32_t depth, Filtering filtering, Wrapping wrapping, bool dedicatedMemory = false); + int32_t depth, Filtering filtering, Wrapping wrapping, + bool dedicatedMemory = false, bool usedForRenderTarget = false); void RecreateSampler(Filtering filtering, Wrapping wrapping); diff --git a/src/engine/texture/Texture2D.cpp b/src/engine/texture/Texture2D.cpp index b59ebf790..b6f569f6a 100644 --- a/src/engine/texture/Texture2D.cpp +++ b/src/engine/texture/Texture2D.cpp @@ -4,17 +4,19 @@ namespace Atlas { namespace Texture { - Texture2D::Texture2D(int32_t width, int32_t height, VkFormat format, Wrapping wrapping, Filtering filtering) { + Texture2D::Texture2D(int32_t width, int32_t height, VkFormat format, Wrapping wrapping, Filtering filtering, + bool dedicatedMemory, bool usedForRenderTarget) { this->format = format; - Reallocate(Graphics::ImageType::Image2D, width, height, 1, filtering, wrapping); + Reallocate(Graphics::ImageType::Image2D, width, height, 1, filtering, wrapping, dedicatedMemory, usedForRenderTarget); RecreateSampler(filtering, wrapping); } Texture2D::Texture2D(const std::string& filename, bool colorSpaceConversion, - Wrapping wrapping, Filtering filtering, int32_t forceChannels) { + Wrapping wrapping, Filtering filtering, int32_t forceChannels, + bool dedicatedMemory, bool usedForRenderTarget) { auto image = Loader::ImageLoader::LoadImage(filename, colorSpaceConversion, forceChannels); @@ -38,7 +40,8 @@ namespace Atlas { if (width != this->width || height != this->height) { - Reallocate(Graphics::ImageType::Image2D, width, height, 1, filtering, wrapping); + Reallocate(Graphics::ImageType::Image2D, width, height, 1, + filtering, wrapping, dedicatedMemory, usedForRenderTarget); } diff --git a/src/engine/texture/Texture2D.h b/src/engine/texture/Texture2D.h index 8fe6c8520..215892a8d 100644 --- a/src/engine/texture/Texture2D.h +++ b/src/engine/texture/Texture2D.h @@ -27,7 +27,7 @@ namespace Atlas { * @param filtering The filtering of the texture. */ Texture2D(int32_t width, int32_t height, VkFormat format, Wrapping wrapping = Wrapping::Repeat, - Filtering filtering = Filtering::Nearest); + Filtering filtering = Filtering::Nearest, bool dedicatedMemory = false, bool usedForRenderTarget = false); /** * Constructs a Texture2D object from an image file. @@ -39,7 +39,7 @@ namespace Atlas { */ explicit Texture2D(const std::string& filename, bool colorSpaceConversion = true, Wrapping wrapping = Wrapping::Repeat, Filtering filtering = Filtering::Anisotropic, - int32_t forceChannels = 0); + int32_t forceChannels = 0, bool dedicatedMemory = false, bool usedForRenderTarget = false); /** * Constructs a Texture2D object from an image object. @@ -79,7 +79,7 @@ namespace Atlas { private: template void InitializeInternal(const Ref>& image, Wrapping wrapping, - Filtering filtering); + Filtering filtering, bool dedicatedMemory = false, bool usedForRenderTarget = false); }; @@ -126,7 +126,8 @@ namespace Atlas { } template - void Texture2D::InitializeInternal(const Ref>& image, Wrapping wrapping, Filtering filtering) { + void Texture2D::InitializeInternal(const Ref>& image, Wrapping wrapping, Filtering filtering, + bool dedicatedMemory, bool usedForRenderTarget) { // RGB images are mostly not supported if (image->channels == 3) { @@ -155,7 +156,7 @@ namespace Atlas { } } - Reallocate(Graphics::ImageType::Image2D, image->width, image->height, 1, filtering, wrapping); + Reallocate(Graphics::ImageType::Image2D, image->width, image->height, 1, filtering, wrapping, dedicatedMemory, usedForRenderTarget); RecreateSampler(filtering, wrapping); SetData(image->GetData()); diff --git a/src/engine/texture/Texture2DArray.cpp b/src/engine/texture/Texture2DArray.cpp index 75453701e..9266b9b5e 100644 --- a/src/engine/texture/Texture2DArray.cpp +++ b/src/engine/texture/Texture2DArray.cpp @@ -7,10 +7,10 @@ namespace Atlas { namespace Texture { Texture2DArray::Texture2DArray(int32_t width, int32_t height, int32_t layers, VkFormat format, - Wrapping wrapping, Filtering filtering) { + Wrapping wrapping, Filtering filtering, bool dedicatedMemory, bool usedForRenderTarget) { this->format = format; - Reallocate(Graphics::ImageType::Image2DArray, width, height, layers, filtering, wrapping); + Reallocate(Graphics::ImageType::Image2DArray, width, height, layers, filtering, wrapping, dedicatedMemory, usedForRenderTarget); RecreateSampler(filtering, wrapping); } @@ -59,7 +59,8 @@ namespace Atlas { if (width != this->width || height != this->height || layers != this->depth) { - Reallocate(Graphics::ImageType::Image2DArray, width, height, layers, filtering, wrapping); + Reallocate(Graphics::ImageType::Image2DArray, width, height, layers, + filtering, wrapping, dedicatedMemory, usedForRenderTarget); } diff --git a/src/engine/texture/Texture2DArray.h b/src/engine/texture/Texture2DArray.h index a1b73283b..fb279bff4 100644 --- a/src/engine/texture/Texture2DArray.h +++ b/src/engine/texture/Texture2DArray.h @@ -25,7 +25,8 @@ namespace Atlas { * @param filtering The filtering of the texture. */ Texture2DArray(int32_t width, int32_t height, int32_t layers, VkFormat format, - Wrapping wrapping = Wrapping::Repeat, Filtering filtering = Filtering::Nearest); + Wrapping wrapping = Wrapping::Repeat, Filtering filtering = Filtering::Nearest, + bool dedicatedMemory = false, bool usedForRenderTarget = false); /** * Sets the data of the texture object. diff --git a/src/engine/texture/Texture3D.cpp b/src/engine/texture/Texture3D.cpp index 179313b95..416c18f7b 100644 --- a/src/engine/texture/Texture3D.cpp +++ b/src/engine/texture/Texture3D.cpp @@ -5,10 +5,10 @@ namespace Atlas { namespace Texture { Texture3D::Texture3D(int32_t width, int32_t height, int32_t depth, VkFormat format, - Wrapping wrapping, Filtering filtering) { + Wrapping wrapping, Filtering filtering, bool dedicatedMemory, bool usedForRenderTarget) { this->format = format; - Reallocate(Graphics::ImageType::Image3D, width, height, depth, filtering, wrapping); + Reallocate(Graphics::ImageType::Image3D, width, height, depth, filtering, wrapping, dedicatedMemory, usedForRenderTarget); RecreateSampler(filtering, wrapping); } @@ -18,7 +18,8 @@ namespace Atlas { if (width != this->width || height != this->height || depth != this->depth) { - Reallocate(Graphics::ImageType::Image3D, width, height, depth, filtering, wrapping); + Reallocate(Graphics::ImageType::Image3D, width, height, depth, + filtering, wrapping, dedicatedMemory, usedForRenderTarget); } diff --git a/src/engine/texture/Texture3D.h b/src/engine/texture/Texture3D.h index 62eb820cd..a9f8362c8 100644 --- a/src/engine/texture/Texture3D.h +++ b/src/engine/texture/Texture3D.h @@ -24,7 +24,8 @@ namespace Atlas { * @param filtering The filtering of the texture. */ Texture3D(int32_t width, int32_t height, int32_t depth, VkFormat format, - Wrapping wrapping = Wrapping::Repeat, Filtering filtering = Filtering::Nearest); + Wrapping wrapping = Wrapping::Repeat, Filtering filtering = Filtering::Nearest, + bool dedicatedMemory = false, bool usedForRenderTarget = false); /** * Resizes the texture From eec229bca95ef1a0f105bbde4e6c81157f7c2bcf Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 5 Oct 2024 16:50:02 +0200 Subject: [PATCH 52/66] Fixes + reduce memory allocations --- data/shader/ddgi/probeDebug.fsh | 13 ++-- src/engine/graphics/ASBuilder.cpp | 1 + src/engine/graphics/CommandList.cpp | 12 ++-- src/engine/graphics/CommandList.h | 8 ++- src/engine/ocean/OceanSimulation.cpp | 34 +++------- src/engine/renderer/AORenderer.cpp | 58 +++++++--------- src/engine/renderer/AORenderer.h | 4 +- src/engine/renderer/AtmosphereRenderer.cpp | 9 ++- src/engine/renderer/ExampleRenderer.cpp | 5 +- src/engine/renderer/FSR2Renderer.cpp | 6 +- src/engine/renderer/GBufferRenderer.cpp | 43 ++++++------ src/engine/renderer/ImpostorRenderer.cpp | 17 ++--- src/engine/renderer/MainRenderer.cpp | 34 ++++------ src/engine/renderer/MainRenderer.h | 2 + src/engine/renderer/OceanRenderer.cpp | 27 +++----- src/engine/renderer/PathTracingRenderer.cpp | 8 +-- src/engine/renderer/PathTracingRenderer.h | 2 + src/engine/renderer/PostProcessRenderer.cpp | 28 ++++---- src/engine/renderer/RTGIRenderer.cpp | 30 ++++----- src/engine/renderer/RTReflectionRenderer.cpp | 37 ++++------ src/engine/renderer/SSGIRenderer.cpp | 55 +++++++-------- src/engine/renderer/SSGIRenderer.h | 4 +- src/engine/renderer/SkyboxRenderer.cpp | 9 ++- src/engine/renderer/TemporalAARenderer.cpp | 12 ++-- .../renderer/VolumetricCloudRenderer.cpp | 16 ++--- src/engine/renderer/VolumetricRenderer.cpp | 41 +++++------- src/engine/renderer/VolumetricRenderer.h | 4 +- .../renderer/helper/RayTracingHelper.cpp | 67 ++++++++++--------- .../renderer/helper/VegetationHelper.cpp | 48 +++++++------ src/engine/renderer/helper/VegetationHelper.h | 2 + 30 files changed, 288 insertions(+), 348 deletions(-) diff --git a/data/shader/ddgi/probeDebug.fsh b/data/shader/ddgi/probeDebug.fsh index c40eaad86..ae63d67aa 100644 --- a/data/shader/ddgi/probeDebug.fsh +++ b/data/shader/ddgi/probeDebug.fsh @@ -1,12 +1,14 @@ #include <../globals.hsh> +#include <../common/normalencode.hsh> #include layout (location = 0) out vec3 baseColorFS; -layout (location = 1) out vec3 normalFS; -layout (location = 2) out vec3 geometryNormalFS; +layout (location = 1) out vec2 normalFS; +layout (location = 2) out vec2 geometryNormalFS; layout (location = 3) out vec3 roughnessMetalnessAoFS; -layout (location = 4) out uint materialIdxFS; -layout (location = 5) out vec2 velocityFS; +layout (location = 4) out vec3 emissiveFS; +layout (location = 5) out uint materialIdxFS; +layout (location = 6) out vec2 velocityFS; layout(location=0) in vec3 normalVS; @@ -42,8 +44,7 @@ void main() { baseColorFS = vec3(probeAge / 32.0); //baseColorFS = vec3(moments.x) / length(ddgiData.cascades[probeCascadeIndex].cellSize.xyz); - geometryNormalFS = normalize(normalVS); - geometryNormalFS = 0.5 * geometryNormalFS + 0.5; + geometryNormalFS = EncodeNormal(normalize(normalVS)); float roughnessFactor = 1.0; float metalnessFactor = 1.0; diff --git a/src/engine/graphics/ASBuilder.cpp b/src/engine/graphics/ASBuilder.cpp index fb41afbdb..50c5ed751 100644 --- a/src/engine/graphics/ASBuilder.cpp +++ b/src/engine/graphics/ASBuilder.cpp @@ -82,6 +82,7 @@ namespace Atlas { size_t batchSizeLimit = 256000000; std::vector batchIndices; + batchIndices.reserve(blases.size()); for (size_t i = 0; i < blases.size(); i++) { batchIndices.push_back(uint32_t(i)); diff --git a/src/engine/graphics/CommandList.cpp b/src/engine/graphics/CommandList.cpp index f5c2885ad..1feff64c6 100644 --- a/src/engine/graphics/CommandList.cpp +++ b/src/engine/graphics/CommandList.cpp @@ -493,7 +493,7 @@ namespace Atlas { } - void CommandList::BindBuffers(const std::vector> &buffers, uint32_t set, uint32_t binding) { + void CommandList::BindBuffers(const std::span> buffers, uint32_t set, uint32_t binding) { AE_ASSERT(set < DESCRIPTOR_SET_COUNT && "Descriptor set not allowed for use"); AE_ASSERT(binding < BINDINGS_PER_DESCRIPTOR_SET && "The binding point is not allowed for use"); @@ -501,7 +501,8 @@ namespace Atlas { if (!buffers.size()) return; std::vector buffersPtr; - for (auto& buffer : buffers) { + buffersPtr.reserve(buffers.size()); + for (const auto& buffer : buffers) { AE_ASSERT(buffer->size > 0 && "Invalid buffer size"); AE_ASSERT(buffer->usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT && "Only storage buffers support array bindings"); @@ -592,7 +593,7 @@ namespace Atlas { } - void CommandList::BindSampledImages(const std::vector>& images, uint32_t set, uint32_t binding) { + void CommandList::BindSampledImages(const std::span> images, uint32_t set, uint32_t binding) { AE_ASSERT(set < DESCRIPTOR_SET_COUNT && "Descriptor set not allowed for use"); AE_ASSERT(binding < BINDINGS_PER_DESCRIPTOR_SET && "The binding point is not allowed for use"); @@ -600,6 +601,7 @@ namespace Atlas { if (!images.size()) return; std::vector imagesPtr; + imagesPtr.reserve(images.size()); for (const auto& image : images) imagesPtr.push_back(image.get()); descriptorBindingData.ResetBinding(set, binding); @@ -743,8 +745,8 @@ namespace Atlas { } - void CommandList::PipelineBarrier(std::vector& imageBarriers, - std::vector& bufferBarriers, VkPipelineStageFlags srcStageMask, + void CommandList::PipelineBarrier(std::span imageBarriers, + std::span bufferBarriers, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) { // Not so sure about the cost of these vector allocations on the heap diff --git a/src/engine/graphics/CommandList.h b/src/engine/graphics/CommandList.h index 27badaca7..f01101282 100644 --- a/src/engine/graphics/CommandList.h +++ b/src/engine/graphics/CommandList.h @@ -15,7 +15,9 @@ #include "../common/Ref.h" #include +#include #include +#include namespace Atlas { @@ -89,7 +91,7 @@ namespace Atlas { void BindBufferOffset(const Ref& buffer, size_t offset, uint32_t set, uint32_t binding); - void BindBuffers(const std::vector>& buffers, uint32_t set, uint32_t binding); + void BindBuffers(const std::span> buffers, uint32_t set, uint32_t binding); void BindBuffer(const Ref& buffer, uint32_t set, uint32_t binding); @@ -99,7 +101,7 @@ namespace Atlas { void BindImage(const Ref& image, const Ref& sampler, uint32_t set, uint32_t binding); - void BindSampledImages(const std::vector>& images, uint32_t set, uint32_t binding); + void BindSampledImages(const std::span> images, uint32_t set, uint32_t binding); void BindSampler(const Ref& sampler, uint32_t set, uint32_t binding); @@ -135,7 +137,7 @@ namespace Atlas { void PipelineBarrier(VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - void PipelineBarrier(std::vector& imageBarriers, std::vector& bufferBarriers, + void PipelineBarrier(std::span imageBarriers, std::span bufferBarriers, VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); diff --git a/src/engine/ocean/OceanSimulation.cpp b/src/engine/ocean/OceanSimulation.cpp index 646fedaa1..ff7b86584 100644 --- a/src/engine/ocean/OceanSimulation.cpp +++ b/src/engine/ocean/OceanSimulation.cpp @@ -188,14 +188,11 @@ namespace Atlas { }; commandList->PushConstants("constants", &constants); - std::vector imageBarriers; - std::vector bufferBarriers; - - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {hTD.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {h0K.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(hTD.image, 3, 0); commandList->BindImage(h0K.image, 3, 1); @@ -232,29 +229,26 @@ namespace Atlas { commandList->BindPipeline(pipeline); - std::vector imageBarriers; - std::vector bufferBarriers; - for (int32_t i = 0; i < log2n; i++) { if (!pingpong) { - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {hTD.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT}, {hTDPingpong.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} }; commandList->BindImage(hTD.image, 3, 1); commandList->BindImage(hTDPingpong.image, 3, 2); + commandList->PipelineBarrier(imageBarriers, {}); } else { - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {hTD.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {hTDPingpong.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT} }; commandList->BindImage(hTDPingpong.image, 3, 1); commandList->BindImage(hTD.image, 3, 2); - } - - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); + } auto preTwiddle = (float)N / powf(2.0f, (float)i + 1.0f); @@ -288,14 +282,11 @@ namespace Atlas { image = hTDPingpong.image; } - std::vector imageBarriers; - std::vector bufferBarriers; - - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {displacementMap.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(displacementMap.image, 3, 0); commandList->BindImage(image, 3, 1); @@ -342,14 +333,11 @@ namespace Atlas { }; commandList->PushConstants("constants", &constants); - std::vector imageBarriers; - std::vector bufferBarriers; - - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {displacementMap.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT}, {normalMap.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(displacementMap.image, 3, 0); commandList->BindImage(normalMap.image, 3, 1); diff --git a/src/engine/renderer/AORenderer.cpp b/src/engine/renderer/AORenderer.cpp index 13db76bd1..a3d1f4888 100644 --- a/src/engine/renderer/AORenderer.cpp +++ b/src/engine/renderer/AORenderer.cpp @@ -10,9 +10,16 @@ namespace Atlas { this->device = device; - const int32_t filterSize = 4; blurFilter.CalculateGaussianFilter(float(filterSize) / 3.0f, filterSize); + std::vector blurKernelWeights; + std::vector blurKernelOffsets; + blurFilter.GetLinearized(&blurKernelWeights, &blurKernelOffsets, false); + + auto mean = (blurKernelWeights.size() - 1) / 2; + blurKernelWeights = std::vector(blurKernelWeights.begin() + mean, blurKernelWeights.end()); + blurKernelOffsets = std::vector(blurKernelOffsets.begin() + mean, blurKernelOffsets.end()); + auto noiseImage = Loader::ImageLoader::LoadImage("scrambling_ranking.png", false, 4); scramblingRankingTexture = Texture::Texture2D(noiseImage->width, noiseImage->height, VK_FORMAT_R8G8B8A8_UNORM); @@ -36,7 +43,8 @@ namespace Atlas { ssUniformBuffer = Buffer::UniformBuffer(sizeof(SSUniforms)); // If we don't set the element size to the whole thing, otherwise uniform buffer element alignment kicks in ssSamplesUniformBuffer = Buffer::UniformBuffer(sizeof(vec4) * 64); - blurWeightsUniformBuffer = Buffer::UniformBuffer(sizeof(float) * (size_t(filterSize) + 1)); + blurWeightsUniformBuffer = Buffer::Buffer(Buffer::BufferUsageBits::UniformBufferBit, + sizeof(float) * (size_t(filterSize) + 1), 1, blurKernelWeights.data()); } @@ -56,12 +64,12 @@ namespace Atlas { if (!target->HasHistory()) { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + + Graphics::ImageBarrier imageBarriers[] = { {target->historyAoTexture.image, layout, access}, {target->historyAoLengthTexture.image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); } auto downsampledRT = target->GetData(target->GetAOResolution()); @@ -158,9 +166,6 @@ namespace Atlas { if (ao->rt) { Graphics::Profiler::EndAndBeginQuery("Temporal filter"); - std::vector imageBarriers; - std::vector bufferBarriers; - ivec2 groupCount = ivec2(res.x / 16, res.y / 16); groupCount.x += ((groupCount.x * 16 == res.x) ? 0 : 1); groupCount.y += ((groupCount.y * 16 == res.y) ? 0 : 1); @@ -168,11 +173,11 @@ namespace Atlas { auto pipeline = PipelineManager::GetPipeline(temporalPipelineConfig); commandList->BindPipeline(pipeline); - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->aoTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {target->aoLengthTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(target->aoTexture.image, 3, 0); commandList->BindImage(target->aoLengthTexture.image, 3, 1); @@ -196,26 +201,26 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier preCopyImageBarriers[] = { {target->aoTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->aoLengthTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->historyAoTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, {target->historyAoLengthTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preCopyImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->CopyImage(target->aoTexture.image, target->historyAoTexture.image); commandList->CopyImage(target->aoLengthTexture.image, target->historyAoLengthTexture.image); // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier postCopyImageBarriers[] = { {target->aoTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->aoLengthTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyAoTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyAoLengthTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postCopyImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); } @@ -224,37 +229,24 @@ namespace Atlas { const int32_t groupSize = 256; - std::vector kernelWeights; - std::vector kernelOffsets; - - blurFilter.GetLinearized(&kernelWeights, &kernelOffsets, false); - - auto mean = (kernelWeights.size() - 1) / 2; - kernelWeights = std::vector(kernelWeights.begin() + mean, kernelWeights.end()); - kernelOffsets = std::vector(kernelOffsets.begin() + mean, kernelOffsets.end()); - - auto kernelSize = int32_t(kernelWeights.size() - 1); + auto kernelSize = int32_t(filterSize); auto horizontalBlurPipeline = PipelineManager::GetPipeline(horizontalBlurPipelineConfig); auto verticalBlurPipeline = PipelineManager::GetPipeline(verticalBlurPipelineConfig); - blurWeightsUniformBuffer.SetData(kernelWeights.data(), 0); - commandList->BindImage(depthTexture->image, depthTexture->sampler, 3, 2); commandList->BindImage(normalTexture->image, normalTexture->sampler, 3, 3); commandList->BindBuffer(blurWeightsUniformBuffer.Get(), 3, 4); - std::vector imageBarriers; - std::vector bufferBarriers; - for (int32_t i = 0; i < 3; i++) { ivec2 groupCount = ivec2(res.x / groupSize, res.y); groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); - imageBarriers = { + + Graphics::ImageBarrier horizImageBarriers[] = { {target->aoTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->swapAoTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(horizImageBarriers, {}); commandList->BindPipeline(horizontalBlurPipeline); commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); @@ -267,11 +259,11 @@ namespace Atlas { groupCount = ivec2(res.x, res.y / groupSize); groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - imageBarriers = { + Graphics::ImageBarrier vertImageBarriers[] = { {target->swapAoTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->aoTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(vertImageBarriers, {}); commandList->BindPipeline(verticalBlurPipeline); commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); diff --git a/src/engine/renderer/AORenderer.h b/src/engine/renderer/AORenderer.h index 23c04c5ca..4afde5683 100644 --- a/src/engine/renderer/AORenderer.h +++ b/src/engine/renderer/AORenderer.h @@ -46,7 +46,9 @@ namespace Atlas { Buffer::UniformBuffer rtUniformBuffer; Buffer::UniformBuffer ssUniformBuffer; Buffer::UniformBuffer ssSamplesUniformBuffer; - Buffer::UniformBuffer blurWeightsUniformBuffer; + Buffer::Buffer blurWeightsUniformBuffer; + + const int32_t filterSize = 4; }; diff --git a/src/engine/renderer/AtmosphereRenderer.cpp b/src/engine/renderer/AtmosphereRenderer.cpp index eb3502145..0ecb8c3a2 100644 --- a/src/engine/renderer/AtmosphereRenderer.cpp +++ b/src/engine/renderer/AtmosphereRenderer.cpp @@ -55,12 +55,11 @@ namespace Atlas { }; uniformBuffer.SetData(&uniforms, 0); - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {velocityTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(preImageBarriers, {}); commandList->BindImage(target->lightingTexture.image, 3, 0); commandList->BindImage(velocityTexture->image, 3, 1); @@ -76,11 +75,11 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->lightingTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {velocityTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); Graphics::Profiler::EndQuery(); diff --git a/src/engine/renderer/ExampleRenderer.cpp b/src/engine/renderer/ExampleRenderer.cpp index 5ad5b3a08..a727a6fdd 100644 --- a/src/engine/renderer/ExampleRenderer.cpp +++ b/src/engine/renderer/ExampleRenderer.cpp @@ -235,12 +235,11 @@ namespace Atlas { Graphics::Profiler::EndAndBeginQuery("Copy image"); { - auto imageBarriers = std::vector { + Graphics::ImageBarrier imageBarriers[] = { {destinationImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, {mainFrameBuffer->GetColorImage(0), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT} }; - auto bufferBarriers = std::vector(); - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); // Copy to other image diff --git a/src/engine/renderer/FSR2Renderer.cpp b/src/engine/renderer/FSR2Renderer.cpp index 71081e545..15c905d2c 100644 --- a/src/engine/renderer/FSR2Renderer.cpp +++ b/src/engine/renderer/FSR2Renderer.cpp @@ -831,10 +831,8 @@ namespace Atlas::Renderer { auto& taa = scene->postProcessing.taa; - std::vector bufferBarriers; - std::vector imageBarriers; - imageBarriers.push_back({ outputImage,VK_IMAGE_LAYOUT_GENERAL,VK_ACCESS_SHADER_WRITE_BIT }); - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + Graphics::ImageBarrier imageBarriers[] = {{outputImage,VK_IMAGE_LAYOUT_GENERAL,VK_ACCESS_SHADER_WRITE_BIT}}; + commandList->PipelineBarrier(imageBarriers, {}); FfxFsr2DispatchDescription dispatchParameters = {}; dispatchParameters.commandList = commandList; diff --git a/src/engine/renderer/GBufferRenderer.cpp b/src/engine/renderer/GBufferRenderer.cpp index 117830b13..1d2e364c2 100644 --- a/src/engine/renderer/GBufferRenderer.cpp +++ b/src/engine/renderer/GBufferRenderer.cpp @@ -144,17 +144,17 @@ namespace Atlas { commandList->BindImage(velocityIn->image, velocityIn->sampler, 3 , 4); commandList->BindImage(materialIdxIn->image, materialIdxIn->sampler, 3 , 5); - std::vector imageBarriers; - std::vector bufferBarriers; - imageBarriers.push_back({depthOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}); - imageBarriers.push_back({normalOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}); - imageBarriers.push_back({geometryNormalOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}); - imageBarriers.push_back({roughnessMetallicAoOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}); - imageBarriers.push_back({velocityOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}); - imageBarriers.push_back({materialIdxOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}); - imageBarriers.push_back({offsetOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}); - - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + Graphics::ImageBarrier preImageBarriers[] = { + {depthOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + {normalOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + {geometryNormalOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + {roughnessMetallicAoOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + {velocityOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + {materialIdxOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, + {offsetOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} + }; + + commandList->PipelineBarrier(preImageBarriers, {}); commandList->BindImage(depthOut->image, 3 , 6); commandList->BindImage(normalOut->image, 3 , 7); @@ -166,16 +166,17 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); - imageBarriers.clear(); - imageBarriers.push_back({depthOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}); - imageBarriers.push_back({normalOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}); - imageBarriers.push_back({geometryNormalOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}); - imageBarriers.push_back({roughnessMetallicAoOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}); - imageBarriers.push_back({velocityOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}); - imageBarriers.push_back({materialIdxOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}); - imageBarriers.push_back({offsetOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}); - - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + Graphics::ImageBarrier postImageBarriers[] = { + {depthOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {normalOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {geometryNormalOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {roughnessMetallicAoOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {velocityOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {materialIdxOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {offsetOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT} + }; + + commandList->PipelineBarrier(postImageBarriers, {}); } diff --git a/src/engine/renderer/ImpostorRenderer.cpp b/src/engine/renderer/ImpostorRenderer.cpp index 02fca947a..e947af02e 100644 --- a/src/engine/renderer/ImpostorRenderer.cpp +++ b/src/engine/renderer/ImpostorRenderer.cpp @@ -102,19 +102,17 @@ namespace Atlas { { // Transfer all framebuffer images including all mips into same layout/access as end of render pass - std::vector imageBarriers; - std::vector bufferBarriers; VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {impostor->baseColorTexture.image, layout, access}, {impostor->normalTexture.image, layout, access}, {impostor->roughnessMetalnessAoTexture.image, layout, access}, {impostor->depthTexture.image, layout, access}, {frameBuffer->GetDepthImage(), layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); } @@ -175,18 +173,15 @@ namespace Atlas { } { - std::vector imageBarriers; - std::vector bufferBarriers; - VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; VkAccessFlags access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {impostor->baseColorTexture.image, layout, access}, {impostor->normalTexture.image, layout, access}, {impostor->roughnessMetalnessAoTexture.image, layout, access}, {impostor->depthTexture.image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); commandList->GenerateMipMaps(impostor->baseColorTexture.image); @@ -194,13 +189,13 @@ namespace Atlas { commandList->GenerateMipMaps(impostor->roughnessMetalnessAoTexture.image); commandList->GenerateMipMaps(impostor->depthTexture.image); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {impostor->baseColorTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {impostor->normalTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {impostor->roughnessMetalnessAoTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {impostor->depthTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); } diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 2e2279399..27211e9e9 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -176,10 +176,8 @@ namespace Atlas { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers; - auto lightSubset = scene->GetSubset(); + shadowImageBarriers.clear(); for (auto& lightEntity : lightSubset) { auto& light = lightEntity.GetComponent(); @@ -187,11 +185,11 @@ namespace Atlas { continue; auto shadow = light.shadow; - imageBarriers.push_back({ shadow->useCubemap ? + shadowImageBarriers.push_back({ shadow->useCubemap ? shadow->cubemap->image : shadow->maps->image, layout, access }); } - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + commandList->PipelineBarrier(shadowImageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); @@ -241,8 +239,7 @@ namespace Atlas { auto rtData = target->GetHistoryData(FULL_RES); VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {rtData->baseColorTexture->image, layout, access}, {rtData->depthTexture->image, layout, access}, {rtData->normalTexture->image, layout, access}, @@ -264,7 +261,7 @@ namespace Atlas { {rtHalfData->stencilTexture->image, layout, access}, {rtHalfData->velocityTexture->image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); } { @@ -273,8 +270,7 @@ namespace Atlas { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {rtData->baseColorTexture->image, layout, access}, {rtData->depthTexture->image, layout, access}, {rtData->normalTexture->image, layout, access}, @@ -289,7 +285,7 @@ namespace Atlas { {target->oceanDepthTexture.image, layout, access} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } { @@ -356,16 +352,14 @@ namespace Atlas { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->lightingTexture.image, layout, access}, {rtData->depthTexture->image, layout, access}, {rtData->velocityTexture->image, layout, access}, {rtData->stencilTexture->image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); - + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } { @@ -554,14 +548,12 @@ namespace Atlas { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->lightingTexture.image, layout, access}, {rtData->depthTexture->image, layout, access}, {rtData->velocityTexture->image, layout, access}, }; - - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); commandList->BeginRenderPass(target->afterLightingRenderPass, target->afterLightingFrameBuffer); @@ -599,13 +591,13 @@ namespace Atlas { commandList->EndRenderPass(); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->lightingTexture.image, layout, access}, {rtData->depthTexture->image, layout, access}, {rtData->velocityTexture->image, layout, access}, {rtData->stencilTexture->image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); if (localCommandList) { diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index e1ef0aa9a..1b702f22d 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -122,6 +122,8 @@ namespace Atlas { size_t haltonIndex = 0; uint32_t frameCount = 0; + std::vector shadowImageBarriers; + }; } diff --git a/src/engine/renderer/OceanRenderer.cpp b/src/engine/renderer/OceanRenderer.cpp index a55dc7ad5..51236c1fd 100644 --- a/src/engine/renderer/OceanRenderer.cpp +++ b/src/engine/renderer/OceanRenderer.cpp @@ -177,28 +177,25 @@ namespace Atlas { depthImage->format); } - std::vector imageBarriers; - std::vector bufferBarriers; - - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {depthImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {refractionTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, {depthTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->CopyImage(colorImage, refractionTexture.image); commandList->CopyImage(depthImage, depthTexture.image); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {colorImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {depthImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {refractionTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {depthTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } @@ -344,15 +341,14 @@ namespace Atlas { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->lightingTexture.image, layout, access}, {rtData->depthTexture->image, layout, access}, {rtData->stencilTexture->image, layout, access}, {rtData->velocityTexture->image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } if (ocean->underwaterShader) { @@ -360,23 +356,20 @@ namespace Atlas { auto& colorImage = target->afterLightingFrameBuffer->GetColorImage(0); - std::vector imageBarriers; - std::vector bufferBarriers; - - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {refractionTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->CopyImage(colorImage, refractionTexture.image); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {colorImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {refractionTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); const int32_t groupSize = 8; diff --git a/src/engine/renderer/PathTracingRenderer.cpp b/src/engine/renderer/PathTracingRenderer.cpp index ef35e42c8..7beb40c50 100644 --- a/src/engine/renderer/PathTracingRenderer.cpp +++ b/src/engine/renderer/PathTracingRenderer.cpp @@ -99,9 +99,7 @@ namespace Atlas { rayHitUniformBuffer.SetData(&uniforms, i); } - std::vector imageBarriers; - std::vector bufferBarriers; - + imageBarriers.clear(); imageBarriers.push_back({ renderTarget->outputTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT }); imageBarriers.push_back({ renderTarget->radianceTexture.image, @@ -157,7 +155,7 @@ namespace Atlas { commandList->BindImage(baseColorTexture->image, 3, 9); } - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); auto tileResolution = resolution / imageSubdivisions; auto groupCount = tileResolution / 8; @@ -232,7 +230,7 @@ namespace Atlas { imageBarriers.push_back({ historyMaterialIdxTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT }); - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); velocityTexture->Bind(commandList, 3, 4); depthTexture->Bind(commandList, 3, 5); diff --git a/src/engine/renderer/PathTracingRenderer.h b/src/engine/renderer/PathTracingRenderer.h index 463f18afa..10890059c 100644 --- a/src/engine/renderer/PathTracingRenderer.h +++ b/src/engine/renderer/PathTracingRenderer.h @@ -84,6 +84,8 @@ namespace Atlas { size_t frameCount = 0; + std::vector imageBarriers; + }; } diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index eb57a9238..a66f4b175 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -215,12 +215,11 @@ namespace Atlas { resolution /= 2; for (int32_t i = 1; i < mipLevels; i++) { - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {textureIn->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {textureOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); ivec2 groupCount = resolution / 16; groupCount.x += ((groupCount.x * 16 == resolution.x) ? 0 : 1); @@ -261,13 +260,11 @@ namespace Atlas { commandList->BindPipeline(pipeline); for (int32_t i = mipLevels - 2; i >= 0; i--) { - - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {textureIn->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {textureOut->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); ivec2 groupCount = resolutions[i] / 8; groupCount.x += ((groupCount.x * 8 == resolutions[i].x) ? 0 : 1); @@ -292,6 +289,12 @@ namespace Atlas { Graphics::Profiler::EndQuery(); } + Graphics::ImageBarrier imageBarriers[] = { + {textureIn->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, + {textureOut->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT} + }; + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + } void PostProcessRenderer::CopyToTexture(Texture::Texture2D* sourceTexture, Texture::Texture2D *texture, @@ -300,23 +303,20 @@ namespace Atlas { auto& srcImage = sourceTexture->image; auto& dstImage = texture->image; - std::vector imageBarriers; - std::vector bufferBarriers; - - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->BlitImage(srcImage, dstImage); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {srcImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {dstImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); } diff --git a/src/engine/renderer/RTGIRenderer.cpp b/src/engine/renderer/RTGIRenderer.cpp index 092b0c969..294fd2c05 100644 --- a/src/engine/renderer/RTGIRenderer.cpp +++ b/src/engine/renderer/RTGIRenderer.cpp @@ -61,12 +61,11 @@ namespace Atlas { target->historyGiMomentsTexture.image->layout == VK_IMAGE_LAYOUT_UNDEFINED) { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->historyGiTexture.image, layout, access}, {target->historyGiMomentsTexture.image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); } Graphics::Profiler::BeginQuery("Trace rays"); @@ -183,9 +182,6 @@ namespace Atlas { Graphics::Profiler::EndAndBeginQuery("Temporal filter"); { - std::vector imageBarriers; - std::vector bufferBarriers; - ivec2 groupCount = ivec2(res.x / 16, res.y / 16); groupCount.x += ((groupCount.x * 16 == res.x) ? 0 : 1); groupCount.y += ((groupCount.y * 16 == res.y) ? 0 : 1); @@ -202,12 +198,12 @@ namespace Atlas { commandList->PushConstants("constants", &constants); - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->giTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->swapGiTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {target->giMomentsTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(target->swapGiTexture.image, 3, 0); commandList->BindImage(target->giMomentsTexture.image, 3, 1); @@ -228,30 +224,27 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); } - std::vector imageBarriers; - std::vector bufferBarriers; - // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->swapGiTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->giMomentsTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->historyGiTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, {target->historyGiMomentsTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->CopyImage(target->swapGiTexture.image, target->historyGiTexture.image); commandList->CopyImage(target->giMomentsTexture.image, target->historyGiMomentsTexture.image); // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->swapGiTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->giMomentsTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyGiTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyGiMomentsTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); Graphics::Profiler::EndAndBeginQuery("Spatial filter"); @@ -281,22 +274,23 @@ namespace Atlas { commandList->PushConstants("constants", &constants); if (pingpong) { - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->giTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->swapGiTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; commandList->BindImage(target->swapGiTexture.image, 3, 0); commandList->BindImage(target->giTexture.image, target->giTexture.sampler, 3, 1); + commandList->PipelineBarrier(imageBarriers, {}); } else { - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->swapGiTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->giTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; commandList->BindImage(target->giTexture.image, 3, 0); commandList->BindImage(target->swapGiTexture.image, target->swapGiTexture.sampler, 3, 1); + commandList->PipelineBarrier(imageBarriers, {}); } - commandList->PipelineBarrier(imageBarriers, bufferBarriers); pingpong = !pingpong; diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index d4d1a4eff..02345cca9 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -60,12 +60,11 @@ namespace Atlas { target->historyReflectionMomentsTexture.image->layout == VK_IMAGE_LAYOUT_UNDEFINED) { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->historyReflectionTexture.image, layout, access}, {target->historyReflectionMomentsTexture.image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); } Graphics::Profiler::BeginQuery("Trace rays"); @@ -178,9 +177,6 @@ namespace Atlas { if (reflection->upsampleBeforeFiltering) { Graphics::Profiler::EndAndBeginQuery("Upscaling"); - std::vector imageBarriers; - std::vector bufferBarriers; - ivec2 groupCount = ivec2(res.x / 8, res.y / 8); groupCount.x += ((groupCount.x * 8 == res.x) ? 0 : 1); groupCount.y += ((groupCount.y * 8 == res.y) ? 0 : 1); @@ -188,11 +184,11 @@ namespace Atlas { auto pipeline = PipelineManager::GetPipeline(upsamplePipelineConfig); commandList->BindPipeline(pipeline); - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {reflectionTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {swapReflectionTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(swapReflectionTexture->image, 3, 0); @@ -226,9 +222,6 @@ namespace Atlas { Graphics::Profiler::EndAndBeginQuery("Temporal filter"); { - std::vector imageBarriers; - std::vector bufferBarriers; - ivec2 groupCount = ivec2(res.x / 16, res.y / 16); groupCount.x += ((groupCount.x * 16 == res.x) ? 0 : 1); groupCount.y += ((groupCount.y * 16 == res.y) ? 0 : 1); @@ -245,12 +238,12 @@ namespace Atlas { commandList->PushConstants("constants", &constants); - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {reflectionTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {swapReflectionTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {target->reflectionMomentsTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(swapReflectionTexture->image, 3, 0); commandList->BindImage(target->reflectionMomentsTexture.image, 3, 1); @@ -271,30 +264,27 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); } - std::vector imageBarriers; - std::vector bufferBarriers; - // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {swapReflectionTexture->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->reflectionMomentsTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->historyReflectionTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, {target->historyReflectionMomentsTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->CopyImage(swapReflectionTexture->image, target->historyReflectionTexture.image); commandList->CopyImage(target->reflectionMomentsTexture.image, target->historyReflectionMomentsTexture.image); // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {swapReflectionTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->reflectionMomentsTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyReflectionTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyReflectionMomentsTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); Graphics::Profiler::EndAndBeginQuery("Spatial filter"); @@ -324,22 +314,23 @@ namespace Atlas { commandList->PushConstants("constants", &constants); if (pingpong) { - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {reflectionTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {swapReflectionTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; commandList->BindImage(swapReflectionTexture->image, 3, 0); commandList->BindImage(reflectionTexture->image, reflectionTexture->sampler, 3, 1); + commandList->PipelineBarrier(imageBarriers, {}); } else { - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {swapReflectionTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {reflectionTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; commandList->BindImage(reflectionTexture->image, 3, 0); commandList->BindImage(swapReflectionTexture->image, swapReflectionTexture->sampler, 3, 1); + commandList->PipelineBarrier(imageBarriers, {}); } - commandList->PipelineBarrier(imageBarriers, bufferBarriers); pingpong = !pingpong; diff --git a/src/engine/renderer/SSGIRenderer.cpp b/src/engine/renderer/SSGIRenderer.cpp index 8b88da14e..d189f980c 100644 --- a/src/engine/renderer/SSGIRenderer.cpp +++ b/src/engine/renderer/SSGIRenderer.cpp @@ -11,9 +11,16 @@ namespace Atlas { this->device = device; - const int32_t filterSize = 3; blurFilter.CalculateBoxFilter(filterSize); + std::vector blurKernelWeights; + std::vector blurKernelOffsets; + blurFilter.GetLinearized(&blurKernelWeights, &blurKernelOffsets, false); + + auto mean = (blurKernelWeights.size() - 1) / 2; + blurKernelWeights = std::vector(blurKernelWeights.begin() + mean, blurKernelWeights.end()); + blurKernelOffsets = std::vector(blurKernelOffsets.begin() + mean, blurKernelOffsets.end()); + auto noiseImage = Loader::ImageLoader::LoadImage("scrambling_ranking.png", false, 4); scramblingRankingTexture = Texture::Texture2D(noiseImage->width, noiseImage->height, VK_FORMAT_R8G8B8A8_UNORM); @@ -34,7 +41,8 @@ namespace Atlas { ssUniformBuffer = Buffer::UniformBuffer(sizeof(SSUniforms)); // If we don't set the element size to the whole thing, otherwise uniform buffer element alignment kicks in - blurWeightsUniformBuffer = Buffer::UniformBuffer(sizeof(float) * (size_t(filterSize) + 1)); + blurWeightsUniformBuffer = Buffer::Buffer(Buffer::BufferUsageBits::UniformBufferBit, + sizeof(float) * (size_t(filterSize) + 1), 1, blurKernelWeights.data()); } @@ -59,12 +67,11 @@ namespace Atlas { target->historyGiLengthTexture.image->layout == VK_IMAGE_LAYOUT_UNDEFINED) { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->historyGiTexture.image, layout, access}, {target->historyGiLengthTexture.image, layout, access}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); } // Try to get a shadow map @@ -140,9 +147,6 @@ namespace Atlas { { Graphics::Profiler::EndAndBeginQuery("Temporal filter"); - std::vector imageBarriers; - std::vector bufferBarriers; - ivec2 groupCount = ivec2(res.x / 8, res.y / 8); groupCount.x += ((groupCount.x * 8 == res.x) ? 0 : 1); groupCount.y += ((groupCount.y * 8 == res.y) ? 0 : 1); @@ -150,13 +154,13 @@ namespace Atlas { auto pipeline = PipelineManager::GetPipeline(temporalPipelineConfig); commandList->BindPipeline(pipeline); - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->giTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {target->giLengthTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {target->historyGiTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyGiLengthTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(target->giTexture.image, 3, 0); commandList->BindImage(target->giLengthTexture.image, 3, 1); @@ -180,26 +184,26 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->giTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->giLengthTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->historyGiTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, {target->historyGiLengthTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT} }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->CopyImage(target->giTexture.image, target->historyGiTexture.image); commandList->CopyImage(target->giLengthTexture.image, target->historyGiLengthTexture.image); // Need barriers for all four images - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->giTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->giLengthTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyGiTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyGiLengthTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); } @@ -209,37 +213,24 @@ namespace Atlas { const int32_t groupSize = 256; - std::vector kernelWeights; - std::vector kernelOffsets; - - blurFilter.GetLinearized(&kernelWeights, &kernelOffsets, false); - - auto mean = (kernelWeights.size() - 1) / 2; - kernelWeights = std::vector(kernelWeights.begin() + mean, kernelWeights.end()); - kernelOffsets = std::vector(kernelOffsets.begin() + mean, kernelOffsets.end()); - - auto kernelSize = int32_t(kernelWeights.size() - 1); + auto kernelSize = int32_t(filterSize); auto horizontalBlurPipeline = PipelineManager::GetPipeline(horizontalBlurPipelineConfig); auto verticalBlurPipeline = PipelineManager::GetPipeline(verticalBlurPipelineConfig); - blurWeightsUniformBuffer.SetData(kernelWeights.data(), 0); - commandList->BindImage(depthTexture->image, depthTexture->sampler, 3, 2); commandList->BindImage(normalTexture->image, normalTexture->sampler, 3, 3); commandList->BindBuffer(blurWeightsUniformBuffer.Get(), 3, 4); - std::vector bufferBarriers; - for (int32_t i = 0; i < 3; i++) { ivec2 groupCount = ivec2(res.x / groupSize, res.y); groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); - std::vector imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->giTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->swapGiTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(preImageBarriers, {}); commandList->BindPipeline(horizontalBlurPipeline); commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); @@ -252,11 +243,11 @@ namespace Atlas { groupCount = ivec2(res.x, res.y / groupSize); groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->swapGiTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->giTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(postImageBarriers, {}); commandList->BindPipeline(verticalBlurPipeline); commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); diff --git a/src/engine/renderer/SSGIRenderer.h b/src/engine/renderer/SSGIRenderer.h index 335f08ebe..1043197ef 100644 --- a/src/engine/renderer/SSGIRenderer.h +++ b/src/engine/renderer/SSGIRenderer.h @@ -40,7 +40,9 @@ namespace Atlas { PipelineConfig verticalBlurPipelineConfig; Buffer::UniformBuffer ssUniformBuffer; - Buffer::UniformBuffer blurWeightsUniformBuffer; + Buffer::Buffer blurWeightsUniformBuffer; + + const int32_t filterSize = 3; }; diff --git a/src/engine/renderer/SkyboxRenderer.cpp b/src/engine/renderer/SkyboxRenderer.cpp index 4931f5163..82d8598c4 100644 --- a/src/engine/renderer/SkyboxRenderer.cpp +++ b/src/engine/renderer/SkyboxRenderer.cpp @@ -25,12 +25,11 @@ namespace Atlas { auto velocityTexture = rtData->velocityTexture; auto depthTexture = rtData->depthTexture; - std::vector bufferBarriers; - std::vector imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, {velocityTexture->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(preImageBarriers, {}); vec4 lastCameraLocation = vec4(camera.GetLastLocation(), 1.0f); commandList->PushConstants("constants", &lastCameraLocation); @@ -50,11 +49,11 @@ namespace Atlas { commandList->Dispatch(groupCount.x, groupCount.y, 1); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->lightingTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {velocityTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); Graphics::Profiler::EndQuery(); diff --git a/src/engine/renderer/TemporalAARenderer.cpp b/src/engine/renderer/TemporalAARenderer.cpp index 44c8e62b6..d0211ade6 100644 --- a/src/engine/renderer/TemporalAARenderer.cpp +++ b/src/engine/renderer/TemporalAARenderer.cpp @@ -43,12 +43,12 @@ namespace Atlas { const auto depth = targetData->depthTexture; const auto stencil = targetData->stencilTexture; - std::vector bufferBarriers; - std::vector imageBarriers; - imageBarriers.push_back({lastHistory->image,VK_IMAGE_LAYOUT_GENERAL,VK_ACCESS_SHADER_WRITE_BIT}); - imageBarriers.push_back({history->image,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,VK_ACCESS_SHADER_READ_BIT}); - imageBarriers.push_back({lastVelocity->image,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,VK_ACCESS_SHADER_READ_BIT}); - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + Graphics::ImageBarrier imageBarriers[] = { + {lastHistory->image,VK_IMAGE_LAYOUT_GENERAL,VK_ACCESS_SHADER_WRITE_BIT}, + {history->image,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,VK_ACCESS_SHADER_READ_BIT}, + {lastVelocity->image,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,VK_ACCESS_SHADER_READ_BIT} + }; + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(lastHistory->image, 3, 0); diff --git a/src/engine/renderer/VolumetricCloudRenderer.cpp b/src/engine/renderer/VolumetricCloudRenderer.cpp index f07d6aac4..b64f5f3ba 100644 --- a/src/engine/renderer/VolumetricCloudRenderer.cpp +++ b/src/engine/renderer/VolumetricCloudRenderer.cpp @@ -68,9 +68,6 @@ namespace Atlas { auto velocityTexture = downsampledRT->velocityTexture; auto historyDepthTexture = downsampledHistoryRT->depthTexture; - - std::vector bufferBarriers; - std::vector imageBarriers; { Graphics::Profiler::BeginQuery("Integrate"); @@ -124,12 +121,11 @@ namespace Atlas { auto pipeline = PipelineManager::GetPipeline(temporalPipelineConfig); commandList->BindPipeline(pipeline); - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->swapVolumetricCloudsTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->volumetricCloudsTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT} }; - - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); commandList->BindImage(target->volumetricCloudsTexture.image, 3, 0); commandList->BindImage(target->swapVolumetricCloudsTexture.image, target->swapVolumetricCloudsTexture.sampler, 3, 1); @@ -153,20 +149,20 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Copy to history"); // Need barriers for both images - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->volumetricCloudsTexture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT}, {target->historyVolumetricCloudsTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); commandList->CopyImage(target->volumetricCloudsTexture.image, target->historyVolumetricCloudsTexture.image); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->volumetricCloudsTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->historyVolumetricCloudsTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers, + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); Graphics::Profiler::EndQuery(); diff --git a/src/engine/renderer/VolumetricRenderer.cpp b/src/engine/renderer/VolumetricRenderer.cpp index e60b97e52..982e49026 100644 --- a/src/engine/renderer/VolumetricRenderer.cpp +++ b/src/engine/renderer/VolumetricRenderer.cpp @@ -9,9 +9,16 @@ namespace Atlas { this->device = device; - const int32_t filterSize = 4; blurFilter.CalculateBoxFilter(filterSize); + std::vector blurKernelWeights; + std::vector blurKernelOffsets; + blurFilter.GetLinearized(&blurKernelWeights, &blurKernelOffsets, false); + + auto mean = (blurKernelWeights.size() - 1) / 2; + blurKernelWeights = std::vector(blurKernelWeights.begin() + mean, blurKernelWeights.end()); + blurKernelOffsets = std::vector(blurKernelOffsets.begin() + mean, blurKernelOffsets.end()); + auto noiseImage = Loader::ImageLoader::LoadImage("scrambling_ranking.png", false, 4); scramblingRankingTexture = Texture::Texture2D(noiseImage->width, noiseImage->height, VK_FORMAT_R8G8B8A8_UNORM); @@ -35,7 +42,9 @@ namespace Atlas { volumetricUniformBuffer = Buffer::UniformBuffer(sizeof(VolumetricUniforms)); resolveUniformBuffer = Buffer::UniformBuffer(sizeof(ResolveUniforms)); - blurWeightsUniformBuffer = Buffer::UniformBuffer(sizeof(float) * (size_t(filterSize) + 1)); + + blurWeightsUniformBuffer = Buffer::Buffer(Buffer::BufferUsageBits::UniformBufferBit, + sizeof(float) * (size_t(filterSize) + 1), 1, blurKernelWeights.data()); auto samplerDesc = Graphics::SamplerDesc{ .filter = VK_FILTER_NEAREST, @@ -213,41 +222,27 @@ namespace Atlas { Graphics::Profiler::EndQuery(); - std::vector bufferBarriers; - std::vector imageBarriers; - if (fog && fog->enable && fog->rayMarching) { Graphics::Profiler::BeginQuery("Bilateral blur"); const int32_t groupSize = 256; - std::vector kernelWeights; - std::vector kernelOffsets; - - blurFilter.GetLinearized(&kernelWeights, &kernelOffsets, false); - - auto mean = (kernelWeights.size() - 1) / 2; - kernelWeights = std::vector(kernelWeights.begin() + mean, kernelWeights.end()); - kernelOffsets = std::vector(kernelOffsets.begin() + mean, kernelOffsets.end()); - - auto kernelSize = int32_t(kernelWeights.size() - 1); + auto kernelSize = int32_t(filterSize); auto horizontalBlurPipeline = PipelineManager::GetPipeline(horizontalBlurPipelineConfig); auto verticalBlurPipeline = PipelineManager::GetPipeline(verticalBlurPipelineConfig); - blurWeightsUniformBuffer.SetData(kernelWeights.data(), 0); - commandList->BindImage(lowResDepthTexture->image, lowResDepthTexture->sampler, 3, 2); commandList->BindBuffer(blurWeightsUniformBuffer.Get(), 3, 4); for (int32_t j = 0; j < 3; j++) { ivec2 groupCount = ivec2(res.x / groupSize, res.y); groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); - imageBarriers = { + Graphics::ImageBarrier preImageBarriers[] = { {target->volumetricTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->swapVolumetricTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(preImageBarriers, {}); commandList->BindPipeline(horizontalBlurPipeline); commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); @@ -260,11 +255,11 @@ namespace Atlas { groupCount = ivec2(res.x, res.y / groupSize); groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - imageBarriers = { + Graphics::ImageBarrier postImageBarriers[] = { {target->swapVolumetricTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->volumetricTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(postImageBarriers, {}); commandList->BindPipeline(verticalBlurPipeline); commandList->PushConstants("constants", &kernelSize, sizeof(int32_t)); @@ -278,11 +273,11 @@ namespace Atlas { Graphics::Profiler::EndQuery(); } - imageBarriers = { + Graphics::ImageBarrier imageBarriers[] = { {target->volumetricTexture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT}, {target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT}, }; - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier(imageBarriers, {}); { Graphics::Profiler::BeginQuery("Resolve"); diff --git a/src/engine/renderer/VolumetricRenderer.h b/src/engine/renderer/VolumetricRenderer.h index 44d984861..9ed64f197 100644 --- a/src/engine/renderer/VolumetricRenderer.h +++ b/src/engine/renderer/VolumetricRenderer.h @@ -64,12 +64,14 @@ namespace Atlas { Texture::Texture2D sobolSequenceTexture; Buffer::Buffer lightCullingBuffer; + Buffer::Buffer blurWeightsUniformBuffer; Buffer::UniformBuffer volumetricUniformBuffer; - Buffer::UniformBuffer blurWeightsUniformBuffer; Buffer::UniformBuffer resolveUniformBuffer; Ref shadowSampler; + const int32_t filterSize = 4; + }; } diff --git a/src/engine/renderer/helper/RayTracingHelper.cpp b/src/engine/renderer/helper/RayTracingHelper.cpp index da3baf826..ac98463b4 100644 --- a/src/engine/renderer/helper/RayTracingHelper.cpp +++ b/src/engine/renderer/helper/RayTracingHelper.cpp @@ -290,9 +290,6 @@ namespace Atlas { commandList->BindBuffer(indirectDispatchBuffer.Get(), 2, 12); - std::vector bufferBarriers; - std::vector imageBarriers; - // Set up command buffer, reset ray count { auto pipeline = PipelineManager::GetPipeline(traceDispatchPipelineConfig); @@ -303,32 +300,39 @@ namespace Atlas { VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT); if (dispatchCounter % 2 == 0) { - bufferBarriers.push_back({ counterBuffer0.Get(), VK_ACCESS_SHADER_READ_BIT }); - bufferBarriers.push_back({ counterBuffer1.Get(), VK_ACCESS_SHADER_WRITE_BIT }); + Graphics::BufferBarrier bufferBarriers[] = { + { counterBuffer0.Get(), VK_ACCESS_SHADER_READ_BIT }, + { counterBuffer1.Get(), VK_ACCESS_SHADER_WRITE_BIT } + }; commandList->BindBuffer(counterBuffer0.Get(), 2, 13); commandList->BindBuffer(counterBuffer1.Get(), 2, 14); + + commandList->PipelineBarrier({}, bufferBarriers); } else { - bufferBarriers.push_back({ counterBuffer0.Get(), VK_ACCESS_SHADER_WRITE_BIT }); - bufferBarriers.push_back({ counterBuffer1.Get(), VK_ACCESS_SHADER_READ_BIT }); + Graphics::BufferBarrier bufferBarriers[] = { + { counterBuffer0.Get(), VK_ACCESS_SHADER_WRITE_BIT }, + { counterBuffer1.Get(), VK_ACCESS_SHADER_READ_BIT } + }; commandList->BindBuffer(counterBuffer0.Get(), 2, 14); commandList->BindBuffer(counterBuffer1.Get(), 2, 13); + + commandList->PipelineBarrier({}, bufferBarriers); } - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->Dispatch(1, 1, 1); } - bufferBarriers.clear(); - imageBarriers.clear(); - // Can't group barriers together because of different access patterns commandList->BufferMemoryBarrier(indirectDispatchBuffer.Get(), VK_ACCESS_INDIRECT_COMMAND_READ_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT); - bufferBarriers.push_back({ rayBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); - bufferBarriers.push_back({ rayPayloadBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + Graphics::BufferBarrier bufferBarriers[] = { + { rayBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }, + { rayPayloadBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT } + }; + commandList->PipelineBarrier({}, bufferBarriers); commandList->BindBuffer(rayBuffer.Get(), 2, 15); commandList->BindBuffer(rayPayloadBuffer.Get(), 2, 16); @@ -400,19 +404,18 @@ namespace Atlas { Graphics::Profiler::EndAndBeginQuery("Execute hit shader"); - bufferBarriers.clear(); - imageBarriers.clear(); - - bufferBarriers.push_back({ rayBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); - bufferBarriers.push_back({ rayPayloadBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); + Graphics::BufferBarrier preShaderBufferBarriers[3] = { + { rayBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }, + { rayPayloadBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT } + }; if (dispatchCounter % 2 == 0) { - bufferBarriers.push_back({ counterBuffer1.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); + preShaderBufferBarriers[2] = {counterBuffer1.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT}; } else { - bufferBarriers.push_back({ counterBuffer0.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); + preShaderBufferBarriers[2] = {counterBuffer0.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT}; } - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + commandList->PipelineBarrier({}, preShaderBufferBarriers); // Shade rays { @@ -441,22 +444,22 @@ namespace Atlas { void RayTracingHelper::InvalidateRayBuffer(Graphics::CommandList* commandList) { - std::vector bufferBarriers; - std::vector imageBarriers; - - bufferBarriers.push_back({counterBuffer0.Get(), VK_ACCESS_TRANSFER_WRITE_BIT}); - bufferBarriers.push_back({counterBuffer1.Get(), VK_ACCESS_TRANSFER_WRITE_BIT}); - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Graphics::BufferBarrier preBufferBarriers[] = { + {counterBuffer0.Get(), VK_ACCESS_TRANSFER_WRITE_BIT}, + {counterBuffer1.Get(), VK_ACCESS_TRANSFER_WRITE_BIT} + }; + commandList->PipelineBarrier({}, preBufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); uint32_t zero = 0; commandList->FillBuffer(counterBuffer0.Get(), &zero); commandList->FillBuffer(counterBuffer1.Get(), &zero); - bufferBarriers.clear(); - bufferBarriers.push_back({counterBuffer0.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}); - bufferBarriers.push_back({counterBuffer1.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}); - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_TRANSFER_BIT, + Graphics::BufferBarrier postBufferBarriers[] = { + {counterBuffer0.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}, + {counterBuffer1.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT} + }; + commandList->PipelineBarrier({}, postBufferBarriers, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); } diff --git a/src/engine/renderer/helper/VegetationHelper.cpp b/src/engine/renderer/helper/VegetationHelper.cpp index 3de59d36a..ec0017935 100644 --- a/src/engine/renderer/helper/VegetationHelper.cpp +++ b/src/engine/renderer/helper/VegetationHelper.cpp @@ -40,9 +40,6 @@ namespace Atlas { uint32_t binCount; }; - std::vector bufferBarriers; - std::vector imageBarriers; - Graphics::Profiler::BeginQuery("Culling"); auto meshes = vegetation.GetMeshes(); @@ -93,9 +90,8 @@ namespace Atlas { commandList->Dispatch(groupCount, 1, 1); } - bufferBarriers.clear(); - bufferBarriers.push_back({ binCounterBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + Graphics::BufferBarrier bufferBarriers[] = {{ binCounterBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }}; + commandList->PipelineBarrier({}, bufferBarriers); } Graphics::Profiler::EndAndBeginQuery("Compute bin offsets"); @@ -114,16 +110,17 @@ namespace Atlas { commandList->Dispatch(groupCount, 1, 1); - bufferBarriers.clear(); - bufferBarriers.push_back({binOffsetBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); - bufferBarriers.push_back({binCounterBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); - bufferBarriers.push_back({instanceCounterBuffer.Get(), VK_ACCESS_SHADER_READ_BIT}); + meshBufferBarriers.clear(); + meshBufferBarriers.push_back({ binOffsetBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); + meshBufferBarriers.push_back({ binCounterBuffer.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); + meshBufferBarriers.push_back({ instanceCounterBuffer.Get(), VK_ACCESS_SHADER_READ_BIT }); for (auto mesh : meshes) { auto buffers = vegetation.GetBuffers(mesh); - bufferBarriers.push_back({buffers->culledInstanceData.Get(), + meshBufferBarriers.push_back({buffers->culledInstanceData.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); } - commandList->PipelineBarrier(imageBarriers, bufferBarriers); + + commandList->PipelineBarrier({}, meshBufferBarriers); } Graphics::Profiler::EndAndBeginQuery("Sort by bins"); @@ -192,13 +189,14 @@ namespace Atlas { commandList->BufferMemoryBarrier(indirectDrawCallBuffer.Get(), VK_ACCESS_INDIRECT_COMMAND_READ_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT); - bufferBarriers.clear(); + meshBufferBarriers.clear(); + for (auto mesh : meshes) { auto buffers = vegetation.GetBuffers(mesh); - bufferBarriers.push_back({buffers->binnedInstanceData.Get(), + meshBufferBarriers.push_back({buffers->binnedInstanceData.Get(), VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT }); } - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + commandList->PipelineBarrier({}, meshBufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT); Graphics::Profiler::EndQuery(); @@ -276,22 +274,22 @@ namespace Atlas { void VegetationHelper::ResetCounterBuffers(Graphics::CommandList* commandList) { - std::vector bufferBarriers; - std::vector imageBarriers; - - bufferBarriers.push_back({binCounterBuffer.Get(), VK_ACCESS_TRANSFER_WRITE_BIT}); - bufferBarriers.push_back({instanceCounterBuffer.Get(), VK_ACCESS_TRANSFER_WRITE_BIT}); - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Graphics::BufferBarrier preBufferBarriers[] = { + {binCounterBuffer.Get(), VK_ACCESS_TRANSFER_WRITE_BIT}, + {instanceCounterBuffer.Get(), VK_ACCESS_TRANSFER_WRITE_BIT} + }; + commandList->PipelineBarrier({}, preBufferBarriers, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); uint32_t zero = 0; commandList->FillBuffer(binCounterBuffer.Get(), &zero); commandList->FillBuffer(instanceCounterBuffer.Get(), &zero); - bufferBarriers.clear(); - bufferBarriers.push_back({binCounterBuffer.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}); - bufferBarriers.push_back({instanceCounterBuffer.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}); - commandList->PipelineBarrier(imageBarriers, bufferBarriers, VK_PIPELINE_STAGE_TRANSFER_BIT, + Graphics::BufferBarrier postBufferBarriers[] = { + {binCounterBuffer.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}, + {instanceCounterBuffer.Get(), VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT} + }; + commandList->PipelineBarrier({}, postBufferBarriers, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); } diff --git a/src/engine/renderer/helper/VegetationHelper.h b/src/engine/renderer/helper/VegetationHelper.h index 442ba2baa..2377a7c86 100644 --- a/src/engine/renderer/helper/VegetationHelper.h +++ b/src/engine/renderer/helper/VegetationHelper.h @@ -69,6 +69,8 @@ namespace Atlas { std::map meshToIdxMap; std::vector meshSubdataInformation; + std::vector meshBufferBarriers; + }; } From 0bdc241c26e747f65ddfde1f665f77338f51f529 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 15 Oct 2024 13:10:22 +0200 Subject: [PATCH 53/66] Some adjustments --- data/shader/deferred/geometry.vsh | 4 +- data/shader/impostor/impostor.vsh | 4 +- data/shader/impostor/impostorShadow.vsh | 4 +- data/shader/pathtracer/rayHit.csh | 4 +- data/shader/raytracer/surface.hsh | 6 +- data/shader/shadowMapping.vsh | 2 +- src/editor/ui/panels/ResourceSelectionPanel.h | 2 +- src/engine/graphics/ASBuilder.cpp | 78 +++++++++++++------ src/engine/graphics/ASBuilder.h | 13 ++-- src/engine/graphics/BLAS.cpp | 4 +- src/engine/graphics/BLAS.h | 6 ++ src/engine/graphics/CommandList.cpp | 4 +- src/engine/graphics/CommandList.h | 4 + src/engine/graphics/Framebuffer.cpp | 5 +- src/engine/graphics/Framebuffer.h | 2 + src/engine/graphics/GraphicsDevice.cpp | 2 +- src/engine/graphics/Instance.cpp | 1 + src/engine/jobsystem/JobSystem.h | 5 +- src/engine/lighting/VolumetricClouds.cpp | 2 +- src/engine/mesh/Mesh.h | 4 +- src/engine/raytracing/RayTracingManager.cpp | 44 ++++++++++- src/engine/raytracing/RayTracingManager.h | 5 ++ src/engine/raytracing/RayTracingWorld.cpp | 43 +++++++--- src/engine/raytracing/RayTracingWorld.h | 3 + src/engine/renderer/IndirectLightRenderer.cpp | 2 +- src/engine/renderer/MainRenderer.cpp | 4 +- src/engine/renderer/ShadowRenderer.cpp | 8 +- src/engine/renderer/ShadowRenderer.h | 2 + src/engine/resource/ResourceManager.h | 57 ++++++++++---- src/engine/scene/Scene.cpp | 5 +- src/engine/scene/SceneRenderState.cpp | 75 ++++++++---------- src/engine/scene/SceneRenderState.h | 1 - .../scene/components/CameraComponent.cpp | 20 ++--- src/engine/scene/components/CameraComponent.h | 2 +- .../scene/components/LightComponent.cpp | 2 +- .../scripting/bindings/UtilityBindings.cpp | 4 +- src/engine/volume/BVH.cpp | 3 + src/engine/volume/Frustum.cpp | 10 +-- src/engine/volume/Frustum.h | 10 ++- 39 files changed, 301 insertions(+), 155 deletions(-) diff --git a/data/shader/deferred/geometry.vsh b/data/shader/deferred/geometry.vsh index 2cd3550a0..83d78e1a9 100644 --- a/data/shader/deferred/geometry.vsh +++ b/data/shader/deferred/geometry.vsh @@ -25,11 +25,11 @@ layout(location=3) in vec4 vTangent; layout(location=4) in vec4 vVertexColors; #endif -layout(std430, set = 1, binding = 1) buffer CurrentMatrices { +layout(std430, set = 1, binding = 1) readonly buffer CurrentMatrices { mat3x4 currentMatrices[]; }; -layout(std430, set = 1, binding = 2) buffer LastMatrices { +layout(std430, set = 1, binding = 2) readonly buffer LastMatrices { mat3x4 lastMatrices[]; }; diff --git a/data/shader/impostor/impostor.vsh b/data/shader/impostor/impostor.vsh index 18cf7a6b4..da85ffb7b 100644 --- a/data/shader/impostor/impostor.vsh +++ b/data/shader/impostor/impostor.vsh @@ -10,11 +10,11 @@ struct ViewPlane { vec4 up; }; -layout(std430, set = 1, binding = 3) buffer Matrices { +layout(std430, set = 1, binding = 3) readonly buffer Matrices { mat3x4 matrices[]; }; -layout (std430, set = 3, binding = 4) buffer ViewPlanes { +layout (std430, set = 3, binding = 4) readonly buffer ViewPlanes { ViewPlane viewPlanes[]; }; diff --git a/data/shader/impostor/impostorShadow.vsh b/data/shader/impostor/impostorShadow.vsh index 71e8a3dd2..1cec78ef4 100644 --- a/data/shader/impostor/impostorShadow.vsh +++ b/data/shader/impostor/impostorShadow.vsh @@ -26,11 +26,11 @@ struct ViewPlane { vec4 up; }; -layout(std430, set = 1, binding = 3) buffer Matrices { +layout(std430, set = 1, binding = 3) readonly buffer Matrices { mat3x4 matrices[]; }; -layout (std430, set = 3, binding = 1) buffer ViewPlanes { +layout (std430, set = 3, binding = 1) readonly buffer ViewPlanes { ViewPlane viewPlanes[]; }; diff --git a/data/shader/pathtracer/rayHit.csh b/data/shader/pathtracer/rayHit.csh index 93634474d..5ead8a10b 100644 --- a/data/shader/pathtracer/rayHit.csh +++ b/data/shader/pathtracer/rayHit.csh @@ -112,10 +112,10 @@ void main() { imageStore(depthImage, pixel, vec4(ray.hitID >= 0 ? projPositionCurrent.z / projPositionCurrent.w : INF, 0.0, 0.0, 0.0)); imageStore(materialIdxImage, pixel, uvec4(materialId, 0.0, 0.0, 0.0)); - imageStore(normalImage, pixel, vec4(EncodeNormal(geometryNormal), 0.0, 0.0)); + imageStore(normalImage, pixel, vec4(EncodeNormal(geometryNormal), 0.0, 0.0)); } #endif - + if (energy == 0 || Uniforms.bounceCount == Uniforms.maxBounces) { #ifndef REALTIME if (Uniforms.sampleCount > 0) diff --git a/data/shader/raytracer/surface.hsh b/data/shader/raytracer/surface.hsh index 1bb3499e5..e7b4dc462 100644 --- a/data/shader/raytracer/surface.hsh +++ b/data/shader/raytracer/surface.hsh @@ -9,19 +9,19 @@ Instance GetInstance(Ray ray) { - return bvhInstances[ray.hitInstanceID]; + return bvhInstances[nonuniformEXT(ray.hitInstanceID)]; } Triangle GetTriangle(Ray ray, Instance instance) { - return UnpackTriangle(triangles[nonuniformEXT(instance.meshOffset)].data[ray.hitID]); + return UnpackTriangle(triangles[nonuniformEXT(instance.meshOffset)].data[nonuniformEXT(ray.hitID)]); } Material GetTriangleMaterial(Triangle tri, int materialOffset, out RaytraceMaterial rayMat) { Material mat; - rayMat = materials[tri.materialIndex + materialOffset]; + rayMat = materials[nonuniformEXT(tri.materialIndex + materialOffset)]; mat.ID = rayMat.ID; diff --git a/data/shader/shadowMapping.vsh b/data/shader/shadowMapping.vsh index 597f16988..87af352ce 100644 --- a/data/shader/shadowMapping.vsh +++ b/data/shader/shadowMapping.vsh @@ -10,7 +10,7 @@ layout(location=2) in vec2 vTexCoord; layout(location=0) out vec2 texCoordVS; #endif -layout(std430, set = 1, binding = 1) buffer Matrices { +layout(std430, set = 1, binding = 1) readonly buffer Matrices { mat3x4 matrices[]; }; diff --git a/src/editor/ui/panels/ResourceSelectionPanel.h b/src/editor/ui/panels/ResourceSelectionPanel.h index acf47ec6a..51be3ba5a 100644 --- a/src/editor/ui/panels/ResourceSelectionPanel.h +++ b/src/editor/ui/panels/ResourceSelectionPanel.h @@ -34,7 +34,7 @@ namespace Atlas::Editor::UI { auto buttonName = resourceHandle.IsValid() ? resourceHandle.GetResource()->GetFileName() : "Drop resource here##" + std::to_string(counter++); - ImGui::PushID(resourceHandle.IsValid() ? resourceHandle.GetID() : counter); + ImGui::PushID(resourceHandle.IsValid() ? int32_t(resourceHandle.GetID()) : counter); popup.SetID(resourceHandle.IsValid() ? resourceHandle.GetID() : counter); if (ImGui::Button(buttonName.c_str(), { resourceButtonSize, 0 })) diff --git a/src/engine/graphics/ASBuilder.cpp b/src/engine/graphics/ASBuilder.cpp index 50c5ed751..396a15902 100644 --- a/src/engine/graphics/ASBuilder.cpp +++ b/src/engine/graphics/ASBuilder.cpp @@ -49,7 +49,7 @@ namespace Atlas { } - void ASBuilder::BuildBLAS(std::vector> &blases) { + int32_t ASBuilder::BuildBLAS(std::vector> &blases, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; @@ -70,7 +70,9 @@ namespace Atlas { auto scratchBuffer = device->CreateBuffer(scratchBufferDesc); Ref queryPool = nullptr; - if (compactionCount == blases.size()) { + // Only on a direct submission we can actually afford to wait for the queries, otherwise we can't + // afford the compaction if the BVH build is in frame + if (compactionCount == blases.size() && !commandList) { auto queryPoolDesc = QueryPoolDesc{ .queryType = VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, .queryCount = uint32_t(compactionCount) @@ -94,29 +96,44 @@ namespace Atlas { queryPool->Reset(); } - BuildBLASBatch(batchIndices, blases, scratchBuffer, queryPool); + BuildBLASBatch(batchIndices, blases, scratchBuffer, queryPool, commandList); if (queryPool) { - CompactBLASBatch(batchIndices, blases, queryPool); + CompactBLASBatch(batchIndices, blases, queryPool, commandList); } batchIndices.clear(); batchSize = 0; + for (size_t j = 0; j <= i; j++) { + blases[j]->isBuilt = true; + } + + return int32_t(i + 1); + // With one commandlist it only makes sense to create one batch per frame + if (commandList) { + return int32_t(i + 1); + } + } } + return int32_t(blases.size()); + } - Ref ASBuilder::BuildTLAS(Ref &tlas, - std::vector &instances) { + Ref ASBuilder::BuildTLAS(Ref& tlas, + std::vector& instances, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; - auto commandList = device->GetCommandList(GraphicsQueue); + bool immediateSubmission = commandList == nullptr; + if (!commandList) { + commandList = device->GetCommandList(GraphicsQueue); - commandList->BeginCommands(); + commandList->BeginCommands(); + } BufferDesc desc = { .usageFlags = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR @@ -147,22 +164,27 @@ namespace Atlas { commandList->BuildTLAS(tlas, buildInfo); - commandList->EndCommands(); + if (immediateSubmission) { + commandList->EndCommands(); - device->SubmitCommandList(commandList); + device->SubmitCommandList(commandList); + } return instanceBuffer; } - void ASBuilder::BuildBLASBatch(const std::vector &batchIndices, - std::vector> &blases, Ref& scratchBuffer, Ref& queryPool) { + void ASBuilder::BuildBLASBatch(const std::vector &batchIndices, std::vector> &blases, + Ref& scratchBuffer, Ref& queryPool, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; - auto commandList = device->GetCommandList(GraphicsQueue, true); + bool immediateSubmission = commandList == nullptr; + if (!commandList) { + commandList = device->GetCommandList(GraphicsQueue, true); - commandList->BeginCommands(); + commandList->BeginCommands(); + } VkDeviceAddress scratchAddress = scratchBuffer->GetDeviceAddress(); @@ -179,7 +201,7 @@ namespace Atlas { commandList->BuildBLAS(blas, buildInfo); commandList->MemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); @@ -190,20 +212,25 @@ namespace Atlas { } } - commandList->EndCommands(); + if (immediateSubmission) { + commandList->EndCommands(); - device->FlushCommandList(commandList); + device->FlushCommandList(commandList); + } } void ASBuilder::CompactBLASBatch(const std::vector& batchIndices, - std::vector>& blases, Ref& queryPool) { + std::vector>& blases, Ref& queryPool, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; - auto commandList = device->GetCommandList(GraphicsQueue, true); + bool immediateSubmission = commandList == nullptr; + if (!commandList) { + commandList = device->GetCommandList(GraphicsQueue, true); - commandList->BeginCommands(); + commandList->BeginCommands(); + } std::vector compactSizes(batchIndices.size()); queryPool->GetResult(0, uint32_t(batchIndices.size()), batchIndices.size() * sizeof(size_t), @@ -240,9 +267,16 @@ namespace Atlas { } - commandList->EndCommands(); + commandList->MemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); + + if (immediateSubmission) { + commandList->EndCommands(); - device->FlushCommandList(commandList); + device->FlushCommandList(commandList); + } } diff --git a/src/engine/graphics/ASBuilder.h b/src/engine/graphics/ASBuilder.h index fc0154894..247ffd207 100644 --- a/src/engine/graphics/ASBuilder.h +++ b/src/engine/graphics/ASBuilder.h @@ -5,6 +5,7 @@ #include "BLAS.h" #include "TLAS.h" #include "QueryPool.h" +#include "CommandList.h" namespace Atlas { @@ -25,16 +26,18 @@ namespace Atlas { BLASDesc GetBLASDescForTriangleGeometry(Ref vertexBuffer, Ref indexBuffer, size_t vertexCount, size_t vertexSize, size_t indexSize, std::vector regions); - void BuildBLAS(std::vector>& blases); + int32_t BuildBLAS(std::vector>& blases, CommandList* commandList = nullptr); - Ref BuildTLAS(Ref& tlas, std::vector& instances); + Ref BuildTLAS(Ref& tlas, std::vector& instances, CommandList* commandList = nullptr); private: - void BuildBLASBatch(const std::vector& batchIndices, - std::vector>& blases, Ref& scratchBuffer, Ref& queryPool); + void BuildBLASBatch(const std::vector& batchIndices, std::vector>& blases, + Ref& scratchBuffer, Ref& queryPool, CommandList* commandList); void CompactBLASBatch(const std::vector& batchIndices, - std::vector>& blases, Ref& queryPool); + std::vector>& blases, Ref& queryPool, CommandList* commandList); + + Ref scratchBuffer = nullptr; }; diff --git a/src/engine/graphics/BLAS.cpp b/src/engine/graphics/BLAS.cpp index f5eb7bc05..de6d92474 100644 --- a/src/engine/graphics/BLAS.cpp +++ b/src/engine/graphics/BLAS.cpp @@ -6,8 +6,8 @@ namespace Atlas { namespace Graphics { - BLAS::BLAS(GraphicsDevice* device, BLASDesc desc) : device(device), geometries(desc.geometries), - buildRanges(desc.buildRanges), flags(desc.flags) { + BLAS::BLAS(GraphicsDevice* device, BLASDesc desc) : isDynamic(desc.isDynamic), device(device), + geometries(desc.geometries), buildRanges(desc.buildRanges), flags(desc.flags) { buildGeometryInfo = {}; buildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; diff --git a/src/engine/graphics/BLAS.h b/src/engine/graphics/BLAS.h index 873f24e52..d44a9c4ce 100644 --- a/src/engine/graphics/BLAS.h +++ b/src/engine/graphics/BLAS.h @@ -4,6 +4,7 @@ #include "Buffer.h" #include +#include namespace Atlas { @@ -16,6 +17,8 @@ namespace Atlas { struct BLASDesc { VkBuildAccelerationStructureFlagsKHR flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + bool isDynamic = false; + std::vector geometries; std::vector buildRanges; }; @@ -41,6 +44,9 @@ namespace Atlas { VkDeviceAddress bufferDeviceAddress; + bool isDynamic = false; + std::atomic_bool isBuilt = false; + private: GraphicsDevice* device; diff --git a/src/engine/graphics/CommandList.cpp b/src/engine/graphics/CommandList.cpp index 1feff64c6..8a2020082 100644 --- a/src/engine/graphics/CommandList.cpp +++ b/src/engine/graphics/CommandList.cpp @@ -176,7 +176,7 @@ namespace Atlas { rpInfo.renderArea.extent = frameBuffer->extent; rpInfo.framebuffer = frameBuffer->frameBuffer; - std::vector clearValues; + clearValues.clear(); for (auto& attachment : renderPass->colorAttachments) { if (!attachment.isValid) continue; if (attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { @@ -350,7 +350,7 @@ namespace Atlas { void CommandList::ClearAttachments() { - std::vector clearAttachments; + clearAttachments.clear(); VkClearRect clearRect = {}; if (swapChainInUse) { VkClearAttachment colorClear = {}, depthClear = {}; diff --git a/src/engine/graphics/CommandList.h b/src/engine/graphics/CommandList.h index f01101282..cd5a12758 100644 --- a/src/engine/graphics/CommandList.h +++ b/src/engine/graphics/CommandList.h @@ -328,6 +328,10 @@ namespace Atlas { std::vector semaphores; + // Resources that are used each frame where we don't want allocate memory each time + std::vector clearValues; + std::vector clearAttachments; + }; } diff --git a/src/engine/graphics/Framebuffer.cpp b/src/engine/graphics/Framebuffer.cpp index 05d2e661a..7ea26558f 100644 --- a/src/engine/graphics/Framebuffer.cpp +++ b/src/engine/graphics/Framebuffer.cpp @@ -50,11 +50,12 @@ namespace Atlas { void FrameBuffer::Refresh() { - std::vector imageViews; - const auto& rpColorAttachments = renderPass->colorAttachments; const auto& rpDepthAttachment = renderPass->depthAttachment; + imageViews.reserve(MAX_COLOR_ATTACHMENTS + 1); + imageViews.clear(); + // NOTE: The frame buffer requires to have an image view for each attachment in the render pass // This doesn't mean we need to write to all attachments. The writing to attachments is being configured // in the pipeline setup and is based on which color attachments the user specified in this frame buffer diff --git a/src/engine/graphics/Framebuffer.h b/src/engine/graphics/Framebuffer.h index 2a925a7f6..06363f92b 100644 --- a/src/engine/graphics/Framebuffer.h +++ b/src/engine/graphics/Framebuffer.h @@ -59,6 +59,8 @@ namespace Atlas { FrameBufferAttachment colorAttachments[MAX_COLOR_ATTACHMENTS]; FrameBufferAttachment depthAttachment; + std::vector imageViews; + VkExtent2D extent; uint32_t layers; diff --git a/src/engine/graphics/GraphicsDevice.cpp b/src/engine/graphics/GraphicsDevice.cpp index 2a6ba5d07..e9d734de6 100644 --- a/src/engine/graphics/GraphicsDevice.cpp +++ b/src/engine/graphics/GraphicsDevice.cpp @@ -434,7 +434,7 @@ namespace Atlas { VK_CHECK(vkQueueSubmit(queue.queue, 1, &submit, cmd->fence)) queue.Unlock(); - VK_CHECK(vkWaitForFences(device, 1, &cmd->fence, true, 9999999999)); + VK_CHECK(vkWaitForFences(device, 1, &cmd->fence, true, 30000000000)); VK_CHECK(vkResetFences(device, 1, &cmd->fence)); // Is submitted now and must be unlocked diff --git a/src/engine/graphics/Instance.cpp b/src/engine/graphics/Instance.cpp index 1c882c069..edc572f4c 100644 --- a/src/engine/graphics/Instance.cpp +++ b/src/engine/graphics/Instance.cpp @@ -263,6 +263,7 @@ namespace Atlas { VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT; + createInfo.pfnUserCallback = DebugCallback; createInfo.pUserData = static_cast(const_cast(name.c_str())); return createInfo; diff --git a/src/engine/jobsystem/JobSystem.h b/src/engine/jobsystem/JobSystem.h index 6b450a717..0a05fe743 100644 --- a/src/engine/jobsystem/JobSystem.h +++ b/src/engine/jobsystem/JobSystem.h @@ -15,10 +15,11 @@ namespace Atlas { + // Idea: Keep 8 threads to the high priority pool and main thread, split the rest in two struct JobSystemConfig { int32_t highPriorityThreadCount = int32_t(std::thread::hardware_concurrency()) - 1; - int32_t mediumPriorityThreadCount = int32_t(std::thread::hardware_concurrency()) - 3; - int32_t lowPriorityThreadCount = int32_t(std::thread::hardware_concurrency()) - 4; + int32_t mediumPriorityThreadCount = std::max(1, std::max(int32_t(std::thread::hardware_concurrency()) - 8, int32_t(std::thread::hardware_concurrency()) / 2) / 2); + int32_t lowPriorityThreadCount = std::max(1, std::max(int32_t(std::thread::hardware_concurrency()) - 8, int32_t(std::thread::hardware_concurrency()) / 2) / 2); }; class JobSystem { diff --git a/src/engine/lighting/VolumetricClouds.cpp b/src/engine/lighting/VolumetricClouds.cpp index 79eac047c..f517695a7 100644 --- a/src/engine/lighting/VolumetricClouds.cpp +++ b/src/engine/lighting/VolumetricClouds.cpp @@ -40,7 +40,7 @@ namespace Atlas { vec3 up = glm::vec3(0.0000000000000001f, 1.0f, 0.0000000000000001f); viewMatrix = lookAt(cascadeCenter, cascadeCenter + lightDirection, up); - std::vector corners = camera.GetFrustumCorners(camera.nearPlane, camera.farPlane); + auto corners = camera.GetFrustumCorners(camera.nearPlane, camera.farPlane); vec3 maxProj = vec3(viewMatrix * vec4(corners.at(0), 1.0f)); vec3 minProj = maxProj; diff --git a/src/engine/mesh/Mesh.h b/src/engine/mesh/Mesh.h index cc66a7a0d..a719a009e 100644 --- a/src/engine/mesh/Mesh.h +++ b/src/engine/mesh/Mesh.h @@ -115,11 +115,13 @@ namespace Atlas { bool invertUVs = false; + std::atomic_bool needsBvhRefresh = false; + private: bool isLoaded = false; std::atomic_bool isBvhBuilt = false; - std::atomic_bool needsBvhRefresh = false; + }; diff --git a/src/engine/raytracing/RayTracingManager.cpp b/src/engine/raytracing/RayTracingManager.cpp index 712d98429..5bd9a4ce0 100644 --- a/src/engine/raytracing/RayTracingManager.cpp +++ b/src/engine/raytracing/RayTracingManager.cpp @@ -1,12 +1,14 @@ #include "RayTracingManager.h" #include "graphics/GraphicsDevice.h" +#include "graphics/ASBuilder.h" #include "resource/ResourceManager.h" #include "mesh/Mesh.h" namespace Atlas::RayTracing { JobGroup RayTracingManager::bvhUpdateGroup; + std::vector> RayTracingManager::blases; void RayTracingManager::Update() { @@ -16,6 +18,7 @@ namespace Atlas::RayTracing { auto buildRTStructure = [&](JobData) { auto sceneMeshes = ResourceManager::GetResources(); + JobGroup bvhBuildGroup; for (const auto& mesh : sceneMeshes) { if (!mesh.IsLoaded()) continue; @@ -24,10 +27,17 @@ namespace Atlas::RayTracing { if (mesh->data.GetIndexCount() == 0 || mesh->data.GetVertexCount() == 0) continue; - JobSystem::Execute(bvhUpdateGroup, [mesh](JobData&) { + + JobSystem::Execute(bvhBuildGroup, [mesh](JobData&) { mesh->BuildBVH(false); }); } + + JobSystem::Wait(bvhBuildGroup); + + auto device = Graphics::GraphicsDevice::DefaultDevice; + if (device->support.hardwareRayTracing) + BuildStaticBLAS(sceneMeshes); }; if (bvhUpdateGroup.HasFinished()) { @@ -37,4 +47,36 @@ namespace Atlas::RayTracing { } + void RayTracingManager::BuildStaticBLAS(std::vector>& meshes) { + + Graphics::ASBuilder asBuilder; + + for (auto it = meshes.begin(); it != meshes.end();) { + auto& mesh = *it; + + // Only want static meshes + if (!mesh.IsLoaded() || !mesh->IsBVHBuilt() || !mesh->needsBvhRefresh || mesh->blas->isDynamic) { + it = meshes.erase(it); + } + else { + blases.push_back(mesh->blas); + ++it; + } + } + + size_t blasBuiltCount = 0; + if (!blases.empty()) { + blasBuiltCount = asBuilder.BuildBLAS(blases); + } + + // Copy the non-compacted versions over + for (size_t i = 0; i < blasBuiltCount; i++) { + meshes[i]->blas = blases[i]; + meshes[i]->needsBvhRefresh = false; + } + + blases.clear(); + + } + } \ No newline at end of file diff --git a/src/engine/raytracing/RayTracingManager.h b/src/engine/raytracing/RayTracingManager.h index 6c902a631..337e5814c 100644 --- a/src/engine/raytracing/RayTracingManager.h +++ b/src/engine/raytracing/RayTracingManager.h @@ -2,6 +2,8 @@ #include "../System.h" #include "jobsystem/JobGroup.h" +#include "graphics/BLAS.h" +#include "mesh/Mesh.h" namespace Atlas::RayTracing { @@ -11,7 +13,10 @@ namespace Atlas::RayTracing { static void Update(); private: + static void BuildStaticBLAS(std::vector>& meshes); + static JobGroup bvhUpdateGroup; + static std::vector> blases; }; diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index 75dee35ea..d94b2c103 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -47,15 +47,21 @@ namespace Atlas { JobSystem::Wait(renderState->bindlessMeshMapUpdateJob); + std::swap(prevMeshInfos, meshInfos); + meshInfos.clear(); + for (auto& mesh : meshes) { // Only need to check for this, since that means that the BVH was built and the mesh is loaded if (!renderState->meshIdToBindlessIdx.contains(mesh.GetID())) continue; - if (!meshInfos.contains(mesh.GetID())) { + if (!prevMeshInfos.contains(mesh.GetID())) { meshInfos[mesh.GetID()] = {}; BuildTriangleLightsForMesh(mesh); } + else { + meshInfos[mesh.GetID()] = prevMeshInfos[mesh.GetID()]; + } auto &meshInfo = meshInfos[mesh.GetID()]; meshInfo.offset = int32_t(renderState->meshIdToBindlessIdx[mesh.GetID()]); @@ -63,7 +69,7 @@ namespace Atlas { // Some extra path for hardware raytracing, don't want to do work twice if (hardwareRayTracing) { - if (mesh->needsBvhRefresh) { + if (mesh->needsBvhRefresh && mesh->blas->isDynamic) { blases.push_back(mesh->blas); mesh->needsBvhRefresh = false; } @@ -73,10 +79,15 @@ namespace Atlas { } } - if (hardwareRayTracing) { + if (hardwareRayTracing) { Graphics::ASBuilder asBuilder; - if (!blases.empty()) - asBuilder.BuildBLAS(blases); + if (!blases.empty()) { + auto commandList = device->GetCommandList(); + commandList->BeginCommands(); + asBuilder.BuildBLAS(blases, commandList); + commandList->EndCommands(); + device->SubmitCommandList(commandList); + } } for (auto& [_, meshInfo] : meshInfos) { @@ -114,6 +125,8 @@ namespace Atlas { cameraLocation); if (hasCamera && distSqd > meshInfo.cullingDistanceSqr) continue; + if (hardwareRayTracing && !meshComponent.mesh->blas->isBuilt || meshComponent.mesh->needsBvhRefresh) + continue; actorAABBs.push_back(meshComponent.aabb); auto inverseMatrix = mat3x4(glm::transpose(transformComponent.inverseGlobalMatrix)); @@ -126,7 +139,7 @@ namespace Atlas { .meshOffset = meshInfo.offset, .materialOffset = meshInfo.materialOffset, .mask = mask - }; + }; meshInfo.matrices.emplace_back(transformComponent.globalMatrix); meshInfo.instanceIndices.push_back(uint32_t(gpuBvhInstances.size())); @@ -145,7 +158,7 @@ namespace Atlas { inst.transform = transform; inst.instanceCustomIndex = meshInfo.offset; - inst.accelerationStructureReference = meshInfo.blas->bufferDeviceAddress; + inst.accelerationStructureReference = meshComponent.mesh->blas->bufferDeviceAddress; inst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; inst.mask = mask; inst.instanceShaderBindingTableRecordOffset = 0; @@ -153,8 +166,11 @@ namespace Atlas { } } - if (gpuBvhInstances.empty()) + if (gpuBvhInstances.empty()) { + // Need to reset the TLAS in this case, since it might contain invalid memory addresses + tlas = nullptr; return; + } if (hardwareRayTracing) { UpdateForHardwareRayTracing(subset, gpuBvhInstances.size()); @@ -181,8 +197,7 @@ namespace Atlas { } void RayTracingWorld::UpdateMaterials() { - - std::vector materials; + UpdateMaterials(materials); } @@ -270,8 +285,12 @@ namespace Atlas { if (materials.empty()) return; - materialBuffer.SetSize(materials.size()); - materialBuffer.SetData(materials.data(), 0, materials.size()); + if (materialBuffer.GetElementCount() < materials.size()) { + materialBuffer.SetSize(materials.size(), materials.data()); + } + else { + materialBuffer.SetData(materials.data(), 0, materials.size()); + } } diff --git a/src/engine/raytracing/RayTracingWorld.h b/src/engine/raytracing/RayTracingWorld.h index 7b12f65d7..18810abcf 100644 --- a/src/engine/raytracing/RayTracingWorld.h +++ b/src/engine/raytracing/RayTracingWorld.h @@ -92,6 +92,9 @@ namespace Atlas { std::vector triangleLights; std::unordered_map meshInfos; + std::unordered_map prevMeshInfos; + + std::vector materials; bool hardwareRayTracing = false; diff --git a/src/engine/renderer/IndirectLightRenderer.cpp b/src/engine/renderer/IndirectLightRenderer.cpp index b7edbf123..ece269629 100644 --- a/src/engine/renderer/IndirectLightRenderer.cpp +++ b/src/engine/renderer/IndirectLightRenderer.cpp @@ -30,7 +30,7 @@ namespace Atlas { auto ddgiEnabled = volume && volume->enable && !rtgiEnabled && rtDataValid; auto ddgiVisibility = volume && volume->enable && rtDataValid && volume->visibility; auto reflectionEnabled = reflection && reflection->enable && rtDataValid; - auto aoEnabled = ao && ao->enable && (!ao->rt || rtDataValid); + auto aoEnabled = ao && ao->enable && (!ao->rt || rtDataValid) && !rtgiEnabled; auto ssgiEnabled = ssgi && ssgi->enable && !rtgiEnabled; bool ssgiAo = ssgiEnabled && ssgi->enableAo; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 27211e9e9..7ef90e0c0 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -141,7 +141,7 @@ namespace Atlas { // Wait as long as possible for this to finish JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); - JobSystem::WaitSpin(renderState->prepareBindlessTexturesJob); + JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); JobSystem::WaitSpin(renderState->bindlessOtherTextureMapUpdateJob); commandList->BindBuffers(renderState->triangleBuffers, 0, 1); if (renderState->textures.size()) @@ -461,7 +461,7 @@ namespace Atlas { JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); - JobSystem::WaitSpin(renderState->prepareBindlessTexturesJob); + JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); commandList->BindBuffer(pathTraceGlobalUniformBuffer, 1, 31); commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index 6cce24a63..eb586ce9f 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -18,6 +18,7 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Shadows"); + std::swap(prevLightMap, lightMap); lightMap.clear(); Ref shadowPass = renderList->PopPassFromQueue(RenderList::RenderPassType::Shadow); @@ -204,15 +205,13 @@ namespace Atlas { auto& light = entity.GetComponent(); auto& shadow = light.shadow; - /* - if (lightMap.contains(entity)) { - auto frameBuffer = lightMap[entity]; + if (prevLightMap.contains(entity)) { + auto frameBuffer = prevLightMap[entity]; if (frameBuffer->extent.width == shadow->resolution || frameBuffer->extent.height == shadow->resolution) { return frameBuffer; } } - */ Graphics::RenderPassDepthAttachment attachment = { .imageFormat = shadow->useCubemap ? shadow->cubemap->format : @@ -231,6 +230,7 @@ namespace Atlas { .depthAttachment = { shadow->useCubemap ? shadow->cubemap->image : shadow->maps->image, 0, true}, .extent = { uint32_t(shadow->resolution), uint32_t(shadow->resolution) } }; + return device->CreateFrameBuffer(frameBufferDesc); } diff --git a/src/engine/renderer/ShadowRenderer.h b/src/engine/renderer/ShadowRenderer.h index e31118aae..53f23aa81 100644 --- a/src/engine/renderer/ShadowRenderer.h +++ b/src/engine/renderer/ShadowRenderer.h @@ -43,12 +43,14 @@ namespace Atlas { uint32_t textureID; }; + LightMap prevLightMap; LightMap lightMap; ImpostorShadowRenderer impostorRenderer; std::vector> subDatas; + }; } diff --git a/src/engine/resource/ResourceManager.h b/src/engine/resource/ResourceManager.h index 0bb1e453f..9666301ab 100644 --- a/src/engine/resource/ResourceManager.h +++ b/src/engine/resource/ResourceManager.h @@ -26,7 +26,7 @@ namespace Atlas { static ResourceHandle GetResource(const std::string& path) { CheckInitialization(); - + auto relativePath = GetAssetDirectoryPath(path); std::lock_guard lock(mutex); if (resources.contains(relativePath)) { @@ -50,7 +50,7 @@ namespace Atlas { static ResourceHandle GetOrLoadResource(const std::string& path, ResourceOrigin origin, Args&&... args) { static_assert(std::is_constructible() || - std::is_constructible(), + std::is_constructible(), "Resource class needs to implement constructor with provided argument type"); CheckInitialization(); @@ -72,7 +72,7 @@ namespace Atlas { template static ResourceHandle GetOrLoadResourceWithLoader(const std::string& path, - Ref (*loaderFunction)(const std::string&, Args...), Args... args) { + Ref(*loaderFunction)(const std::string&, Args...), Args... args) { return GetOrLoadResourceWithLoader(path, System, std::function(loaderFunction), std::forward(args)...); @@ -80,7 +80,7 @@ namespace Atlas { template static ResourceHandle GetOrLoadResourceWithLoader(const std::string& path, ResourceOrigin origin, - Ref (*loaderFunction)(const std::string&, Args...), Args... args) { + Ref(*loaderFunction)(const std::string&, Args...), Args... args) { return GetOrLoadResourceWithLoader(path, origin, std::function(loaderFunction), std::forward(args)...); @@ -137,7 +137,7 @@ namespace Atlas { auto resource = GetResourceInternal(relativePath); JobSystem::Execute(resource->jobGroup, [resource, args...](JobData&) { resource->Load(args...); - }); + }); NotifyAllSubscribers(ResourceTopic::ResourceCreate, resource); handle = ResourceHandle(resource); } @@ -148,7 +148,7 @@ namespace Atlas { template static ResourceHandle GetOrLoadResourceWithLoaderAsync(const std::string& path, - Ref (*loaderFunction)(const std::string&, Args...), Args... args) { + Ref(*loaderFunction)(const std::string&, Args...), Args... args) { return GetOrLoadResourceWithLoaderAsync(path, System, std::function(loaderFunction), std::forward(args)...); @@ -156,7 +156,7 @@ namespace Atlas { template static ResourceHandle GetOrLoadResourceWithLoaderAsync(const std::string& path, ResourceOrigin origin, - Ref (*loaderFunction)(const std::string&, Args...), Args... args) { + Ref(*loaderFunction)(const std::string&, Args...), Args... args) { return GetOrLoadResourceWithLoaderAsync(path, origin, std::function(loaderFunction), std::forward(args)...); @@ -182,7 +182,7 @@ namespace Atlas { auto resource = GetResourceInternal(relativePath); JobSystem::Execute(resource->jobGroup, [resource, loaderFunction, args...](JobData&) { resource->LoadWithExternalLoader(loaderFunction, args...); - }); + }); NotifyAllSubscribers(ResourceTopic::ResourceCreate, resource); handle = ResourceHandle(resource); } @@ -206,7 +206,7 @@ namespace Atlas { { std::lock_guard lock(mutex); if (resources.contains(relativePath)) { - auto &resource = resources[relativePath]; + auto& resource = resources[relativePath]; resource->framesToDeletion = RESOURCE_RETENTION_FRAME_COUNT; alreadyExisted = true; return ResourceHandle(resource); @@ -284,7 +284,7 @@ namespace Atlas { subscribers->emplace_back(ResourceSubscriber{ .ID = subscriberCount, - .function = function + .function = function }); return subscriberCount++; @@ -300,7 +300,7 @@ namespace Atlas { auto item = std::find_if(subscribers->begin(), subscribers->end(), [&](ResourceSubscriber subscriber) { return subscriber.ID == subscriptionID; - }); + }); if (item != subscribers->end()) { subscribers->erase(item); @@ -321,6 +321,8 @@ namespace Atlas { static std::atomic_int subscriberCount; + static JobGroup deallocationJobs; + static inline void CheckInitialization() { if (isInitialized) return; @@ -363,8 +365,9 @@ namespace Atlas { std::lock_guard lock(mutex); - for (auto it = resources.begin(); it != resources.end();) { - auto& resource = it->second; + // First loop to count and update the resources + size_t resourceUnloadCount = 0; + for (auto& [_, resource] : resources) { // Just one reference (the resource manager), so start countdown for future deletion // If resource is accessed in certain time frame we reset the counter if (resource.use_count() == 1 && !resource->permanent) { @@ -374,22 +377,43 @@ namespace Atlas { resource->framesToDeletion = RESOURCE_RETENTION_FRAME_COUNT; } + if (resource.use_count() == 1 && resource->framesToDeletion == 0) { + resourceUnloadCount++; + } + } + + std::vector>> resourcesToUnload; + resourcesToUnload.reserve(resourceUnloadCount); + + // Second loop for actual removal + for (auto it = resources.begin(); it != resources.end();) { + auto& resource = it->second; + // Delete if all conditions are met if (resource.use_count() == 1 && resource->framesToDeletion == 0) { NotifyAllSubscribers(ResourceTopic::ResourceDestroy, resource); AE_ASSERT(resource.use_count() == 1 && "Subscribers shouldn't claim ownership of to be deleted resources"); - resource->Unload(); + resourcesToUnload.push_back(resource); it = resources.erase(it); } else { ++it; } } + + // This is kind of fucked up, but we can avoid unwanted spikes when a bunch of data is suddenly needed anymore + // Also we shouldn't unload them multi-threaded, so not one job per resource. + if (!resourcesToUnload.empty()) { + JobSystem::Execute(deallocationJobs, [resourcesToUnload = std::move(resourcesToUnload)](JobData&) { + for (auto& resource : resourcesToUnload) + resource->Unload(); + }); + } } static void ShutdownHandler() { - + for (const auto& [_, resource] : resources) { if (!resource->future.valid()) continue; @@ -449,4 +473,7 @@ namespace Atlas { template std::atomic_int ResourceManager::subscriberCount = 0; + template + JobGroup ResourceManager::deallocationJobs{ JobPriority::Low }; + } \ No newline at end of file diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 5299ff6fb..f597d9aef 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -463,6 +463,7 @@ namespace Atlas { if (terrain) { auto terrainMaterials = terrain->storage.GetMaterials(); + materials.reserve(terrainMaterials.size()); for (const auto& material : terrainMaterials) { if (!material) @@ -472,12 +473,14 @@ namespace Atlas { } } - + auto meshes = GetMeshes(); if (clutter) { auto vegMeshes = clutter->GetMeshes(); meshes.insert(meshes.end(), vegMeshes.begin(), vegMeshes.end()); } + + materials.reserve(materials.size() + meshes.size()); for (const auto& mesh : meshes) { if (!mesh.IsLoaded()) diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 8b51f8572..bd5852e0e 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -197,8 +197,8 @@ namespace Atlas::Scene { for (const auto& mesh : meshes) { if (!mesh.IsLoaded()) continue; - // Not all meshes might have a bvh - if (!mesh->IsBVHBuilt()) + // Not all meshes might have a bvh and not all blases will be built in frame, so skip them if they are not ready + if (!mesh->IsBVHBuilt() || mesh->IsBVHBuilt() && !mesh->blas->isDynamic && !mesh->blas->isBuilt) continue; meshIdToBindlessIdx[mesh.GetID()] = bufferIdx++; @@ -215,24 +215,13 @@ namespace Atlas::Scene { void SceneRenderState::UpdateTextureBindlessData() { - auto bindlessTextureBuffersUpdate = [&](JobData&) { - JobSystem::Wait(bindlessTextureMapUpdateJob); - - if (textures.size() != textureToBindlessIdx.size()) { - textures.resize(textureToBindlessIdx.size()); - } - - for (const auto& [texture, idx] : textureToBindlessIdx) - textures[idx] = texture->image; - - }; - - auto bindlessTextureMapUpdate = [&, bindlessTextureBuffersUpdate](JobData&) { + auto bindlessTextureMapUpdate = [&](JobData&) { auto meshes = scene->GetMeshes(); textureToBindlessIdx.clear(); + textures.clear(); - std::set> materials; - std::set> textures; + std::set> materialSet; + std::set> textureSet; uint32_t textureIdx = 0; for (const auto& mesh : meshes) { @@ -240,40 +229,39 @@ namespace Atlas::Scene { for (auto& material : mesh->data.materials) if (material.IsLoaded()) - materials.insert(material.Get()); + materialSet.insert(material.Get()); } - for (const auto& material : materials) { + for (const auto& material : materialSet) { if (material->HasBaseColorMap()) - textures.insert(material->baseColorMap.Get()); + textureSet.insert(material->baseColorMap.Get()); if (material->HasOpacityMap()) - textures.insert(material->opacityMap.Get()); + textureSet.insert(material->opacityMap.Get()); if (material->HasNormalMap()) - textures.insert(material->normalMap.Get()); + textureSet.insert(material->normalMap.Get()); if (material->HasRoughnessMap()) - textures.insert(material->roughnessMap.Get()); + textureSet.insert(material->roughnessMap.Get()); if (material->HasMetalnessMap()) - textures.insert(material->metalnessMap.Get()); + textureSet.insert(material->metalnessMap.Get()); if (material->HasAoMap()) - textures.insert(material->aoMap.Get()); + textureSet.insert(material->aoMap.Get()); if (material->HasDisplacementMap()) - textures.insert(material->displacementMap.Get()); + textureSet.insert(material->displacementMap.Get()); if (material->HasEmissiveMap()) - textures.insert(material->emissiveMap.Get()); + textureSet.insert(material->emissiveMap.Get()); } - for (const auto& texture : textures) { + for (const auto& texture : textureSet) { textureToBindlessIdx[texture] = textureIdx++; + textures.push_back(texture->image); } }; JobSystem::Wait(bindlessTextureMapUpdateJob); - JobSystem::Wait(prepareBindlessTexturesJob); JobSystem::Execute(bindlessTextureMapUpdateJob, bindlessTextureMapUpdate); - JobSystem::Execute(prepareBindlessTexturesJob, bindlessTextureBuffersUpdate); } @@ -287,6 +275,9 @@ namespace Atlas::Scene { cubemapToBindlessIdx.clear(); textureArrayToBindlessIdx.clear(); + cubemaps.clear(); + textureArrays.clear(); + uint32_t textureArrayIdx = 0; uint32_t cubemapIdx = 0; for (auto entity : lightSubset) { @@ -297,22 +288,13 @@ namespace Atlas::Scene { if (lightComponent.shadow->useCubemap) { cubemapToBindlessIdx[lightComponent.shadow->cubemap] = cubemapIdx++; + cubemaps.push_back(lightComponent.shadow->cubemap->image); } else { textureArrayToBindlessIdx[lightComponent.shadow->maps] = textureArrayIdx++; + textureArrays.push_back(lightComponent.shadow->maps->image); } } - - if (cubemaps.size() != cubemapIdx) - cubemaps.resize(cubemapIdx); - for (const auto& [cubemap, idx] : cubemapToBindlessIdx) - cubemaps[idx] = cubemap->image; - - if (textureArrays.size() != textureArrayIdx) - textureArrays.resize(textureArrayIdx); - for (const auto& [textureArray, idx] : textureArrayToBindlessIdx) - textureArrays[idx] = textureArray->image; - }); } @@ -383,6 +365,7 @@ namespace Atlas::Scene { auto& camera = scene->GetMainCamera(); lightEntities.clear(); + lightEntities.reserve(scene->GetComponentCount()); auto lightSubset = scene->GetSubset(); for (auto& lightEntity : lightSubset) { auto& light = lightEntity.GetComponent(); @@ -479,8 +462,13 @@ namespace Atlas::Scene { abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; shadowUniform.cascades[i].distance = cascade->farDistance; if (light.type == LightType::DirectionalLight) { - shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * - cascade->viewMatrix * camera.invViewMatrix); + auto matrix = cascade->projectionMatrix * + cascade->viewMatrix * camera.invViewMatrix; + shadowUniform.cascades[i].cascadeSpace = glm::transpose(matrix); + + mat4 reTransposed = mat4(glm::transpose(shadowUniform.cascades[i].cascadeSpace)); + + AE_ASSERT(reTransposed == matrix); } shadowUniform.cascades[i].texelSize = texelSize; } @@ -579,7 +567,6 @@ namespace Atlas::Scene { JobSystem::Wait(materialUpdateJob); JobSystem::Wait(rayTracingWorldUpdateJob); JobSystem::Wait(prepareBindlessMeshesJob); - JobSystem::Wait(prepareBindlessTexturesJob); JobSystem::Wait(fillRenderListJob); JobSystem::Wait(cullAndSortLightsJob); diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index 99eb5c062..44c42b629 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -79,7 +79,6 @@ namespace Atlas::Scene { JobGroup bindlessTextureMapUpdateJob{ JobPriority::High }; JobGroup bindlessOtherTextureMapUpdateJob{ JobPriority::High }; JobGroup prepareBindlessMeshesJob{ JobPriority::High }; - JobGroup prepareBindlessTexturesJob{ JobPriority::High }; JobGroup fillRenderListJob{ JobPriority::High }; JobGroup cullAndSortLightsJob{ JobPriority::High }; diff --git a/src/engine/scene/components/CameraComponent.cpp b/src/engine/scene/components/CameraComponent.cpp index 0a80657bc..1818dc2e3 100644 --- a/src/engine/scene/components/CameraComponent.cpp +++ b/src/engine/scene/components/CameraComponent.cpp @@ -128,9 +128,9 @@ namespace Atlas { } - std::vector CameraComponent::GetFrustumCorners(float nearPlane, float farPlane) const { + std::array CameraComponent::GetFrustumCorners(float nearPlane, float farPlane) const { - std::vector corners; + std::array corners; float radians = glm::radians(fieldOfView) / 2.0f; float tang = tanf(radians); @@ -144,15 +144,15 @@ namespace Atlas { vec3 farPoint = cameraLocation + globalDirection * farPlane; vec3 nearPoint = cameraLocation + globalDirection * nearPlane; - corners.push_back(farPoint + farHeight * globalUp - farWidth * globalRight); - corners.push_back(farPoint + farHeight * globalUp + farWidth * globalRight); - corners.push_back(farPoint - farHeight * globalUp - farWidth * globalRight); - corners.push_back(farPoint - farHeight * globalUp + farWidth * globalRight); + corners[0] = farPoint + farHeight * globalUp - farWidth * globalRight; + corners[1] = farPoint + farHeight * globalUp + farWidth * globalRight; + corners[2] = farPoint - farHeight * globalUp - farWidth * globalRight; + corners[3] = farPoint - farHeight * globalUp + farWidth * globalRight; - corners.push_back(nearPoint + nearHeight * globalUp - nearWidth * globalRight); - corners.push_back(nearPoint + nearHeight * globalUp + nearWidth * globalRight); - corners.push_back(nearPoint - nearHeight * globalUp - nearWidth * globalRight); - corners.push_back(nearPoint - nearHeight * globalUp + nearWidth * globalRight); + corners[4] = nearPoint + nearHeight * globalUp - nearWidth * globalRight; + corners[5] = nearPoint + nearHeight * globalUp + nearWidth * globalRight; + corners[6] = nearPoint - nearHeight * globalUp - nearWidth * globalRight; + corners[7] = nearPoint - nearHeight * globalUp + nearWidth * globalRight; return corners; diff --git a/src/engine/scene/components/CameraComponent.h b/src/engine/scene/components/CameraComponent.h index 396931725..928d16eb4 100644 --- a/src/engine/scene/components/CameraComponent.h +++ b/src/engine/scene/components/CameraComponent.h @@ -35,7 +35,7 @@ namespace Atlas { vec3 GetLastLocation() const; - std::vector GetFrustumCorners(float nearPlane, float farPlane) const; + std::array GetFrustumCorners(float nearPlane, float farPlane) const; void UpdateFrustum(); diff --git a/src/engine/scene/components/LightComponent.cpp b/src/engine/scene/components/LightComponent.cpp index 9ebc23e39..01b643344 100644 --- a/src/engine/scene/components/LightComponent.cpp +++ b/src/engine/scene/components/LightComponent.cpp @@ -214,7 +214,7 @@ namespace Atlas { vec3 up = vec3(1e-12f, 1.0f, 1e-12f); cascade.viewMatrix = glm::lookAt(cascadeCenter, cascadeCenter + lightDirection, up); - std::vector corners = camera.GetFrustumCorners(cascade.nearDistance, + auto corners = camera.GetFrustumCorners(cascade.nearDistance, cascade.farDistance + shadow->cascadeBlendDistance); vec3 maxProj = vec3(cascade.viewMatrix * vec4(corners.at(0), 1.0f)); diff --git a/src/engine/scripting/bindings/UtilityBindings.cpp b/src/engine/scripting/bindings/UtilityBindings.cpp index da5c9017c..46c363605 100644 --- a/src/engine/scripting/bindings/UtilityBindings.cpp +++ b/src/engine/scripting/bindings/UtilityBindings.cpp @@ -72,13 +72,13 @@ namespace Atlas::Scripting::Bindings { ); auto resizeFrustumOverload = sol::overload( - [](Volume::Frustum& frustum, const std::vector& corners) { frustum.Resize(corners); }, + [](Volume::Frustum& frustum, const std::array& corners) { frustum.Resize(corners); }, [](Volume::Frustum& frustum, const mat4& matrix) { frustum.Resize(matrix); } ); ns->new_usertype("Frustum", sol::call_constructor, - sol::constructors&), Volume::Frustum(glm::mat4)>(), + sol::constructors&), Volume::Frustum(glm::mat4)>(), "Resize", resizeFrustumOverload, "Intersects", &Volume::Frustum::Intersects, "IsInside", &Volume::Frustum::IsInside, diff --git a/src/engine/volume/BVH.cpp b/src/engine/volume/BVH.cpp index 3a78c0103..4c6c2746a 100644 --- a/src/engine/volume/BVH.cpp +++ b/src/engine/volume/BVH.cpp @@ -412,6 +412,9 @@ namespace Atlas { refs[refs.size() - 1].endOfNode = true; } else { + if (!leftChild || !rightChild) + return; + const auto nodeIdx = nodes.size(); nodes.push_back(BVHNode()); diff --git a/src/engine/volume/Frustum.cpp b/src/engine/volume/Frustum.cpp index f6b9ad763..a729d5aae 100644 --- a/src/engine/volume/Frustum.cpp +++ b/src/engine/volume/Frustum.cpp @@ -4,7 +4,7 @@ namespace Atlas { namespace Volume { - Frustum::Frustum(const std::vector& corners) { + Frustum::Frustum(const std::array& corners) { Resize(corners); @@ -16,7 +16,7 @@ namespace Atlas { } - void Frustum::Resize(const std::vector& corners) { + void Frustum::Resize(const std::array& corners) { this->corners = corners; planes[NEAR_PLANE] = Plane(corners[4], corners[5], corners[7]); @@ -80,6 +80,7 @@ namespace Atlas { std::vector Frustum::GetPlanes() const { std::vector planes; + planes.reserve(6); for (uint8_t i = 0; i < 6; i++) { planes.push_back(vec4(this->planes[i].normal, @@ -90,7 +91,7 @@ namespace Atlas { } - std::vector Frustum::GetCorners() const { + std::array Frustum::GetCorners() const { return corners; @@ -110,12 +111,11 @@ namespace Atlas { vec3(1.0f, -1.0f, 1.0f) }; - corners.clear(); auto inverseMatrix = glm::inverse(matrix); for (uint8_t i = 0; i < 8; i++) { auto homogenous = inverseMatrix * vec4(vectors[i], 1.0f); - corners.push_back(vec3(homogenous) / homogenous.w); + corners[i] = vec3(homogenous) / homogenous.w; } } diff --git a/src/engine/volume/Frustum.h b/src/engine/volume/Frustum.h index c90b604cb..8ac81a636 100644 --- a/src/engine/volume/Frustum.h +++ b/src/engine/volume/Frustum.h @@ -5,6 +5,8 @@ #include "AABB.h" #include +#include +#include namespace Atlas { @@ -26,7 +28,7 @@ namespace Atlas { * Far plane: Upper left, upper right, bottom left, bottom right * Near plane: Upper left, upper right, bottom left, bottom right */ - explicit Frustum(const std::vector& corners); + explicit Frustum(const std::array& corners); /** * Constructs a Frustum object. @@ -42,7 +44,7 @@ namespace Atlas { * Far plane: Upper left, upper right, bottom left, bottom right * Near plane: Upper left, upper right, bottom left, bottom right */ - void Resize(const std::vector& corners); + void Resize(const std::array& corners); /** * Resizes the frustum. @@ -80,7 +82,7 @@ namespace Atlas { * Far plane: Upper left, upper right, bottom left, bottom right * Near plane: Upper left, upper right, bottom left, bottom right */ - std::vector GetCorners() const; + std::array GetCorners() const; private: void CalculateCorners(const mat4& matrix); @@ -104,7 +106,7 @@ namespace Atlas { float distance = 0.0f; }; - std::vector corners; + std::array corners; Plane planes[6]; }; From 17d418b3c570a3a5a25a15e34ade63a3d3b4d460 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Wed, 16 Oct 2024 19:40:57 +0200 Subject: [PATCH 54/66] Improved tests --- data/shader/raytracer/structures.hsh | 8 +++++++- data/shader/raytracer/surface.hsh | 3 ++- data/shader/text.vsh | 4 ++-- src/engine/buffer/Buffer.cpp | 1 + src/engine/graphics/Buffer.cpp | 2 +- src/engine/graphics/Buffer.h | 2 ++ src/engine/graphics/Instance.cpp | 5 +++-- src/engine/loader/ModelImporter.cpp | 18 +++++++++++++++++- src/engine/raytracing/RTStructures.h | 4 +++- src/engine/raytracing/RayTracingWorld.cpp | 2 ++ src/engine/renderer/MainRenderer.cpp | 2 -- src/engine/renderer/MainRenderer.h | 2 -- src/engine/renderer/VolumetricRenderer.cpp | 13 ++++++++----- src/engine/scene/SceneRenderState.cpp | 10 +++++++++- src/tests/App.cpp | 10 +++++----- src/tests/App.h | 5 +++-- src/tests/Main.cpp | 4 +--- 17 files changed, 66 insertions(+), 29 deletions(-) diff --git a/data/shader/raytracer/structures.hsh b/data/shader/raytracer/structures.hsh index 1410eefe3..5a0f40b69 100644 --- a/data/shader/raytracer/structures.hsh +++ b/data/shader/raytracer/structures.hsh @@ -122,7 +122,9 @@ struct RaytraceMaterial { float reflectance; float normalScale; - + + float tiling; + int invertUVs; int twoSided; int cullBackFaces; @@ -136,6 +138,10 @@ struct RaytraceMaterial { int aoTexture; int emissiveTexture; + int padding0; + int padding1; + int padding2; + }; struct PackedLight { diff --git a/data/shader/raytracer/surface.hsh b/data/shader/raytracer/surface.hsh index e7b4dc462..5d63d9062 100644 --- a/data/shader/raytracer/surface.hsh +++ b/data/shader/raytracer/surface.hsh @@ -88,6 +88,7 @@ Surface GetSurfaceParameters(Instance instance, Triangle tri, Ray ray, vec4 vertexColor = r * tri.color0 + s * tri.color1 + t * tri.color2; texCoord = rayMat.invertUVs > 0 ? vec2(texCoord.x, 1.0 - texCoord.y) : texCoord; + texCoord *= rayMat.tiling; // Produces some problems in the bottom left corner of the Sponza scene, // but fixes the cube. Should work in theory. @@ -157,6 +158,6 @@ float GetOpacity(Triangle tri, vec2 barrycentric, int materialOffset, int textur vec2 texCoord = r * tri.uv0 + s * tri.uv1 + t * tri.uv2; texCoord = rayMat.invertUVs > 0 ? vec2(texCoord.x, 1.0 - texCoord.y) : texCoord; - return SampleOpacityBilinear(rayMat.opacityTexture, float(textureLevel), texCoord) + return SampleOpacityBilinear(rayMat.opacityTexture, float(textureLevel), texCoord * rayMat.tiling) * rayMat.opacity; } \ No newline at end of file diff --git a/data/shader/text.vsh b/data/shader/text.vsh index ea5276f3a..ec84c473f 100644 --- a/data/shader/text.vsh +++ b/data/shader/text.vsh @@ -12,11 +12,11 @@ struct GlyphInfo { vec2 size; }; -layout (set = 3, binding = 1, std430) buffer GlyphBuffer { +layout (set = 3, binding = 1, std430) readonly buffer GlyphBuffer { GlyphInfo glyphs[]; }; -layout (set = 3, binding = 2, std430) buffer InstancesBuffer { +layout (set = 3, binding = 2, std430) readonly buffer InstancesBuffer { vec4 instances[]; }; diff --git a/src/engine/buffer/Buffer.cpp b/src/engine/buffer/Buffer.cpp index f17290f21..6f5fa27dd 100644 --- a/src/engine/buffer/Buffer.cpp +++ b/src/engine/buffer/Buffer.cpp @@ -202,6 +202,7 @@ namespace Atlas { .usageFlags = usageFlags | VK_BUFFER_USAGE_TRANSFER_DST_BIT, .domain = hostAccessible ? Graphics::BufferDomain::Host : Graphics::BufferDomain::Device, .data = data, + .dataSize = elementCount * elementSize, .size = sizeInBytes, .dedicatedMemory = (usageFlags & BufferUsageBits::DedicatedMemoryBit) > 0, .priority = (usageFlags & BufferUsageBits::HighPriorityMemoryBit) > 0 ? 1.0f : 0.5f diff --git a/src/engine/graphics/Buffer.cpp b/src/engine/graphics/Buffer.cpp index 09fed833b..5940daf37 100644 --- a/src/engine/graphics/Buffer.cpp +++ b/src/engine/graphics/Buffer.cpp @@ -42,7 +42,7 @@ namespace Atlas { &allocationCreateInfo, alignment, &buffer, &allocation, nullptr)) } - if (desc.data) SetData(desc.data, 0, desc.size); + if (desc.data) SetData(desc.data, 0, desc.dataSize > 0 ? desc.dataSize : desc.size); } diff --git a/src/engine/graphics/Buffer.h b/src/engine/graphics/Buffer.h index d6768eff2..48428b6ba 100644 --- a/src/engine/graphics/Buffer.h +++ b/src/engine/graphics/Buffer.h @@ -29,6 +29,8 @@ namespace Atlas { BufferHostAccess hostAccess = BufferHostAccess::Sequential; void* data = nullptr; + size_t dataSize = 0; + size_t size; size_t alignment = 0; diff --git a/src/engine/graphics/Instance.cpp b/src/engine/graphics/Instance.cpp index edc572f4c..61d90ab97 100644 --- a/src/engine/graphics/Instance.cpp +++ b/src/engine/graphics/Instance.cpp @@ -96,8 +96,9 @@ namespace Atlas { #ifdef AE_BUILDTYPE_DEBUG validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; - validationFeatures.enabledValidationFeatureCount = std::size(enables); - validationFeatures.pEnabledValidationFeatures = enables; + // This doesn't seem to work anymore with newer VulkanSDKs on Nvidia hardware + //validationFeatures.enabledValidationFeatureCount = std::size(enables); + //validationFeatures.pEnabledValidationFeatures = enables; structureChainBuilder.Append(validationFeatures); #endif diff --git a/src/engine/loader/ModelImporter.cpp b/src/engine/loader/ModelImporter.cpp index c046148c7..0656fe10d 100644 --- a/src/engine/loader/ModelImporter.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -415,6 +415,12 @@ namespace Atlas { lightMap[light->mName.C_Str()] = light; } + std::map cameraMap; + for (uint32_t i = 0; i < state.scene->mNumCameras; i++) { + auto camera = state.scene->mCameras[i]; + cameraMap[camera->mName.C_Str()] = camera; + } + auto rootEntity = scene->CreateEntity(); rootEntity.AddComponent("Root"); auto& rootHierarchy = rootEntity.AddComponent(); @@ -472,7 +478,17 @@ namespace Atlas { lightComp.properties.point.radius = std::max(glm::sqrt(100.0f * light->mAttenuationQuadratic), intensityRadius); lightComp.AddSpotShadow(3.0f, 1024); } - } + } + + if (cameraMap.contains(node->mName.C_Str())) { + auto camera = cameraMap[node->mName.C_Str()]; + + float verticalFOV = glm::degrees(camera->mHorizontalFOV) / camera->mAspect; + vec3 position = vec3(camera->mPosition.x, camera->mPosition.y, camera->mPosition.z); + vec2 rotation = vec2(0.0f); + parentEntity.AddComponent(verticalFOV, camera->mAspect, camera->mClipPlaneNear, + camera->mClipPlaneFar, position, rotation); + } for (uint32_t i = 0; i < node->mNumChildren; i++) { auto nodeEntity = scene->CreatePrefab(node->mChildren[i]->mName.C_Str(), nodeTransform); diff --git a/src/engine/raytracing/RTStructures.h b/src/engine/raytracing/RTStructures.h index 90e5ccae0..46b069110 100644 --- a/src/engine/raytracing/RTStructures.h +++ b/src/engine/raytracing/RTStructures.h @@ -48,7 +48,7 @@ namespace Atlas { int32_t valid = -1; }; - struct GPUMaterial { + struct alignas(16) GPUMaterial { int32_t ID = 0; vec3 baseColor = vec3(1.0f); @@ -64,6 +64,8 @@ namespace Atlas { float normalScale = 1.0f; + float tiling = 1.0f; + int32_t invertUVs = 0; int32_t twoSided = 0; int32_t cullBackFaces = 0; diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index d94b2c103..ec7208ccb 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -244,6 +244,8 @@ namespace Atlas { gpuMaterial.normalScale = material->normalScale; + gpuMaterial.tiling = material->tiling; + gpuMaterial.invertUVs = mesh->invertUVs ? 1 : 0; gpuMaterial.twoSided = material->twoSided ? 1 : 0; gpuMaterial.cullBackFaces = mesh->cullBackFaces ? 1 : 0; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 7ef90e0c0..25fda6f4f 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -62,8 +62,6 @@ namespace Atlas { textRenderer.Init(device); textureRenderer.Init(device); - font = Atlas::CreateRef("font/roboto.ttf", 22.0f, 5); - } void MainRenderer::RenderScene(Ref viewport, Ref target, Ref scene, diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index 1b702f22d..a89d02db5 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -66,8 +66,6 @@ namespace Atlas { AtmosphereRenderer atmosphereRenderer; PathTracingRenderer pathTracingRenderer; - Ref font; - private: void CreateGlobalDescriptorSetLayout(); diff --git a/src/engine/renderer/VolumetricRenderer.cpp b/src/engine/renderer/VolumetricRenderer.cpp index 982e49026..b65c7c9d4 100644 --- a/src/engine/renderer/VolumetricRenderer.cpp +++ b/src/engine/renderer/VolumetricRenderer.cpp @@ -79,13 +79,16 @@ namespace Atlas { auto mainLightEntity = GetMainLightEntity(scene); VolumetricUniforms uniforms; - uniforms.sampleCount = fog->rayMarchStepCount; - uniforms.intensity = fog->volumetricIntensity; + uniforms.sampleCount = fog ? fog->rayMarchStepCount : 1; + uniforms.intensity = fog ? fog->volumetricIntensity : 0.0f; uniforms.lightCount = std::min(128, int32_t(renderState->volumetricLights.size())); uniforms.directionalLightCount = 0; - for (const auto& lightEntity : renderState->lightEntities) { - if (lightEntity.comp.type != LightType::DirectionalLight) + for (auto& light : renderState->volumetricLights) { + auto packedType = reinterpret_cast(light.color.a); + auto type = static_cast(packedType); + + if (type != LightType::DirectionalLight) break; uniforms.directionalLightCount++; @@ -213,7 +216,7 @@ namespace Atlas { volumetricPipelineConfig.ManageMacro("CLOUDS", cloudsEnabled); volumetricPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowsEnabled); volumetricPipelineConfig.ManageMacro("OCEAN", oceanEnabled); - volumetricPipelineConfig.ManageMacro("LOCAL_LIGHTS", fog->localLights); + volumetricPipelineConfig.ManageMacro("LOCAL_LIGHTS", fogEnabled && fog->localLights); auto volumetricPipeline = PipelineManager::GetPipeline(volumetricPipelineConfig); commandList->BindPipeline(volumetricPipeline); diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index bd5852e0e..f217d43b2 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -521,7 +521,7 @@ namespace Atlas::Scene { // We need to have at least a fake light auto type = 0; auto packedType = reinterpret_cast(type); - lights.push_back(Renderer::Light { + lights.emplace_back(Renderer::Light { .direction = vec4(0.0f, -1.0f, 0.0f, 0.0f), .color = vec4(vec3(0.0f), packedType), .intensity = 0.0f, @@ -536,6 +536,14 @@ namespace Atlas::Scene { lightBuffer.SetData(lights.data(), 0, lights.size()); } + if (volumetricLights.empty()) { + volumetricLights.emplace_back(Renderer::VolumetricLight { + .intensity = 0.0f, + .shadowIdx = -1, + }); + volumetricShadows.emplace_back(Renderer::Shadow {}); + } + if (volumetricLightBuffer.GetElementCount() < volumetricLights.size()) { volumetricLightBuffer = Buffer::Buffer(Buffer::BufferUsageBits::HostAccessBit | Buffer::BufferUsageBits::MultiBufferedBit | Buffer::BufferUsageBits::StorageBufferBit, sizeof(Renderer::VolumetricLight), volumetricLights.size(), volumetricLights.data()); diff --git a/src/tests/App.cpp b/src/tests/App.cpp index 5f20fca7f..7fb4c4136 100644 --- a/src/tests/App.cpp +++ b/src/tests/App.cpp @@ -21,12 +21,12 @@ void App::LoadContent(AppConfiguration config) { viewport = Atlas::CreateRef(0, 0, renderTarget->GetWidth(), renderTarget->GetHeight()); - auto icon = Atlas::Texture::Texture2D("icon.png"); + auto icon = Atlas::ResourceManager::GetOrLoadResource("icon.png"); window.SetIcon(&icon); loadingTexture = Atlas::CreateRef("loading.png"); - font = Atlas::CreateRef("font/roboto.ttf", 22.0f, 5); + font = Atlas::ResourceManager::GetOrLoadResource("font/roboto.ttf", 22.0f, 5); scene = Atlas::CreateRef("testscene", glm::vec3(-2048.0f), glm::vec3(2048.0f)); @@ -126,7 +126,7 @@ void App::LoadContent(AppConfiguration config) { if (config.ocean) { scene->ocean = Atlas::CreateRef(9, 4096.0f, - glm::vec3(0.0f, 5.0f, 0.0f), 512, 86); + glm::vec3(0.0f, 5.0f, 0.0f), 128, 86); } scene->physicsWorld = Atlas::CreateRef(); @@ -274,7 +274,7 @@ void App::DisplayLoadingScreen(float deltaTime) { rotation += deltaTime * abs(sin(Atlas::Clock::Get())) * 10.0f; mainRenderer->textureRenderer.RenderTexture2D(commandList, viewport, - loadingTexture.get(), x, y, width, height, rotation); + loadingTexture.Get().get(), x, y, width, height, rotation); float textWidth, textHeight; font->ComputeDimensions("Loading...", 2.0f, &textWidth, &textHeight); @@ -283,7 +283,7 @@ void App::DisplayLoadingScreen(float deltaTime) { y = windowSize.y / 2 - textHeight / 2 + float(loadingTexture->height) + 20.0f; viewport->Set(0, 0, windowSize.x, windowSize.y); - mainRenderer->textRenderer.Render(commandList, viewport, font, + mainRenderer->textRenderer.Render(commandList, viewport, font.Get(), "Loading...", x, y, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), 2.0f); commandList->EndRenderPass(); diff --git a/src/tests/App.h b/src/tests/App.h index 3a0f37d64..727c2bae5 100644 --- a/src/tests/App.h +++ b/src/tests/App.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,7 @@ class App : public Atlas::EngineInstance { Ref renderTarget; Ref viewport; - Ref font; + Atlas::ResourceHandle font; Ref scene; @@ -76,7 +77,7 @@ class App : public Atlas::EngineInstance { Atlas::Input::MouseHandler mouseHandler; Atlas::Input::KeyboardHandler keyboardHandler; - Ref loadingTexture; + Atlas::ResourceHandle loadingTexture; Atlas::Renderer::ExampleRenderer exampleRenderer; diff --git a/src/tests/Main.cpp b/src/tests/Main.cpp index 089940848..1a1bb892c 100644 --- a/src/tests/Main.cpp +++ b/src/tests/Main.cpp @@ -29,8 +29,6 @@ class EngineEndToEndTest : public testing::TestWithParam { void TearDown() override { delete engineInstance; - Atlas::PipelineManager::Clear(); - graphicsDevice->ForceMemoryCleanup(); } @@ -107,7 +105,7 @@ auto testingValues = testing::Values( AppConfiguration { .recreateSwapchain = true }, AppConfiguration { .resize = true }, AppConfiguration { .exampleRenderer = true }, - AppConfiguration{ .minimizeWindow = true } + AppConfiguration { .minimizeWindow = true } ); INSTANTIATE_TEST_SUITE_P(DemoTestSuite, EngineEndToEndTest, testingValues); From 2d67be55f5fb9c5ca83f39272484996df4a71744 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 17 Oct 2024 20:07:05 +0200 Subject: [PATCH 55/66] SSR support --- data/shader/common/ign.hsh | 9 + data/shader/common/traceScreenSpace.hsh | 263 +++ data/shader/globals.hsh | 2 + data/shader/reflection/rtreflection.csh | 12 +- data/shader/reflection/ssr.csh | 174 ++ data/shader/reflection/temporal.csh | 2 +- src/demo/App.h | 4 +- src/engine/renderer/MainRenderer.cpp | 1869 +++++++++-------- src/engine/renderer/RTReflectionRenderer.cpp | 132 +- src/engine/renderer/RTReflectionRenderer.h | 1 + src/engine/renderer/helper/CommonStructures.h | 2 + 11 files changed, 1481 insertions(+), 989 deletions(-) create mode 100644 data/shader/common/traceScreenSpace.hsh create mode 100644 data/shader/reflection/ssr.csh diff --git a/data/shader/common/ign.hsh b/data/shader/common/ign.hsh index 1cd603c63..9f36a67b1 100644 --- a/data/shader/common/ign.hsh +++ b/data/shader/common/ign.hsh @@ -6,6 +6,15 @@ float GetInterleavedGradientNoise(vec2 screenPos) { float x = float(screenPos.x) + 5.588238 * float(frame); float y = float(screenPos.y) + 5.588238 * float(frame); + vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189); + return fract(magic.z * fract(dot(vec2(x, y), magic.xy))); +} + +float GetInterleavedGradientNoise(vec2 screenPos, uint frameCount) { + uint frame = globalData.frameCount % frameCount; + float x = float(screenPos.x) + 5.588238 * float(frame); + float y = float(screenPos.y) + 5.588238 * float(frame); + vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189); return fract(magic.z * fract(dot(vec2(x, y), magic.xy))); } \ No newline at end of file diff --git a/data/shader/common/traceScreenSpace.hsh b/data/shader/common/traceScreenSpace.hsh new file mode 100644 index 000000000..1804ef724 --- /dev/null +++ b/data/shader/common/traceScreenSpace.hsh @@ -0,0 +1,263 @@ +// By Morgan McGuire and Michael Mara at Williams College 2014 +// Released as open source under the BSD 2-Clause License +// http://opensource.org/licenses/BSD-2-Clause + +// Some ideas: https://willpgfx.com/2015/07/screen-space-glossy-reflections/ +// More: https://interplayoflight.wordpress.com/2019/09/07/hybrid-screen-space-reflections/ + +#include +#include <../globals.hsh> + +#define point2 vec2 +#define point3 vec3 + +float distanceSquared(vec2 a, vec2 b) { a -= b; return dot(a, a); } + +bool intersectsDepthBuffer(float z, float minZ, float maxZ, float thickness, float strideCutoff) { + /* + * Based on how far away from the camera the depth is, + * adding a bit of extra thickness can help improve some + * artifacts. Driving this value up too high can cause + * artifacts of its own. + */ + float depthScale = min(1.0f, z * strideCutoff); + //thickness *= mix(0.0f, 2.0f, depthScale); + return (maxZ >= z - thickness) && (minZ < z); +} + +// Returns true if the ray hit something +bool traceScreenSpace( + // Camera-space ray origin, which must be within the view volume + point3 csOrig, + + // Unit length camera-space ray direction + vec3 csDir, + + // The camera-space Z buffer (all negative values) + sampler2D csZBuffer, + + // Camera space thickness to ascribe to each pixel in the depth buffer + float zThickness, + + // Step in horizontal or vertical pixels between samples. This is a float + // because integer math is slow on GPUs, but should be set to an integer >= 1 + float stride, + + // Number between 0 and 1 for how far to bump the ray in stride units + // to conceal banding artifacts + float jitter, + + // Maximum number of iterations. Higher gives better images but may be slow + const float maxSteps, + + // Maximum camera-space distance to trace before returning a miss + float maxDistance, + + // Pixel coordinates of the first intersection with the scene + out point2 hitPixel, + + // Camera space location of the ray hit + out point3 hitPoint, + + out point3 minPoint, + + out point3 maxPoint) { + + // Clip to the near plane + float rayLength = ((csOrig.z + csDir.z * maxDistance) > -globalData.cameraNearPlane) ? + (-globalData.cameraNearPlane - csOrig.z) / csDir.z : maxDistance; + point3 csEndPoint = csOrig + csDir * rayLength; + + vec2 csZBufferSize = vec2(textureSize(csZBuffer, 0)); + + // Project into homogeneous clip space + vec4 H0 = globalData.pMatrix * vec4(csOrig, 1.0); + vec4 H1 = globalData.pMatrix * vec4(csEndPoint, 1.0); + float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w; + + // The interpolated homogeneous version of the camera-space points + point3 Q0 = csOrig * k0; + point3 Q1 = csEndPoint * k1; + + // Screen-space endpoints + point2 P0 = (H0.xy * k0) * 0.5 + 0.5; + point2 P1 = 0.5 * (H1.xy * k1) + 0.5; + P0 *= csZBufferSize; + P1 *= csZBufferSize; + + // If the line is degenerate, make it cover at least one pixel + // to avoid handling zero-pixel extent as a special case later + P1 += vec2((distanceSquared(P0, P1) < 0.0001) ? 0.01 : 0.0); + vec2 delta = P1 - P0; + + // Permute so that the primary iteration is in x to collapse + // all quadrant-specific DDA cases later + bool permute = false; + if (abs(delta.x) < abs(delta.y)) { + // This is a more-vertical line + permute = true; delta = delta.yx; P0 = P0.yx; P1 = P1.yx; + } + + float stepDir = sign(delta.x); + float invdx = stepDir / delta.x; + + // Track the derivatives of Q and k + vec3 dQ = (Q1 - Q0) * invdx; + float dk = (k1 - k0) * invdx; + vec2 dP = vec2(stepDir, delta.y * invdx); + + // Scale derivatives by the desired pixel stride and then + // offset the starting values by the jitter fraction + + float strideScale = 1.0 - min(1.0, abs(csOrig.z) * 0.01); + stride = 1.0 + strideScale * stride; + + P0 += dP; + Q0 += dQ; + k0 += dk; + + dP *= stride; + dQ *= stride; + dk *= stride; + + P0 += dP * jitter; + Q0 += dQ * jitter; + k0 += dk * jitter; + + // Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, k from k0 to k1 + point3 Q = Q0; + + // Adjust end condition for iteration direction + float end = P1.x * stepDir; + + float k = k0, stepCount = 0.0, prevZMaxEstimate = csOrig.z; + float rayZMin = prevZMaxEstimate, rayZMax = prevZMaxEstimate; + float sceneZMax = rayZMax + 100; + point2 P = P0; + for (; + ((P.x * stepDir) <= end) && (stepCount < maxSteps) && + !intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax, zThickness, 0.01) && + (sceneZMax != 0); + P += dP, Q.z += dQ.z, k += dk, ++stepCount) { + + rayZMin = prevZMaxEstimate; + rayZMax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k); + prevZMaxEstimate = rayZMax; + if (rayZMin > rayZMax) { + float t = rayZMin; rayZMin = rayZMax; rayZMax = t; + } + + hitPixel = permute ? P.yx : P; + // You may need hitPixel.y = csZBufferSize.y - hitPixel.y; here if your vertical axis + // is different than ours in screen space + sceneZMax = ConvertDepthToViewSpaceDepth(texelFetch(csZBuffer, ivec2(hitPixel), 0).r); + } + + minPoint = Q0 + dQ * (stepCount - 2.0); + maxPoint = Q0 + dQ * (stepCount - 1.0); + + minPoint /= (k - 2.0 * dk); + maxPoint /= (k - 1.0 * dk); + + // Advance Q based on the number of steps + Q.xy += dQ.xy * stepCount; + hitPoint = Q * (1.0 / k); + + return intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax, zThickness, 0.01); +} + +bool traceScreenSpace( + // Camera-space ray origin, which must be within the view volume + point3 csOrig, + + // Unit length camera-space ray direction + vec3 csDir, + + // The camera-space Z buffer (all negative values) + sampler2D csZBuffer, + + // Camera space thickness to ascribe to each pixel in the depth buffer + float zThickness, + + // Step in horizontal or vertical pixels between samples. This is a float + // because integer math is slow on GPUs, but should be set to an integer >= 1 + float stride, + + // Number between 0 and 1 for how far to bump the ray in stride units + // to conceal banding artifacts + float jitter, + + // Maximum number of iterations. Higher gives better images but may be slow + const float maxSteps, + + // Maximum camera-space distance to trace before returning a miss + float maxDistance, + + // Pixel coordinates of the first intersection with the scene + out point2 hitPixel, + + // Camera space location of the ray hit + out point3 hitPoint) { + + point3 minPoint, maxPoint; + return traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, hitPixel, hitPoint, minPoint, maxPoint); + +} + +bool traceScreenSpaceAdvanced( + // Camera-space ray origin, which must be within the view volume + point3 csOrig, + + // Unit length camera-space ray direction + vec3 csDir, + + // The camera-space Z buffer (all negative values) + sampler2D csZBuffer, + + // Camera space thickness to ascribe to each pixel in the depth buffer + float zThickness, + + // Step in horizontal or vertical pixels between samples. This is a float + // because integer math is slow on GPUs, but should be set to an integer >= 1 + float stride, + + // Number between 0 and 1 for how far to bump the ray in stride units + // to conceal banding artifacts + float jitter, + + // Maximum number of iterations. Higher gives better images but may be slow + float maxSteps, + + // Maximum camera-space distance to trace before returning a miss + float maxDistance, + + // Pixel coordinates of the first intersection with the scene + out point2 hitPixel, + + // Camera space location of the ray hit + out point3 hitPoint) { + + point3 minPoint, maxPoint; + if(traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, hitPixel, hitPoint, minPoint, maxPoint)) { + + } + + maxSteps /= 2.0; + + csOrig = minPoint; + csDir = normalize(maxPoint - minPoint); + stride = max(1.0, stride / maxSteps);; + zThickness /= maxSteps; + maxDistance = 20.0 * distance(maxPoint, minPoint); + + vec2 newHitPixel; + vec3 newHitPoint; + if (traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, newHitPixel, newHitPoint, minPoint, maxPoint)) { + hitPixel = newHitPixel; + hitPoint = newHitPoint; + return true; + } + + return false; + +} \ No newline at end of file diff --git a/data/shader/globals.hsh b/data/shader/globals.hsh index 0afa8752e..167ae2b38 100644 --- a/data/shader/globals.hsh +++ b/data/shader/globals.hsh @@ -33,6 +33,8 @@ layout(set = 1, binding = 31, std140) uniform GlobalBuffer { float deltaTime; uint frameCount; float mipLodBias; + float cameraNearPlane; + float cameraFarPlane; } globalData; layout(set = 0, binding = 3) uniform texture2D bindlessTextures[TEXTURE_COUNT]; diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index 5a239f9c4..661ec9ec6 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -23,7 +23,7 @@ layout (local_size_x = 8, local_size_y = 4) in; -layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D rtrImage; +layout (set = 3, binding = 0, rgba16f) uniform image2D rtrImage; layout(set = 3, binding = 1) uniform sampler2D normalTexture; layout(set = 3, binding = 2) uniform sampler2D depthTexture; @@ -95,9 +95,9 @@ void main() { float roughness = texelFetch(roughnessMetallicAoTexture, pixel, 0).r; material.roughness *= material.roughnessMap ? roughness : 1.0; - vec3 reflection = vec3(0.0); + vec4 reflection = imageLoad(rtrImage, pixel); - if (material.roughness <= 1.0 && depth < 1.0) { + if (material.roughness <= 1.0 && depth < 1.0 && reflection.a == 0.0) { const int sampleCount = uniforms.sampleCount; @@ -160,15 +160,15 @@ void main() { float radianceMax = max(max(max(radiance.r, max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01); - reflection += radiance * (uniforms.radianceLimit / radianceMax); + reflection.rgb += radiance * (uniforms.radianceLimit / radianceMax); } } - reflection /= float(sampleCount); + reflection.rgb /= float(sampleCount); } - imageStore(rtrImage, pixel, vec4(reflection, 1.0)); + imageStore(rtrImage, pixel, reflection); } } diff --git a/data/shader/reflection/ssr.csh b/data/shader/reflection/ssr.csh new file mode 100644 index 000000000..11d4bc83d --- /dev/null +++ b/data/shader/reflection/ssr.csh @@ -0,0 +1,174 @@ +#define SHADOW_FILTER_1x1 + +#include <../globals.hsh> +#include <../raytracer/lights.hsh> +#include <../raytracer/tracing.hsh> +#include <../raytracer/direct.hsh> + +#include <../common/random.hsh> +#include <../common/utility.hsh> +#include <../common/flatten.hsh> +#include <../common/convert.hsh> +#include <../common/normalencode.hsh> +#include <../common/PI.hsh> +#include <../common/bluenoise.hsh> +#include <../common/traceScreenSpace.hsh> + +#include <../brdf/brdfEval.hsh> +#include <../brdf/brdfSample.hsh> +#include <../brdf/importanceSample.hsh> +#include <../brdf/surface.hsh> + +#include <../ddgi/ddgi.hsh> +#include <../shadow.hsh> + +layout (local_size_x = 8, local_size_y = 8) in; + +layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D rtrImage; + +layout(set = 3, binding = 1) uniform sampler2D normalTexture; +layout(set = 3, binding = 2) uniform sampler2D depthTexture; +layout(set = 3, binding = 3) uniform sampler2D roughnessMetallicAoTexture; +layout(set = 3, binding = 4) uniform isampler2D offsetTexture; +layout(set = 3, binding = 5) uniform usampler2D materialIdxTexture; +layout(set = 3, binding = 6) uniform sampler2DArrayShadow cascadeMaps; + +layout(set = 3, binding = 7) uniform sampler2D scramblingRankingTexture; +layout(set = 3, binding = 8) uniform sampler2D sobolSequenceTexture; + +layout(set = 3, binding = 9) uniform sampler2D lightingTexture; + +const ivec2 offsets[4] = ivec2[4]( + ivec2(0, 0), + ivec2(1, 0), + ivec2(0, 1), + ivec2(1, 1) +); + +layout(std140, set = 3, binding = 10) uniform UniformBuffer { + float radianceLimit; + uint frameSeed; + float bias; + int sampleCount; + int lightSampleCount; + int textureLevel; + float roughnessCutoff; + int halfRes; + int padding0; + int padding1; + ivec2 resolution; + Shadow shadow; +} uniforms; + +void main() { + + ivec2 resolution = uniforms.resolution; + + if (int(gl_GlobalInvocationID.x) < resolution.x && + int(gl_GlobalInvocationID.y) < resolution.y) { + + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + + vec2 texCoord = (vec2(pixel) + vec2(0.5)) / vec2(resolution); + + // No need, there is no offset right now + int offsetIdx = texelFetch(offsetTexture, pixel, 0).r; + ivec2 offset = offsets[offsetIdx]; + + float depth = texelFetch(depthTexture, pixel, 0).r; + + vec2 recontructTexCoord; + if (uniforms.halfRes > 0) + recontructTexCoord = (2.0 * (vec2(pixel)) + offset + 0.5) / (2.0 * vec2(resolution)); + else + recontructTexCoord = (vec2(pixel) + 0.5) / (vec2(resolution)); + + vec3 viewPos = ConvertDepthToViewSpace(depth, recontructTexCoord); + vec3 worldPos = vec3(globalData.ivMatrix * vec4(viewPos, 1.0)); + vec3 viewVec = vec3(globalData.ivMatrix * vec4(viewPos, 0.0)); + vec3 viewNormal = DecodeNormal(textureLod(normalTexture, texCoord, 0).rg); + vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(viewNormal, 0.0))); + + uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; + Material material = UnpackMaterial(materialIdx); + + float roughness = texelFetch(roughnessMetallicAoTexture, pixel, 0).r; + material.roughness *= material.roughnessMap ? roughness : 1.0; + + vec3 reflection = vec3(0.0); + float hits = 0.0; + + if (material.roughness <= 1.0 && depth < 1.0) { + + const int sampleCount = uniforms.sampleCount; + + for (int i = 0; i < sampleCount; i++) { + int sampleIdx = int(uniforms.frameSeed) * sampleCount + i; + vec3 blueNoiseVec = vec3( + SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture), + SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture), + SampleBlueNoise(pixel, i, 2, scramblingRankingTexture, sobolSequenceTexture) + ); + + float alpha = sqr(material.roughness); + + vec3 V = normalize(-viewVec); + vec3 N = worldNorm; + + Surface surface = CreateSurface(V, N, vec3(1.0), material); + + Ray ray; + ray.ID = i; + blueNoiseVec.y *= (1.0 - uniforms.bias); + + float pdf = 1.0; + BRDFSample brdfSample; + if (material.roughness > 0.01) { + ImportanceSampleGGXVNDF(blueNoiseVec.xy, N, V, alpha, + ray.direction, pdf); + } + else { + ray.direction = normalize(reflect(-V, N)); + } + + vec3 viewDir = normalize(vec3(globalData.vMatrix * vec4(ray.direction, 0.0))); + + bool isRayValid = !isnan(ray.direction.x) || !isnan(ray.direction.y) || + !isnan(ray.direction.z) || dot(N, ray.direction) >= 0.0; + + if (isRayValid) { + // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore + float viewOffset = max(1.0, length(viewPos)); + ray.origin = worldPos + ray.direction * EPSILON * viewOffset + worldNorm * EPSILON * viewOffset; + + ray.hitID = -1; + ray.hitDistance = 0.0; + + vec3 radiance = vec3(0.0); + if (material.roughness <= uniforms.roughnessCutoff) { + vec3 viewRayOrigin = viewPos + 10.0 * viewNormal * EPSILON * viewOffset + viewDir * EPSILON * viewOffset; + + vec2 hitPixel; + vec3 hitPoint; + float jitter = GetInterleavedGradientNoise(vec2(pixel), 4u) / float(sampleCount) + i / float(sampleCount); + if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 1.0, 16.0, jitter, 32.0, 2000.0, hitPixel, hitPoint)) { + vec2 hitTexCoord = vec2(hitPixel + 0.5) / vec2(textureSize(depthTexture, 0)); + radiance = textureLod(lightingTexture, hitTexCoord, 1).rgb; + hits += 1.0; + } + } + + float radianceMax = max(max(max(radiance.r, + max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01); + reflection += radiance * (uniforms.radianceLimit / radianceMax); + } + } + + reflection /= float(sampleCount); + + } + + imageStore(rtrImage, pixel, vec4(reflection, hits)); + } + +} \ No newline at end of file diff --git a/data/shader/reflection/temporal.csh b/data/shader/reflection/temporal.csh index 8f84dd523..c2cf4dbc2 100644 --- a/data/shader/reflection/temporal.csh +++ b/data/shader/reflection/temporal.csh @@ -409,7 +409,7 @@ void main() { roughness *= material.roughnessMap ? texelFetch(roughnessMetallicAoTexture, pixel, 0).r : 1.0; float temporalWeight = mix(pushConstants.temporalWeight, 0.5, adjClipBlend); - float factor = clamp(32.0 * log(roughness + 1.0), 0.5, temporalWeight); + float factor = clamp(32.0 * log(roughness + 1.0), 0.75, temporalWeight); factor = (uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0 || uv.y > 1.0) ? 0.0 : factor; diff --git a/src/demo/App.h b/src/demo/App.h index 3f730dbaf..6e90c012d 100644 --- a/src/demo/App.h +++ b/src/demo/App.h @@ -113,10 +113,10 @@ class App : public Atlas::EngineInstance { float sphereDensity = 1.0f; float sphereRestitution = 0.2f; - bool emitSpheresEnabled = true; + bool emitSpheresEnabled = false; float emitSpawnRate = 0.01f; - bool attachLightToSphers = true; + bool attachLightToSphers = false; bool shootSpheresEnabled = false; bool shootSphere = false; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 25fda6f4f..c7df25904 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -8,1119 +8,1124 @@ namespace Atlas { - namespace Renderer { - - void MainRenderer::Init(Graphics::GraphicsDevice *device) { - - this->device = device; - - CreateGlobalDescriptorSetLayout(); - - Helper::GeometryHelper::GenerateRectangleVertexArray(vertexArray); - Helper::GeometryHelper::GenerateCubeVertexArray(cubeVertexArray); - - haltonSequence = Helper::HaltonSequence::Generate(2, 3, 16 + 1); - - PreintegrateBRDF(); - - auto uniformBufferDesc = Graphics::BufferDesc { - .usageFlags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - .domain = Graphics::BufferDomain::Host, - .hostAccess = Graphics::BufferHostAccess::Sequential, - .size = sizeof(GlobalUniforms), - }; - globalUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); - pathTraceGlobalUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); - - uniformBufferDesc.size = sizeof(DDGIUniforms); - ddgiUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); - - opaqueRenderer.Init(device); - impostorRenderer.Init(device); - terrainRenderer.Init(device); - shadowRenderer.Init(device); - impostorShadowRenderer.Init(device); - terrainShadowRenderer.Init(device); - gBufferRenderer.Init(device); - ddgiRenderer.Init(device); - rtgiRenderer.Init(device); - ssgiRenderer.Init(device); - aoRenderer.Init(device); - rtrRenderer.Init(device); - sssRenderer.Init(device); - directLightRenderer.Init(device); - indirectLightRenderer.Init(device); - skyboxRenderer.Init(device); - atmosphereRenderer.Init(device); - oceanRenderer.Init(device); - volumetricCloudRenderer.Init(device); - volumetricRenderer.Init(device); - taaRenderer.Init(device); - postProcessRenderer.Init(device); - pathTracingRenderer.Init(device); - fsr2Renderer.Init(device); - textRenderer.Init(device); - textureRenderer.Init(device); - - } - - void MainRenderer::RenderScene(Ref viewport, Ref target, Ref scene, - Ref primitiveBatch, Texture::Texture2D* texture) { - - if (!device->swapChain->isComplete || !scene->HasMainCamera()) - return; - - if (target->IsUsedForPathTracing()) - target->UseForPathTracing(false); - - auto& camera = scene->GetMainCamera(); - auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue); - - commandList->BeginCommands(); - - auto& taa = scene->postProcessing.taa; - if (taa.enable || scene->postProcessing.fsr2) { - vec2 jitter = vec2(0.0f); - if (scene->postProcessing.fsr2) { - jitter = fsr2Renderer.GetJitter(target, frameCount); - } - else { - jitter = 2.0f * haltonSequence[haltonIndex] - 1.0f; - jitter.x /= (float)target->GetScaledWidth(); - jitter.y /= (float)target->GetScaledHeight(); - } - - camera.Jitter(jitter * taa.jitterRange); - } - else { - // Even if there is no TAA we need to update the jitter for other techniques - // E.g. the reflections and ambient occlusion use reprojection - camera.Jitter(vec2(0.0f)); - } - - auto renderState = &scene->renderState; - - Graphics::Profiler::BeginThread("Main renderer", commandList); - Graphics::Profiler::BeginQuery("Render scene"); - - SetUniforms(target, scene, camera); - - commandList->BindBuffer(globalUniformBuffer, 1, 31); - commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); - commandList->BindSampler(globalSampler, 1, 14); - commandList->BindSampler(globalNearestSampler, 1, 16); - - if (scene->clutter) - vegetationRenderer.helper.PrepareInstanceBuffer(*scene->clutter, camera, commandList); - - if (scene->ocean && scene->ocean->enable) - scene->ocean->simulation.Compute(commandList); - - if (scene->sky.probe) { - if (scene->sky.probe->update) { - FilterProbe(scene->sky.probe, commandList); - //scene->sky.probe->update = false; - } - } - else if (scene->sky.atmosphere) { - atmosphereRenderer.Render(scene->sky.atmosphere->probe, scene, commandList); - FilterProbe(scene->sky.atmosphere->probe, commandList); - } - - if (scene->irradianceVolume) { - commandList->BindBuffer(ddgiUniformBuffer, 2, 26); - } - - volumetricCloudRenderer.RenderShadow(target, scene, commandList); - - JobSystem::WaitSpin(renderState->materialUpdateJob); - if (renderState->materialBuffer.GetElementCount()) - renderState->materialBuffer.Bind(commandList, 1, 15); - - // Wait as long as possible for this to finish - JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); - JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); - JobSystem::WaitSpin(renderState->bindlessOtherTextureMapUpdateJob); - commandList->BindBuffers(renderState->triangleBuffers, 0, 1); - if (renderState->textures.size()) - commandList->BindSampledImages(renderState->textures, 0, 3); - if (renderState->cubemaps.size()) - commandList->BindSampledImages(renderState->cubemaps, 0, 4); - if (renderState->textureArrays.size()) - commandList->BindSampledImages(renderState->textureArrays, 0, 5); - - if (device->support.hardwareRayTracing) { - commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); - } - else { - commandList->BindBuffers(renderState->blasBuffers, 0, 0); - commandList->BindBuffers(renderState->bvhTriangleBuffers, 0, 2); - } - - { - shadowRenderer.Render(target, scene, commandList, &renderState->renderList); - - terrainShadowRenderer.Render(target, scene, commandList); - } - - if (scene->sky.GetProbe()) { - commandList->BindImage(scene->sky.GetProbe()->filteredSpecular.image, - scene->sky.GetProbe()->filteredSpecular.sampler, 1, 11); - commandList->BindImage(scene->sky.GetProbe()->filteredDiffuse.image, - scene->sky.GetProbe()->filteredDiffuse.sampler, 1, 12); - } - - { - VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - - auto lightSubset = scene->GetSubset(); - shadowImageBarriers.clear(); - - for (auto& lightEntity : lightSubset) { - auto& light = lightEntity.GetComponent(); - if (!light.shadow || !light.shadow->update) - continue; - - auto shadow = light.shadow; - shadowImageBarriers.push_back({ shadow->useCubemap ? - shadow->cubemap->image : shadow->maps->image, layout, access }); - } - - commandList->PipelineBarrier(shadowImageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); - } - - JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); - - JobSystem::WaitSpin(renderState->cullAndSortLightsJob); - renderState->lightBuffer.Bind(commandList, 1, 17); - - ddgiRenderer.TraceAndUpdateProbes(scene, commandList); - - // Only here does the main pass need to be ready - JobSystem::Wait(renderState->fillRenderListJob); - - { - Graphics::Profiler::BeginQuery("Main render pass"); - - commandList->BeginRenderPass(target->gBufferRenderPass, target->gBufferFrameBuffer, true); - - opaqueRenderer.Render(target, scene, commandList, &renderState->renderList, renderState->materialMap); - - ddgiRenderer.DebugProbes(target, scene, commandList, renderState->materialMap); - - vegetationRenderer.Render(target, scene, commandList, renderState->materialMap); - - terrainRenderer.Render(target, scene, commandList, renderState->materialMap); - - impostorRenderer.Render(target, scene, commandList, &renderState->renderList, renderState->materialMap); - - commandList->EndRenderPass(); - - Graphics::Profiler::EndQuery(); - } - - oceanRenderer.RenderDepthOnly(target, scene, commandList); - - auto targetData = target->GetData(FULL_RES); - - commandList->BindImage(targetData->baseColorTexture->image, targetData->baseColorTexture->sampler, 1, 3); - commandList->BindImage(targetData->normalTexture->image, targetData->normalTexture->sampler, 1, 4); - commandList->BindImage(targetData->geometryNormalTexture->image, targetData->geometryNormalTexture->sampler, 1, 5); - commandList->BindImage(targetData->roughnessMetallicAoTexture->image, targetData->roughnessMetallicAoTexture->sampler, 1, 6); - commandList->BindImage(targetData->emissiveTexture->image, targetData->emissiveTexture->sampler, 1, 7); - commandList->BindImage(targetData->materialIdxTexture->image, targetData->materialIdxTexture->sampler, 1, 8); - commandList->BindImage(targetData->depthTexture->image, targetData->depthTexture->sampler, 1, 9); - - if (!target->HasHistory()) { - auto rtHalfData = target->GetHistoryData(HALF_RES); - auto rtData = target->GetHistoryData(FULL_RES); - VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - Graphics::ImageBarrier imageBarriers[] = { - {rtData->baseColorTexture->image, layout, access}, - {rtData->depthTexture->image, layout, access}, - {rtData->normalTexture->image, layout, access}, - {rtData->geometryNormalTexture->image, layout, access}, - {rtData->roughnessMetallicAoTexture->image, layout, access}, - {rtData->emissiveTexture->image, layout, access}, - {rtData->offsetTexture->image, layout, access}, - {rtData->materialIdxTexture->image, layout, access}, - {rtData->stencilTexture->image, layout, access}, - {rtData->velocityTexture->image, layout, access}, - {rtHalfData->baseColorTexture->image, layout, access}, - {rtHalfData->depthTexture->image, layout, access}, - {rtHalfData->normalTexture->image, layout, access}, - {rtHalfData->geometryNormalTexture->image, layout, access}, - {rtHalfData->roughnessMetallicAoTexture->image, layout, access}, - {rtHalfData->emissiveTexture->image, layout, access}, - {rtHalfData->offsetTexture->image, layout, access}, - {rtHalfData->materialIdxTexture->image, layout, access}, - {rtHalfData->stencilTexture->image, layout, access}, - {rtHalfData->velocityTexture->image, layout, access}, - }; - commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - } + namespace Renderer { + + void MainRenderer::Init(Graphics::GraphicsDevice* device) { + + this->device = device; + + CreateGlobalDescriptorSetLayout(); + + Helper::GeometryHelper::GenerateRectangleVertexArray(vertexArray); + Helper::GeometryHelper::GenerateCubeVertexArray(cubeVertexArray); + + haltonSequence = Helper::HaltonSequence::Generate(2, 3, 16 + 1); + + PreintegrateBRDF(); + + auto uniformBufferDesc = Graphics::BufferDesc{ + .usageFlags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .domain = Graphics::BufferDomain::Host, + .hostAccess = Graphics::BufferHostAccess::Sequential, + .size = sizeof(GlobalUniforms), + }; + globalUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); + pathTraceGlobalUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); + + uniformBufferDesc.size = sizeof(DDGIUniforms); + ddgiUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); + + opaqueRenderer.Init(device); + impostorRenderer.Init(device); + terrainRenderer.Init(device); + shadowRenderer.Init(device); + impostorShadowRenderer.Init(device); + terrainShadowRenderer.Init(device); + gBufferRenderer.Init(device); + ddgiRenderer.Init(device); + rtgiRenderer.Init(device); + ssgiRenderer.Init(device); + aoRenderer.Init(device); + rtrRenderer.Init(device); + sssRenderer.Init(device); + directLightRenderer.Init(device); + indirectLightRenderer.Init(device); + skyboxRenderer.Init(device); + atmosphereRenderer.Init(device); + oceanRenderer.Init(device); + volumetricCloudRenderer.Init(device); + volumetricRenderer.Init(device); + taaRenderer.Init(device); + postProcessRenderer.Init(device); + pathTracingRenderer.Init(device); + fsr2Renderer.Init(device); + textRenderer.Init(device); + textureRenderer.Init(device); + + } + + void MainRenderer::RenderScene(Ref viewport, Ref target, Ref scene, + Ref primitiveBatch, Texture::Texture2D* texture) { + + if (!device->swapChain->isComplete || !scene->HasMainCamera()) + return; + + if (target->IsUsedForPathTracing()) + target->UseForPathTracing(false); + + auto& camera = scene->GetMainCamera(); + auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue); + + commandList->BeginCommands(); + + auto& taa = scene->postProcessing.taa; + if (taa.enable || scene->postProcessing.fsr2) { + vec2 jitter = vec2(0.0f); + if (scene->postProcessing.fsr2) { + jitter = fsr2Renderer.GetJitter(target, frameCount); + } + else { + jitter = 2.0f * haltonSequence[haltonIndex] - 1.0f; + jitter.x /= (float)target->GetScaledWidth(); + jitter.y /= (float)target->GetScaledHeight(); + } + + camera.Jitter(jitter * taa.jitterRange); + } + else { + // Even if there is no TAA we need to update the jitter for other techniques + // E.g. the reflections and ambient occlusion use reprojection + camera.Jitter(vec2(0.0f)); + } + + auto renderState = &scene->renderState; + + Graphics::Profiler::BeginThread("Main renderer", commandList); + Graphics::Profiler::BeginQuery("Render scene"); + + SetUniforms(target, scene, camera); + + commandList->BindBuffer(globalUniformBuffer, 1, 31); + commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); + commandList->BindSampler(globalSampler, 1, 14); + commandList->BindSampler(globalNearestSampler, 1, 16); + + if (scene->clutter) + vegetationRenderer.helper.PrepareInstanceBuffer(*scene->clutter, camera, commandList); + + if (scene->ocean && scene->ocean->enable) + scene->ocean->simulation.Compute(commandList); + + if (scene->sky.probe) { + if (scene->sky.probe->update) { + FilterProbe(scene->sky.probe, commandList); + //scene->sky.probe->update = false; + } + } + else if (scene->sky.atmosphere) { + atmosphereRenderer.Render(scene->sky.atmosphere->probe, scene, commandList); + FilterProbe(scene->sky.atmosphere->probe, commandList); + } + + if (scene->irradianceVolume) { + commandList->BindBuffer(ddgiUniformBuffer, 2, 26); + } + + volumetricCloudRenderer.RenderShadow(target, scene, commandList); + + JobSystem::WaitSpin(renderState->materialUpdateJob); + if (renderState->materialBuffer.GetElementCount()) + renderState->materialBuffer.Bind(commandList, 1, 15); + + // Wait as long as possible for this to finish + JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); + JobSystem::WaitSpin(renderState->bindlessOtherTextureMapUpdateJob); + commandList->BindBuffers(renderState->triangleBuffers, 0, 1); + if (renderState->textures.size()) + commandList->BindSampledImages(renderState->textures, 0, 3); + if (renderState->cubemaps.size()) + commandList->BindSampledImages(renderState->cubemaps, 0, 4); + if (renderState->textureArrays.size()) + commandList->BindSampledImages(renderState->textureArrays, 0, 5); + + if (device->support.hardwareRayTracing) { + commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); + } + else { + commandList->BindBuffers(renderState->blasBuffers, 0, 0); + commandList->BindBuffers(renderState->bvhTriangleBuffers, 0, 2); + } + + { + shadowRenderer.Render(target, scene, commandList, &renderState->renderList); + + terrainShadowRenderer.Render(target, scene, commandList); + } + + if (scene->sky.GetProbe()) { + commandList->BindImage(scene->sky.GetProbe()->filteredSpecular.image, + scene->sky.GetProbe()->filteredSpecular.sampler, 1, 11); + commandList->BindImage(scene->sky.GetProbe()->filteredDiffuse.image, + scene->sky.GetProbe()->filteredDiffuse.sampler, 1, 12); + } + + { + VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; + + auto lightSubset = scene->GetSubset(); + shadowImageBarriers.clear(); + + for (auto& lightEntity : lightSubset) { + auto& light = lightEntity.GetComponent(); + if (!light.shadow || !light.shadow->update) + continue; + + auto shadow = light.shadow; + shadowImageBarriers.push_back({ shadow->useCubemap ? + shadow->cubemap->image : shadow->maps->image, layout, access }); + } + + commandList->PipelineBarrier(shadowImageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + } + + JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); + + JobSystem::WaitSpin(renderState->cullAndSortLightsJob); + renderState->lightBuffer.Bind(commandList, 1, 17); + + ddgiRenderer.TraceAndUpdateProbes(scene, commandList); + + // Only here does the main pass need to be ready + JobSystem::Wait(renderState->fillRenderListJob); + + { + Graphics::Profiler::BeginQuery("Main render pass"); + + commandList->BeginRenderPass(target->gBufferRenderPass, target->gBufferFrameBuffer, true); + + opaqueRenderer.Render(target, scene, commandList, &renderState->renderList, renderState->materialMap); + + ddgiRenderer.DebugProbes(target, scene, commandList, renderState->materialMap); + + vegetationRenderer.Render(target, scene, commandList, renderState->materialMap); + + terrainRenderer.Render(target, scene, commandList, renderState->materialMap); + + impostorRenderer.Render(target, scene, commandList, &renderState->renderList, renderState->materialMap); + + commandList->EndRenderPass(); + + Graphics::Profiler::EndQuery(); + } + + oceanRenderer.RenderDepthOnly(target, scene, commandList); + + auto targetData = target->GetData(FULL_RES); + + commandList->BindImage(targetData->baseColorTexture->image, targetData->baseColorTexture->sampler, 1, 3); + commandList->BindImage(targetData->normalTexture->image, targetData->normalTexture->sampler, 1, 4); + commandList->BindImage(targetData->geometryNormalTexture->image, targetData->geometryNormalTexture->sampler, 1, 5); + commandList->BindImage(targetData->roughnessMetallicAoTexture->image, targetData->roughnessMetallicAoTexture->sampler, 1, 6); + commandList->BindImage(targetData->emissiveTexture->image, targetData->emissiveTexture->sampler, 1, 7); + commandList->BindImage(targetData->materialIdxTexture->image, targetData->materialIdxTexture->sampler, 1, 8); + commandList->BindImage(targetData->depthTexture->image, targetData->depthTexture->sampler, 1, 9); + + if (!target->HasHistory()) { + auto rtHalfData = target->GetHistoryData(HALF_RES); + auto rtData = target->GetHistoryData(FULL_RES); + VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; + Graphics::ImageBarrier imageBarriers[] = { + {rtData->baseColorTexture->image, layout, access}, + {rtData->depthTexture->image, layout, access}, + {rtData->normalTexture->image, layout, access}, + {rtData->geometryNormalTexture->image, layout, access}, + {rtData->roughnessMetallicAoTexture->image, layout, access}, + {rtData->emissiveTexture->image, layout, access}, + {rtData->offsetTexture->image, layout, access}, + {rtData->materialIdxTexture->image, layout, access}, + {rtData->stencilTexture->image, layout, access}, + {rtData->velocityTexture->image, layout, access}, + {rtHalfData->baseColorTexture->image, layout, access}, + {rtHalfData->depthTexture->image, layout, access}, + {rtHalfData->normalTexture->image, layout, access}, + {rtHalfData->geometryNormalTexture->image, layout, access}, + {rtHalfData->roughnessMetallicAoTexture->image, layout, access}, + {rtHalfData->emissiveTexture->image, layout, access}, + {rtHalfData->offsetTexture->image, layout, access}, + {rtHalfData->materialIdxTexture->image, layout, access}, + {rtHalfData->stencilTexture->image, layout, access}, + {rtHalfData->velocityTexture->image, layout, access}, + }; + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + } - { - auto rtData = target->GetData(FULL_RES); + { + auto rtData = target->GetData(FULL_RES); - VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; + VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - Graphics::ImageBarrier imageBarriers[] = { - {rtData->baseColorTexture->image, layout, access}, - {rtData->depthTexture->image, layout, access}, - {rtData->normalTexture->image, layout, access}, - {rtData->geometryNormalTexture->image, layout, access}, - {rtData->roughnessMetallicAoTexture->image, layout, access}, - {rtData->emissiveTexture->image, layout, access}, - {rtData->offsetTexture->image, layout, access}, - {rtData->materialIdxTexture->image, layout, access}, - {rtData->stencilTexture->image, layout, access}, - {rtData->velocityTexture->image, layout, access}, - {target->oceanStencilTexture.image, layout, access}, - {target->oceanDepthTexture.image, layout, access} - }; + Graphics::ImageBarrier imageBarriers[] = { + {rtData->baseColorTexture->image, layout, access}, + {rtData->depthTexture->image, layout, access}, + {rtData->normalTexture->image, layout, access}, + {rtData->geometryNormalTexture->image, layout, access}, + {rtData->roughnessMetallicAoTexture->image, layout, access}, + {rtData->emissiveTexture->image, layout, access}, + {rtData->offsetTexture->image, layout, access}, + {rtData->materialIdxTexture->image, layout, access}, + {rtData->stencilTexture->image, layout, access}, + {rtData->velocityTexture->image, layout, access}, + {target->oceanStencilTexture.image, layout, access}, + {target->oceanDepthTexture.image, layout, access} + }; - commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); - } + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + } - { - if (scene->sky.probe) { - skyboxRenderer.Render(target, scene, commandList); - } - else if (scene->sky.atmosphere) { - atmosphereRenderer.Render(target, scene, commandList); - } - } + { + if (scene->sky.probe) { + skyboxRenderer.Render(target, scene, commandList); + } + else if (scene->sky.atmosphere) { + atmosphereRenderer.Render(target, scene, commandList); + } + } - gBufferRenderer.FillNormalTexture(target, commandList); + gBufferRenderer.FillNormalTexture(target, commandList); - gBufferRenderer.Downscale(target, commandList); + gBufferRenderer.Downscale(target, commandList); - aoRenderer.Render(target, scene, commandList); + aoRenderer.Render(target, scene, commandList); - rtgiRenderer.Render(target, scene, commandList); + rtgiRenderer.Render(target, scene, commandList); - rtrRenderer.Render(target, scene, commandList); + rtrRenderer.Render(target, scene, commandList); - sssRenderer.Render(target, scene, commandList); + sssRenderer.Render(target, scene, commandList); - { - Graphics::Profiler::BeginQuery("Lighting pass"); + { + Graphics::Profiler::BeginQuery("Lighting pass"); - commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); + commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - directLightRenderer.Render(target, scene, commandList); + directLightRenderer.Render(target, scene, commandList); - if (!scene->rtgi || !scene->rtgi->enable || !scene->IsRtDataValid()) { - commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); + commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - ssgiRenderer.Render(target, scene, commandList); - } + if (!scene->rtgi || !scene->rtgi->enable || !scene->IsRtDataValid()) { + ssgiRenderer.Render(target, scene, commandList); + } + - commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - - indirectLightRenderer.Render(target, scene, commandList); - - Graphics::ImageBarrier outBarrier(target->lightingTexture.image, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); - commandList->ImageMemoryBarrier(outBarrier, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + commandList->ImageMemoryBarrier(target->lightingTexture.image, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); + + indirectLightRenderer.Render(target, scene, commandList); + + Graphics::ImageBarrier outBarrier(target->lightingTexture.image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); + commandList->ImageMemoryBarrier(outBarrier, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - Graphics::Profiler::EndQuery(); - } + Graphics::Profiler::EndQuery(); + } - // This was needed after the ocean renderer, if we ever want to have alpha transparency we need it again - // downscaleRenderer.Downscale(target, commandList); + // This was needed after the ocean renderer, if we ever want to have alpha transparency we need it again + // downscaleRenderer.Downscale(target, commandList); - { - commandList->BeginRenderPass(target->afterLightingRenderPass, target->afterLightingFrameBuffer); + { + commandList->BeginRenderPass(target->afterLightingRenderPass, target->afterLightingFrameBuffer); - textRenderer.Render(target, scene, commandList); - - commandList->EndRenderPass(); + textRenderer.Render(target, scene, commandList); - auto rtData = target->GetData(FULL_RES); + commandList->EndRenderPass(); - VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; + auto rtData = target->GetData(FULL_RES); - Graphics::ImageBarrier imageBarriers[] = { - {target->lightingTexture.image, layout, access}, - {rtData->depthTexture->image, layout, access}, - {rtData->velocityTexture->image, layout, access}, - {rtData->stencilTexture->image, layout, access}, - }; + VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); - } + Graphics::ImageBarrier imageBarriers[] = { + {target->lightingTexture.image, layout, access}, + {rtData->depthTexture->image, layout, access}, + {rtData->velocityTexture->image, layout, access}, + {rtData->stencilTexture->image, layout, access}, + }; - { - volumetricCloudRenderer.Render(target, scene, commandList); + commandList->PipelineBarrier(imageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + } - volumetricRenderer.Render(target, scene, commandList); - } + { + volumetricCloudRenderer.Render(target, scene, commandList); - oceanRenderer.Render(target, scene, commandList); + volumetricRenderer.Render(target, scene, commandList); + } - if (primitiveBatch) - RenderPrimitiveBatch(viewport, target, primitiveBatch, scene->GetMainCamera(), commandList); + oceanRenderer.Render(target, scene, commandList); - if (scene->postProcessing.fsr2) { - gBufferRenderer.GenerateReactiveMask(target, commandList); + if (primitiveBatch) + RenderPrimitiveBatch(viewport, target, primitiveBatch, scene->GetMainCamera(), commandList); - fsr2Renderer.Render(target, scene, commandList); - } - else { - taaRenderer.Render(target, scene, commandList); - } + if (scene->postProcessing.fsr2) { + gBufferRenderer.GenerateReactiveMask(target, commandList); - target->Swap(); + fsr2Renderer.Render(target, scene, commandList); + } + else { + taaRenderer.Render(target, scene, commandList); + } - postProcessRenderer.Render(target, scene, commandList, texture); + target->Swap(); - Graphics::Profiler::EndQuery(); - Graphics::Profiler::EndThread(); + postProcessRenderer.Render(target, scene, commandList, texture); - commandList->EndCommands(); - device->SubmitCommandList(commandList); + Graphics::Profiler::EndQuery(); + Graphics::Profiler::EndThread(); - renderState->renderList.Clear(); + commandList->EndCommands(); + device->SubmitCommandList(commandList); - } + renderState->renderList.Clear(); - void MainRenderer::PathTraceScene(Ref viewport, Ref target, - Ref scene, Texture::Texture2D *texture) { + } - if (!scene->IsRtDataValid() || !device->swapChain->isComplete || !scene->HasMainCamera()) - return; + void MainRenderer::PathTraceScene(Ref viewport, Ref target, + Ref scene, Texture::Texture2D* texture) { - if (!target->IsUsedForPathTracing()) - target->UseForPathTracing(true); + if (!scene->IsRtDataValid() || !device->swapChain->isComplete || !scene->HasMainCamera()) + return; - auto renderState = &scene->renderState; + if (!target->IsUsedForPathTracing()) + target->UseForPathTracing(true); - auto& camera = scene->GetMainCamera(); + auto renderState = &scene->renderState; - auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue); + auto& camera = scene->GetMainCamera(); - auto& taa = scene->postProcessing.taa; - if (taa.enable || scene->postProcessing.fsr2) { - vec2 jitter = vec2(0.0f); - if (scene->postProcessing.fsr2) { - jitter = fsr2Renderer.GetJitter(target, frameCount); - } - else { - jitter = 2.0f * haltonSequence[haltonIndex] - 1.0f; - jitter.x /= (float)target->GetScaledWidth() * 0.75f; - jitter.y /= (float)target->GetScaledHeight() * 0.75f; - } + auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue); - camera.Jitter(jitter * taa.jitterRange); - } - else { - // Even if there is no TAA we need to update the jitter for other techniques - // E.g. the reflections and ambient occlusion use reprojection - camera.Jitter(vec2(0.0f)); - } + auto& taa = scene->postProcessing.taa; + if (taa.enable || scene->postProcessing.fsr2) { + vec2 jitter = vec2(0.0f); + if (scene->postProcessing.fsr2) { + jitter = fsr2Renderer.GetJitter(target, frameCount); + } + else { + jitter = 2.0f * haltonSequence[haltonIndex] - 1.0f; + jitter.x /= (float)target->GetScaledWidth() * 0.75f; + jitter.y /= (float)target->GetScaledHeight() * 0.75f; + } - commandList->BeginCommands(); + camera.Jitter(jitter * taa.jitterRange); + } + else { + // Even if there is no TAA we need to update the jitter for other techniques + // E.g. the reflections and ambient occlusion use reprojection + camera.Jitter(vec2(0.0f)); + } - Graphics::Profiler::BeginThread("Path tracing", commandList); - Graphics::Profiler::BeginQuery("Buffer operations"); + commandList->BeginCommands(); - auto globalUniforms = GlobalUniforms{ - .vMatrix = camera.viewMatrix, - .pMatrix = camera.projectionMatrix, - .ivMatrix = camera.invViewMatrix, - .ipMatrix = camera.invProjectionMatrix, - .pvMatrixLast = camera.GetLastJitteredMatrix(), - .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, - .vMatrixLast = camera.GetLastViewMatrix(), - .jitterLast = camera.GetJitter(), - .jitterCurrent = camera.GetLastJitter(), - .cameraLocation = vec4(camera.GetLocation(), 0.0f), - .cameraDirection = vec4(camera.direction, 0.0f), - .cameraUp = vec4(camera.up, 0.0f), - .cameraRight = vec4(camera.right, 0.0f), - .planetCenter = vec4(scene->sky.planetCenter, 0.0f), - .planetRadius = scene->sky.planetRadius, - .time = Clock::Get(), - .deltaTime = Clock::GetDelta(), - .frameCount = frameCount - }; + Graphics::Profiler::BeginThread("Path tracing", commandList); + Graphics::Profiler::BeginQuery("Buffer operations"); - pathTraceGlobalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); + auto globalUniforms = GlobalUniforms{ + .vMatrix = camera.viewMatrix, + .pMatrix = camera.projectionMatrix, + .ivMatrix = camera.invViewMatrix, + .ipMatrix = camera.invProjectionMatrix, + .pvMatrixLast = camera.GetLastJitteredMatrix(), + .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, + .vMatrixLast = camera.GetLastViewMatrix(), + .jitterLast = camera.GetJitter(), + .jitterCurrent = camera.GetLastJitter(), + .cameraLocation = vec4(camera.GetLocation(), 0.0f), + .cameraDirection = vec4(camera.direction, 0.0f), + .cameraUp = vec4(camera.up, 0.0f), + .cameraRight = vec4(camera.right, 0.0f), + .planetCenter = vec4(scene->sky.planetCenter, 0.0f), + .planetRadius = scene->sky.planetRadius, + .time = Clock::Get(), + .deltaTime = Clock::GetDelta(), + .frameCount = frameCount, + .cameraNearPlane = camera.nearPlane, + .cameraFarPlane = camera.farPlane, + }; - JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); - JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); - JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); + pathTraceGlobalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); - commandList->BindBuffer(pathTraceGlobalUniformBuffer, 1, 31); - commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); - commandList->BindSampler(globalSampler, 1, 14); - commandList->BindSampler(globalNearestSampler, 1, 16); - commandList->BindBuffers(renderState->triangleBuffers, 0, 1); - if (renderState->textures.size()) - commandList->BindSampledImages(renderState->textures, 0, 3); + JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); + JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); - if (device->support.hardwareRayTracing) { - commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); - } - else { - commandList->BindBuffers(renderState->blasBuffers, 0, 0); - commandList->BindBuffers(renderState->bvhTriangleBuffers, 0, 2); - } + commandList->BindBuffer(pathTraceGlobalUniformBuffer, 1, 31); + commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); + commandList->BindSampler(globalSampler, 1, 14); + commandList->BindSampler(globalNearestSampler, 1, 16); + commandList->BindBuffers(renderState->triangleBuffers, 0, 1); + if (renderState->textures.size()) + commandList->BindSampledImages(renderState->textures, 0, 3); - Graphics::Profiler::EndQuery(); + if (device->support.hardwareRayTracing) { + commandList->BindBuffers(renderState->triangleOffsetBuffers, 0, 2); + } + else { + commandList->BindBuffers(renderState->blasBuffers, 0, 0); + commandList->BindBuffers(renderState->bvhTriangleBuffers, 0, 2); + } - // No probe filtering required - if (scene->sky.atmosphere) { - atmosphereRenderer.Render(scene->sky.atmosphere->probe, scene, commandList); - } + Graphics::Profiler::EndQuery(); - pathTracingRenderer.Render(target, scene, ivec2(1, 1), commandList); + // No probe filtering required + if (scene->sky.atmosphere) { + atmosphereRenderer.Render(scene->sky.atmosphere->probe, scene, commandList); + } - if (pathTracingRenderer.realTime) { - if (scene->postProcessing.fsr2) { - fsr2Renderer.Render(target, scene, commandList); - } - else { - taaRenderer.Render(target, scene, commandList); - } + pathTracingRenderer.Render(target, scene, ivec2(1, 1), commandList); - target->Swap(); + if (pathTracingRenderer.realTime) { + if (scene->postProcessing.fsr2) { + fsr2Renderer.Render(target, scene, commandList); + } + else { + taaRenderer.Render(target, scene, commandList); + } - postProcessRenderer.Render(target, scene, commandList, texture); - } - else { - Graphics::Profiler::BeginQuery("Post processing"); + target->Swap(); - if (device->swapChain->isComplete && !texture) { - commandList->BeginRenderPass(device->swapChain, true); + postProcessRenderer.Render(target, scene, commandList, texture); + } + else { + Graphics::Profiler::BeginQuery("Post processing"); - textureRenderer.RenderTexture2D(commandList, viewport, &target->outputTexture, - 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0f, 1.0f, false, true); + if (device->swapChain->isComplete && !texture) { + commandList->BeginRenderPass(device->swapChain, true); - commandList->EndRenderPass(); - } - else if (texture) { - postProcessRenderer.CopyToTexture(&target->outputTexture, texture, commandList); - } + textureRenderer.RenderTexture2D(commandList, viewport, &target->outputTexture, + 0.0f, 0.0f, float(viewport->width), float(viewport->height), 0.0f, 1.0f, false, true); - target->Swap(); + commandList->EndRenderPass(); + } + else if (texture) { + postProcessRenderer.CopyToTexture(&target->outputTexture, texture, commandList); + } - Graphics::Profiler::EndQuery(); - } + target->Swap(); - Graphics::Profiler::EndThread(); + Graphics::Profiler::EndQuery(); + } - commandList->EndCommands(); + Graphics::Profiler::EndThread(); - device->SubmitCommandList(commandList); + commandList->EndCommands(); - renderState->WaitForAsyncWorkCompletion(); + device->SubmitCommandList(commandList); - } + renderState->WaitForAsyncWorkCompletion(); - void MainRenderer::RenderPrimitiveBatch(Ref viewport, Ref target, - Ref batch, const CameraComponent& camera, Graphics::CommandList* commandList) { + } - bool localCommandList = !commandList; + void MainRenderer::RenderPrimitiveBatch(Ref viewport, Ref target, + Ref batch, const CameraComponent& camera, Graphics::CommandList* commandList) { - if (localCommandList) { - commandList = device->GetCommandList(Graphics::GraphicsQueue); + bool localCommandList = !commandList; - commandList->BeginCommands(); - } + if (localCommandList) { + commandList = device->GetCommandList(Graphics::GraphicsQueue); - batch->TransferData(); + commandList->BeginCommands(); + } - auto rtData = target->GetData(FULL_RES); + batch->TransferData(); - VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; + auto rtData = target->GetData(FULL_RES); - Graphics::ImageBarrier preImageBarriers[] = { - {target->lightingTexture.image, layout, access}, - {rtData->depthTexture->image, layout, access}, - {rtData->velocityTexture->image, layout, access}, - }; - commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; - commandList->BeginRenderPass(target->afterLightingRenderPass, target->afterLightingFrameBuffer); + Graphics::ImageBarrier preImageBarriers[] = { + {target->lightingTexture.image, layout, access}, + {rtData->depthTexture->image, layout, access}, + {rtData->velocityTexture->image, layout, access}, + }; + commandList->PipelineBarrier(preImageBarriers, {}, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - if (batch->GetLineCount()) { + commandList->BeginRenderPass(target->afterLightingRenderPass, target->afterLightingFrameBuffer); - auto pipelineConfig = GetPipelineConfigForPrimitives(target->afterLightingFrameBuffer, - batch->lineVertexArray, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, batch->testDepth); + if (batch->GetLineCount()) { - auto pipeline = PipelineManager::GetPipeline(pipelineConfig); + auto pipelineConfig = GetPipelineConfigForPrimitives(target->afterLightingFrameBuffer, + batch->lineVertexArray, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, batch->testDepth); - commandList->BindPipeline(pipeline); - batch->lineVertexArray.Bind(commandList); + auto pipeline = PipelineManager::GetPipeline(pipelineConfig); - commandList->SetLineWidth(batch->GetLineWidth()); + commandList->BindPipeline(pipeline); + batch->lineVertexArray.Bind(commandList); - commandList->Draw(batch->GetLineCount() * 2); + commandList->SetLineWidth(batch->GetLineWidth()); - } + commandList->Draw(batch->GetLineCount() * 2); + } - if (batch->GetTriangleCount()) { - auto pipelineConfig = GetPipelineConfigForPrimitives(target->afterLightingFrameBuffer, - batch->triangleVertexArray, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, batch->testDepth); + if (batch->GetTriangleCount()) { - auto pipeline = PipelineManager::GetPipeline(pipelineConfig); + auto pipelineConfig = GetPipelineConfigForPrimitives(target->afterLightingFrameBuffer, + batch->triangleVertexArray, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, batch->testDepth); - commandList->BindPipeline(pipeline); - batch->triangleVertexArray.Bind(commandList); + auto pipeline = PipelineManager::GetPipeline(pipelineConfig); - commandList->Draw(batch->GetTriangleCount() * 3); + commandList->BindPipeline(pipeline); + batch->triangleVertexArray.Bind(commandList); - } + commandList->Draw(batch->GetTriangleCount() * 3); - commandList->EndRenderPass(); + } - Graphics::ImageBarrier postImageBarriers[] = { - {target->lightingTexture.image, layout, access}, - {rtData->depthTexture->image, layout, access}, - {rtData->velocityTexture->image, layout, access}, - {rtData->stencilTexture->image, layout, access}, - }; - commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + commandList->EndRenderPass(); - if (localCommandList) { - commandList->EndCommands(); + Graphics::ImageBarrier postImageBarriers[] = { + {target->lightingTexture.image, layout, access}, + {rtData->depthTexture->image, layout, access}, + {rtData->velocityTexture->image, layout, access}, + {rtData->stencilTexture->image, layout, access}, + }; + commandList->PipelineBarrier(postImageBarriers, {}, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - device->SubmitCommandList(commandList); - } + if (localCommandList) { + commandList->EndCommands(); - } + device->SubmitCommandList(commandList); + } - void MainRenderer::RenderProbe(Ref probe, Ref target, Ref scene) { + } - /* - if (probe->resolution != target->GetWidth() || - probe->resolution != target->GetHeight()) - return; + void MainRenderer::RenderProbe(Ref probe, Ref target, Ref scene) { - std::vector materials; - std::unordered_map materialMap; - Viewport viewport(0, 0, probe->resolution, probe->resolution); + /* + if (probe->resolution != target->GetWidth() || + probe->resolution != target->GetHeight()) + return; - PrepareMaterials(scene, materials, materialMap); + std::vector materials; + std::unordered_map materialMap; + Viewport viewport(0, 0, probe->resolution, probe->resolution); - auto materialBuffer = Buffer::Buffer(AE_SHADER_STORAGE_BUFFER, sizeof(PackedMaterial), 0, - materials.size(), materials.data()); + PrepareMaterials(scene, materials, materialMap); - Lighting::EnvironmentProbe* skyProbe = nullptr; + auto materialBuffer = Buffer::Buffer(AE_SHADER_STORAGE_BUFFER, sizeof(PackedMaterial), 0, + materials.size(), materials.data()); - if (scene->sky.probe) { - skyProbe = scene->sky.probe; - scene->sky.probe = nullptr; - } + Lighting::EnvironmentProbe* skyProbe = nullptr; - vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), - vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; + if (scene->sky.probe) { + skyProbe = scene->sky.probe; + scene->sky.probe = nullptr; + } - vec3 ups[] = { vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f), - vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f) }; + vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), + vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; - Camera camera(90.0f, 1.0f, 0.5f, 1000.0f); - camera.UpdateProjection(); + vec3 ups[] = { vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f), + vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f) }; - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); + Camera camera(90.0f, 1.0f, 0.5f, 1000.0f); + camera.UpdateProjection(); - for (uint8_t i = 0; i < 6; i++) { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); - vec3 dir = faces[i]; - vec3 up = ups[i]; - vec3 right = normalize(cross(up, dir)); - up = normalize(cross(dir, right)); + for (uint8_t i = 0; i < 6; i++) { - camera.viewMatrix = glm::lookAt(probe->GetPosition(), probe->GetPosition() + dir, up); - camera.invViewMatrix = glm::inverse(camera.viewMatrix); - camera.location = probe->GetPosition(); - camera.direction = dir; - camera.right = right; - camera.up = up; + vec3 dir = faces[i]; + vec3 up = ups[i]; + vec3 right = normalize(cross(up, dir)); + up = normalize(cross(dir, right)); - camera.frustum = Volume::Frustum(camera.projectionMatrix * camera.viewMatrix); + camera.viewMatrix = glm::lookAt(probe->GetPosition(), probe->GetPosition() + dir, up); + camera.invViewMatrix = glm::inverse(camera.viewMatrix); + camera.location = probe->GetPosition(); + camera.direction = dir; + camera.right = right; + camera.up = up; - scene->Update(&camera, 0.0f); + camera.frustum = Volume::Frustum(camera.projectionMatrix * camera.viewMatrix); - // Clear the lights depth maps - depthFramebuffer.Bind(); + scene->Update(&camera, 0.0f); - auto lights = scene->GetLights(); + // Clear the lights depth maps + depthFramebuffer.Bind(); - if (scene->sky.sun) { - lights.push_back(scene->sky.sun); - } + auto lights = scene->GetLights(); - for (auto light : lights) { + if (scene->sky.sun) { + lights.push_back(scene->sky.sun); + } - if (!light->GetShadow()) - continue; - if (!light->GetShadow()->update) - continue; + for (auto light : lights) { - for (int32_t j = 0; j < light->GetShadow()->componentCount; j++) { - if (light->GetShadow()->useCubemap) { - depthFramebuffer.AddComponentCubemap(GL_DEPTH_ATTACHMENT, - &light->GetShadow()->cubemap, j); - } - else { - depthFramebuffer.AddComponentTextureArray(GL_DEPTH_ATTACHMENT, - &light->GetShadow()->maps, j); - } + if (!light->GetShadow()) + continue; + if (!light->GetShadow()->update) + continue; - glClear(GL_DEPTH_BUFFER_BIT); - } - } + for (int32_t j = 0; j < light->GetShadow()->componentCount; j++) { + if (light->GetShadow()->useCubemap) { + depthFramebuffer.AddComponentCubemap(GL_DEPTH_ATTACHMENT, + &light->GetShadow()->cubemap, j); + } + else { + depthFramebuffer.AddComponentTextureArray(GL_DEPTH_ATTACHMENT, + &light->GetShadow()->maps, j); + } - shadowRenderer.Render(&viewport, target, &camera, scene); + glClear(GL_DEPTH_BUFFER_BIT); + } + } - glEnable(GL_CULL_FACE); + shadowRenderer.Render(&viewport, target, &camera, scene); - glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); - terrainShadowRenderer.Render(&viewport, target, &camera, scene); + glCullFace(GL_FRONT); - glCullFace(GL_BACK); + terrainShadowRenderer.Render(&viewport, target, &camera, scene); - // Shadows have been updated - for (auto light : lights) { - if (!light->GetShadow()) - continue; - light->GetShadow()->update = false; - } + glCullFace(GL_BACK); - materialBuffer.BindBase(0); + // Shadows have been updated + for (auto light : lights) { + if (!light->GetShadow()) + continue; + light->GetShadow()->update = false; + } - target->geometryFramebuffer.Bind(true); - target->geometryFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, - GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 }); + materialBuffer.BindBase(0); - glEnable(GL_CULL_FACE); + target->geometryFramebuffer.Bind(true); + target->geometryFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 }); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glEnable(GL_CULL_FACE); - opaqueRenderer.Render(&viewport, target, &camera, scene, materialMap); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - terrainRenderer.Render(&viewport, target, &camera, scene, materialMap); + opaqueRenderer.Render(&viewport, target, &camera, scene, materialMap); - glEnable(GL_CULL_FACE); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + terrainRenderer.Render(&viewport, target, &camera, scene, materialMap); - target->geometryFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }); + glEnable(GL_CULL_FACE); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - decalRenderer.Render(&viewport, target, &camera, scene); + target->geometryFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }); - glDisable(GL_BLEND); + decalRenderer.Render(&viewport, target, &camera, scene); - vertexArray.Bind(); + glDisable(GL_BLEND); - target->lightingFramebuffer.Bind(true); - target->lightingFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0 }); + vertexArray.Bind(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + target->lightingFramebuffer.Bind(true); + target->lightingFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0 }); - directionalLightRenderer.Render(&viewport, target, &camera, scene); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); + directionalLightRenderer.Render(&viewport, target, &camera, scene); - target->lightingFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1 }); + glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); + target->lightingFramebuffer.SetDrawBuffers({ GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1 }); - oceanRenderer.Render(&viewport, target, &camera, scene); + glDepthMask(GL_TRUE); - glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); + oceanRenderer.Render(&viewport, target, &camera, scene); - vertexArray.Bind(); + glDisable(GL_CULL_FACE); + glCullFace(GL_BACK); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); - volumetricRenderer.Render(&viewport, target, &camera, scene); + vertexArray.Bind(); - createProbeFaceShader.Bind(); + volumetricRenderer.Render(&viewport, target, &camera, scene); - createProbeFaceShader.GetUniform("faceIndex")->SetValue((int32_t)i); - createProbeFaceShader.GetUniform("ipMatrix")->SetValue(camera.invProjectionMatrix); + createProbeFaceShader.Bind(); - int32_t groupCount = probe->resolution / 8; - groupCount += ((groupCount * 8 == probe->resolution) ? 0 : 1); + createProbeFaceShader.GetUniform("faceIndex")->SetValue((int32_t)i); + createProbeFaceShader.GetUniform("ipMatrix")->SetValue(camera.invProjectionMatrix); - probe->cubemap.Bind(GL_WRITE_ONLY, 0); - probe->depth.Bind(GL_WRITE_ONLY, 1); + int32_t groupCount = probe->resolution / 8; + groupCount += ((groupCount * 8 == probe->resolution) ? 0 : 1); - target->lightingFramebuffer.GetComponentTexture(GL_COLOR_ATTACHMENT0)->Bind(0); - target->lightingFramebuffer.GetComponentTexture(GL_DEPTH_ATTACHMENT)->Bind(1); + probe->cubemap.Bind(GL_WRITE_ONLY, 0); + probe->depth.Bind(GL_WRITE_ONLY, 1); - glDispatchCompute(groupCount, groupCount, 1); + target->lightingFramebuffer.GetComponentTexture(GL_COLOR_ATTACHMENT0)->Bind(0); + target->lightingFramebuffer.GetComponentTexture(GL_DEPTH_ATTACHMENT)->Bind(1); - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + glDispatchCompute(groupCount, groupCount, 1); - } + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - if (skyProbe) { - scene->sky.probe = skyProbe; - } - */ + } - } + if (skyProbe) { + scene->sky.probe = skyProbe; + } + */ - void MainRenderer::FilterProbe(Ref probe, Graphics::CommandList* commandList) { + } - Graphics::Profiler::BeginQuery("Filter probe"); + void MainRenderer::FilterProbe(Ref probe, Graphics::CommandList* commandList) { - mat4 projectionMatrix = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 100.0f); - vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), - vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; + Graphics::Profiler::BeginQuery("Filter probe"); - vec3 ups[] = { vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f), - vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f) }; + mat4 projectionMatrix = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 100.0f); + vec3 faces[] = { vec3(1.0f, 0.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), + vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f) }; - Graphics::Profiler::BeginQuery("Filter diffuse probe"); + vec3 ups[] = { vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, 0.0f, 1.0f), vec3(0.0f, 0.0f, -1.0f), + vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, -1.0f, 0.0f) }; - auto pipelineConfig = PipelineConfig("brdf/filterProbe.csh", { "FILTER_DIFFUSE" }); - auto pipeline = PipelineManager::GetPipeline(pipelineConfig); + Graphics::Profiler::BeginQuery("Filter diffuse probe"); - commandList->BindPipeline(pipeline); + auto pipelineConfig = PipelineConfig("brdf/filterProbe.csh", { "FILTER_DIFFUSE" }); + auto pipeline = PipelineManager::GetPipeline(pipelineConfig); - //auto constantRange = pipeline->shader->GetPushConstantRange("constants"); - //commandList->PushConstants() + commandList->BindPipeline(pipeline); - // It's only accessed in compute shaders - commandList->ImageMemoryBarrier(probe->filteredDiffuse.image, VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - - auto& cubemap = probe->GetCubemap(); - if (cubemap.image->layout == VK_IMAGE_LAYOUT_UNDEFINED) { - commandList->ImageMemoryBarrier(cubemap.image, VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - } + //auto constantRange = pipeline->shader->GetPushConstantRange("constants"); + //commandList->PushConstants() - commandList->BindImage(probe->filteredDiffuse.image, 3, 0); - commandList->BindImage(cubemap.image, cubemap.sampler, 3, 1); + // It's only accessed in compute shaders + commandList->ImageMemoryBarrier(probe->filteredDiffuse.image, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - ivec2 res = ivec2(probe->filteredDiffuse.width, probe->filteredDiffuse.height); - ivec2 groupCount = ivec2(res.x / 8, res.y / 4); - groupCount.x += ((groupCount.x * 8 == res.x) ? 0 : 1); - groupCount.y += ((groupCount.y * 4 == res.y) ? 0 : 1); + auto& cubemap = probe->GetCubemap(); + if (cubemap.image->layout == VK_IMAGE_LAYOUT_UNDEFINED) { + commandList->ImageMemoryBarrier(cubemap.image, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + } - commandList->Dispatch(groupCount.x, groupCount.y, 6); + commandList->BindImage(probe->filteredDiffuse.image, 3, 0); + commandList->BindImage(cubemap.image, cubemap.sampler, 3, 1); - commandList->ImageMemoryBarrier(probe->filteredDiffuse.image, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + ivec2 res = ivec2(probe->filteredDiffuse.width, probe->filteredDiffuse.height); + ivec2 groupCount = ivec2(res.x / 8, res.y / 4); + groupCount.x += ((groupCount.x * 8 == res.x) ? 0 : 1); + groupCount.y += ((groupCount.y * 4 == res.y) ? 0 : 1); - Graphics::Profiler::EndAndBeginQuery("Filter specular probe"); + commandList->Dispatch(groupCount.x, groupCount.y, 6); - pipelineConfig = PipelineConfig("brdf/filterProbe.csh", { "FILTER_SPECULAR" }); - pipeline = PipelineManager::GetPipeline(pipelineConfig); + commandList->ImageMemoryBarrier(probe->filteredDiffuse.image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - struct alignas(16) PushConstants { - int cubeMapMipLevels; - float roughness; - uint32_t mipLevel; - }; + Graphics::Profiler::EndAndBeginQuery("Filter specular probe"); - commandList->BindPipeline(pipeline); + pipelineConfig = PipelineConfig("brdf/filterProbe.csh", { "FILTER_SPECULAR" }); + pipeline = PipelineManager::GetPipeline(pipelineConfig); - commandList->ImageMemoryBarrier(probe->filteredSpecular.image, VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + struct alignas(16) PushConstants { + int cubeMapMipLevels; + float roughness; + uint32_t mipLevel; + }; - int32_t width = int32_t(probe->filteredSpecular.width); - int32_t height = int32_t(probe->filteredSpecular.height); + commandList->BindPipeline(pipeline); - for (uint32_t i = 0; i < probe->filteredSpecular.image->mipLevels; i++) { - Graphics::Profiler::BeginQuery("Mip level " + std::to_string(i)); + commandList->ImageMemoryBarrier(probe->filteredSpecular.image, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - ivec2 res = ivec2(width, height); + int32_t width = int32_t(probe->filteredSpecular.width); + int32_t height = int32_t(probe->filteredSpecular.height); - commandList->BindImage(probe->filteredSpecular.image, 3, 0, i); + for (uint32_t i = 0; i < probe->filteredSpecular.image->mipLevels; i++) { + Graphics::Profiler::BeginQuery("Mip level " + std::to_string(i)); - PushConstants pushConstants = { - .cubeMapMipLevels = int32_t(probe->GetCubemap().image->mipLevels), - .roughness = float(i) / float(probe->filteredSpecular.image->mipLevels - 1), - .mipLevel = i - }; - commandList->PushConstants("constants", &pushConstants); - - ivec2 groupCount = ivec2(res.x / 8, res.y / 4); - groupCount.x += ((groupCount.x * 8 == res.x) ? 0 : 1); - groupCount.y += ((groupCount.y * 4 == res.y) ? 0 : 1); - - commandList->Dispatch(groupCount.x, groupCount.y, 6); - - width /= 2; - height /= 2; - - Graphics::Profiler::EndQuery(); - - } - - commandList->ImageMemoryBarrier(probe->filteredSpecular.image, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - Graphics::Profiler::EndQuery(); - - Graphics::Profiler::EndQuery(); - - } - - void MainRenderer::Update() { - - textRenderer.Update(); - - haltonIndex = (haltonIndex + 1) % haltonSequence.size(); - frameCount++; - - } - - void MainRenderer::CreateGlobalDescriptorSetLayout() { - - if (!device->support.bindless) - return; - - auto samplerDesc = Graphics::SamplerDesc { - .filter = VK_FILTER_LINEAR, - .mode = VK_SAMPLER_ADDRESS_MODE_REPEAT, - .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, - .maxLod = 12, - .anisotropicFiltering = true - }; - globalSampler = device->CreateSampler(samplerDesc); - - samplerDesc = Graphics::SamplerDesc{ - .filter = VK_FILTER_NEAREST, - .mode = VK_SAMPLER_ADDRESS_MODE_REPEAT, - .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, - .maxLod = 12, - .anisotropicFiltering = false - }; - globalNearestSampler = device->CreateSampler(samplerDesc); - - auto layoutDesc = Graphics::DescriptorSetLayoutDesc{ - .bindings = { - { - .bindingIdx = 0, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .descriptorCount = 8192, .bindless = true - }, - { - .bindingIdx = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .descriptorCount = 8192, .bindless = true - }, - { - .bindingIdx = 2, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - .descriptorCount = 8192, .bindless = true - }, - { - .bindingIdx = 3, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = 16384, .bindless = true - } - }, - .bindingCount = 4 - }; - globalDescriptorSetLayout = device->CreateDescriptorSetLayout(layoutDesc); - - PipelineManager::OverrideDescriptorSetLayout(globalDescriptorSetLayout, 0); - - } - - void MainRenderer::SetUniforms(const Ref& target, const Ref& scene, const CameraComponent& camera) { - - auto globalUniforms = GlobalUniforms { - .vMatrix = camera.viewMatrix, - .pMatrix = camera.projectionMatrix, - .ivMatrix = camera.invViewMatrix, - .ipMatrix = camera.invProjectionMatrix, - .pvMatrixLast = camera.GetLastJitteredMatrix(), - .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, - .ipvMatrixLast = glm::inverse(camera.GetLastJitteredMatrix()), - .ipvMatrixCurrent = glm::inverse(camera.projectionMatrix * camera.viewMatrix), - .vMatrixLast = camera.GetLastViewMatrix(), - .jitterLast = camera.GetLastJitter(), - .jitterCurrent = camera.GetJitter(), - .cameraLocation = vec4(camera.GetLocation(), 0.0f), - .cameraDirection = vec4(camera.direction, 0.0f), - .cameraUp = vec4(camera.up, 0.0f), - .cameraRight = vec4(camera.right, 0.0f), - .planetCenter = vec4(scene->sky.planetCenter, 0.0f), - .windDir = glm::normalize(scene->wind.direction), - .windSpeed = scene->wind.speed, - .planetRadius = scene->sky.planetRadius, - .time = Clock::Get(), - .deltaTime = Clock::GetDelta(), - .frameCount = frameCount, - .mipLodBias = -1.0f / target->GetScalingFactor() - }; - - auto frustumPlanes = camera.frustum.GetPlanes(); - std::copy(frustumPlanes.begin(), frustumPlanes.end(), &globalUniforms.frustumPlanes[0]); - - globalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); - - if (scene->irradianceVolume) { - auto volume = scene->irradianceVolume; - - if (volume->scroll) { - auto pos = camera.GetLocation(); - - auto volumeSize = volume->aabb.GetSize(); - auto volumeAABB = Volume::AABB(-volumeSize / 2.0f + pos, volumeSize / 2.0f + pos); - volume->SetAABB(volumeAABB); - } - - auto probeCountPerCascade = volume->probeCount.x * volume->probeCount.y * - volume->probeCount.z; - auto ddgiUniforms = DDGIUniforms { - .volumeCenter = vec4(camera.GetLocation(), 1.0f), - .volumeProbeCount = ivec4(volume->probeCount, probeCountPerCascade), - .cascadeCount = volume->cascadeCount, - .volumeBias = volume->bias, - .volumeIrradianceRes = volume->irrRes, - .volumeMomentsRes = volume->momRes, - .rayCount = volume->rayCount, - .inactiveRayCount = volume->rayCountInactive, - .hysteresis = volume->hysteresis, - .volumeGamma = volume->gamma, - .volumeStrength = volume->strength, - .depthSharpness = volume->sharpness, - .optimizeProbes = volume->optimizeProbes ? 1 : 0, - .volumeEnabled = volume->enable ? 1 : 0 - }; - - for (int32_t i = 0; i < volume->cascadeCount; i++) { - ddgiUniforms.cascades[i] = DDGICascade{ - .volumeMin = vec4(volume->cascades[i].aabb.min, 1.0f), - .volumeMax = vec4(volume->cascades[i].aabb.max, 1.0f), - .cellSize = vec4(volume->cascades[i].cellSize, glm::length(volume->cascades[i].cellSize)), - .offsetDifference = ivec4(volume->cascades[i].offsetDifferences, 0), - }; - } - - ddgiUniformBuffer->SetData(&ddgiUniforms, 0, sizeof(DDGIUniforms)); - } - else { - auto ddgiUniforms = DDGIUniforms { - .volumeEnabled = 0 - }; - - for (int32_t i = 0; i < MAX_IRRADIANCE_VOLUME_CASCADES; i++) { - ddgiUniforms.cascades[i] = DDGICascade { - .volumeMin = vec4(0.0f), - .volumeMax = vec4(0.0f), - .cellSize = vec4(0.0f), - }; - } - - ddgiUniformBuffer->SetData(&ddgiUniforms, 0, sizeof(DDGIUniforms)); - } - - auto meshes = scene->GetMeshes(); - for (auto& mesh : meshes) { - if (!mesh.IsLoaded() || !mesh->impostor) continue; - - auto impostor = mesh->impostor; - Mesh::Impostor::ImpostorInfo impostorInfo = { - .center = vec4(impostor->center, 1.0f), - .radius = impostor->radius, - .views = impostor->views, - .cutoff = impostor->cutoff, - .mipBias = impostor->mipBias - }; - - impostor->impostorInfoBuffer.SetData(&impostorInfo, 0); - } - - } - - void MainRenderer::PreintegrateBRDF() { - - auto pipelineConfig = PipelineConfig("brdf/preintegrateDFG.csh"); - auto computePipeline = PipelineManager::GetPipeline(pipelineConfig); - - const int32_t res = 256; - dfgPreintegrationTexture = Texture::Texture2D(res, res, VK_FORMAT_R16G16B16A16_SFLOAT, - Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); - - auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue, true); - - commandList->BeginCommands(); - commandList->BindPipeline(computePipeline); - - auto barrier = Graphics::ImageBarrier(VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - commandList->ImageMemoryBarrier(barrier.Update(dfgPreintegrationTexture.image), - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); - - uint32_t groupCount = res / 8; - - commandList->BindImage(dfgPreintegrationTexture.image, 3, 0); - commandList->Dispatch(groupCount, groupCount, 1); - - barrier = Graphics::ImageBarrier(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_SHADER_READ_BIT); - commandList->ImageMemoryBarrier(barrier.Update(dfgPreintegrationTexture.image), - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - - commandList->EndCommands(); - device->FlushCommandList(commandList); - - } - - PipelineConfig MainRenderer::GetPipelineConfigForPrimitives(Ref &frameBuffer, - Buffer::VertexArray &vertexArray, VkPrimitiveTopology topology, bool testDepth) { - - const auto shaderConfig = ShaderConfig { - { "primitive.vsh", VK_SHADER_STAGE_VERTEX_BIT}, - { "primitive.fsh", VK_SHADER_STAGE_FRAGMENT_BIT}, - }; - - auto pipelineDesc = Graphics::GraphicsPipelineDesc { - .frameBuffer = frameBuffer, - .vertexInputInfo = vertexArray.GetVertexInputState(), - }; - - pipelineDesc.assemblyInputInfo.topology = topology; - pipelineDesc.depthStencilInputInfo.depthTestEnable = testDepth; - pipelineDesc.rasterizer.cullMode = VK_CULL_MODE_NONE; - pipelineDesc.rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + ivec2 res = ivec2(width, height); - return PipelineConfig(shaderConfig, pipelineDesc); + commandList->BindImage(probe->filteredSpecular.image, 3, 0, i); - } + PushConstants pushConstants = { + .cubeMapMipLevels = int32_t(probe->GetCubemap().image->mipLevels), + .roughness = float(i) / float(probe->filteredSpecular.image->mipLevels - 1), + .mipLevel = i + }; + commandList->PushConstants("constants", &pushConstants); - } + ivec2 groupCount = ivec2(res.x / 8, res.y / 4); + groupCount.x += ((groupCount.x * 8 == res.x) ? 0 : 1); + groupCount.y += ((groupCount.y * 4 == res.y) ? 0 : 1); + + commandList->Dispatch(groupCount.x, groupCount.y, 6); + + width /= 2; + height /= 2; + + Graphics::Profiler::EndQuery(); + + } + + commandList->ImageMemoryBarrier(probe->filteredSpecular.image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + Graphics::Profiler::EndQuery(); + + Graphics::Profiler::EndQuery(); + + } + + void MainRenderer::Update() { + + textRenderer.Update(); + + haltonIndex = (haltonIndex + 1) % haltonSequence.size(); + frameCount++; + + } + + void MainRenderer::CreateGlobalDescriptorSetLayout() { + + if (!device->support.bindless) + return; + + auto samplerDesc = Graphics::SamplerDesc{ + .filter = VK_FILTER_LINEAR, + .mode = VK_SAMPLER_ADDRESS_MODE_REPEAT, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .maxLod = 12, + .anisotropicFiltering = true + }; + globalSampler = device->CreateSampler(samplerDesc); + + samplerDesc = Graphics::SamplerDesc{ + .filter = VK_FILTER_NEAREST, + .mode = VK_SAMPLER_ADDRESS_MODE_REPEAT, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .maxLod = 12, + .anisotropicFiltering = false + }; + globalNearestSampler = device->CreateSampler(samplerDesc); + + auto layoutDesc = Graphics::DescriptorSetLayoutDesc{ + .bindings = { + { + .bindingIdx = 0, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 8192, .bindless = true + }, + { + .bindingIdx = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 8192, .bindless = true + }, + { + .bindingIdx = 2, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 8192, .bindless = true + }, + { + .bindingIdx = 3, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 16384, .bindless = true + } + }, + .bindingCount = 4 + }; + globalDescriptorSetLayout = device->CreateDescriptorSetLayout(layoutDesc); + + PipelineManager::OverrideDescriptorSetLayout(globalDescriptorSetLayout, 0); + + } + + void MainRenderer::SetUniforms(const Ref& target, const Ref& scene, const CameraComponent& camera) { + + auto globalUniforms = GlobalUniforms{ + .vMatrix = camera.viewMatrix, + .pMatrix = camera.projectionMatrix, + .ivMatrix = camera.invViewMatrix, + .ipMatrix = camera.invProjectionMatrix, + .pvMatrixLast = camera.GetLastJitteredMatrix(), + .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, + .ipvMatrixLast = glm::inverse(camera.GetLastJitteredMatrix()), + .ipvMatrixCurrent = glm::inverse(camera.projectionMatrix * camera.viewMatrix), + .vMatrixLast = camera.GetLastViewMatrix(), + .jitterLast = camera.GetLastJitter(), + .jitterCurrent = camera.GetJitter(), + .cameraLocation = vec4(camera.GetLocation(), 0.0f), + .cameraDirection = vec4(camera.direction, 0.0f), + .cameraUp = vec4(camera.up, 0.0f), + .cameraRight = vec4(camera.right, 0.0f), + .planetCenter = vec4(scene->sky.planetCenter, 0.0f), + .windDir = glm::normalize(scene->wind.direction), + .windSpeed = scene->wind.speed, + .planetRadius = scene->sky.planetRadius, + .time = Clock::Get(), + .deltaTime = Clock::GetDelta(), + .frameCount = frameCount, + .mipLodBias = -1.0f / target->GetScalingFactor(), + .cameraNearPlane = camera.nearPlane, + .cameraFarPlane = camera.farPlane, + }; + + auto frustumPlanes = camera.frustum.GetPlanes(); + std::copy(frustumPlanes.begin(), frustumPlanes.end(), &globalUniforms.frustumPlanes[0]); + + globalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); + + if (scene->irradianceVolume) { + auto volume = scene->irradianceVolume; + + if (volume->scroll) { + auto pos = camera.GetLocation(); + + auto volumeSize = volume->aabb.GetSize(); + auto volumeAABB = Volume::AABB(-volumeSize / 2.0f + pos, volumeSize / 2.0f + pos); + volume->SetAABB(volumeAABB); + } + + auto probeCountPerCascade = volume->probeCount.x * volume->probeCount.y * + volume->probeCount.z; + auto ddgiUniforms = DDGIUniforms{ + .volumeCenter = vec4(camera.GetLocation(), 1.0f), + .volumeProbeCount = ivec4(volume->probeCount, probeCountPerCascade), + .cascadeCount = volume->cascadeCount, + .volumeBias = volume->bias, + .volumeIrradianceRes = volume->irrRes, + .volumeMomentsRes = volume->momRes, + .rayCount = volume->rayCount, + .inactiveRayCount = volume->rayCountInactive, + .hysteresis = volume->hysteresis, + .volumeGamma = volume->gamma, + .volumeStrength = volume->strength, + .depthSharpness = volume->sharpness, + .optimizeProbes = volume->optimizeProbes ? 1 : 0, + .volumeEnabled = volume->enable ? 1 : 0 + }; + + for (int32_t i = 0; i < volume->cascadeCount; i++) { + ddgiUniforms.cascades[i] = DDGICascade{ + .volumeMin = vec4(volume->cascades[i].aabb.min, 1.0f), + .volumeMax = vec4(volume->cascades[i].aabb.max, 1.0f), + .cellSize = vec4(volume->cascades[i].cellSize, glm::length(volume->cascades[i].cellSize)), + .offsetDifference = ivec4(volume->cascades[i].offsetDifferences, 0), + }; + } + + ddgiUniformBuffer->SetData(&ddgiUniforms, 0, sizeof(DDGIUniforms)); + } + else { + auto ddgiUniforms = DDGIUniforms{ + .volumeEnabled = 0 + }; + + for (int32_t i = 0; i < MAX_IRRADIANCE_VOLUME_CASCADES; i++) { + ddgiUniforms.cascades[i] = DDGICascade{ + .volumeMin = vec4(0.0f), + .volumeMax = vec4(0.0f), + .cellSize = vec4(0.0f), + }; + } + + ddgiUniformBuffer->SetData(&ddgiUniforms, 0, sizeof(DDGIUniforms)); + } + + auto meshes = scene->GetMeshes(); + for (auto& mesh : meshes) { + if (!mesh.IsLoaded() || !mesh->impostor) continue; + + auto impostor = mesh->impostor; + Mesh::Impostor::ImpostorInfo impostorInfo = { + .center = vec4(impostor->center, 1.0f), + .radius = impostor->radius, + .views = impostor->views, + .cutoff = impostor->cutoff, + .mipBias = impostor->mipBias + }; + + impostor->impostorInfoBuffer.SetData(&impostorInfo, 0); + } + + } + + void MainRenderer::PreintegrateBRDF() { + + auto pipelineConfig = PipelineConfig("brdf/preintegrateDFG.csh"); + auto computePipeline = PipelineManager::GetPipeline(pipelineConfig); + + const int32_t res = 256; + dfgPreintegrationTexture = Texture::Texture2D(res, res, VK_FORMAT_R16G16B16A16_SFLOAT, + Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear); + + auto commandList = device->GetCommandList(Graphics::QueueType::GraphicsQueue, true); + + commandList->BeginCommands(); + commandList->BindPipeline(computePipeline); + + auto barrier = Graphics::ImageBarrier(VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); + commandList->ImageMemoryBarrier(barrier.Update(dfgPreintegrationTexture.image), + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + uint32_t groupCount = res / 8; + + commandList->BindImage(dfgPreintegrationTexture.image, 3, 0); + commandList->Dispatch(groupCount, groupCount, 1); + + barrier = Graphics::ImageBarrier(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_SHADER_READ_BIT); + commandList->ImageMemoryBarrier(barrier.Update(dfgPreintegrationTexture.image), + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + + commandList->EndCommands(); + device->FlushCommandList(commandList); + + } + + PipelineConfig MainRenderer::GetPipelineConfigForPrimitives(Ref& frameBuffer, + Buffer::VertexArray& vertexArray, VkPrimitiveTopology topology, bool testDepth) { + + const auto shaderConfig = ShaderConfig{ + { "primitive.vsh", VK_SHADER_STAGE_VERTEX_BIT}, + { "primitive.fsh", VK_SHADER_STAGE_FRAGMENT_BIT}, + }; + + auto pipelineDesc = Graphics::GraphicsPipelineDesc{ + .frameBuffer = frameBuffer, + .vertexInputInfo = vertexArray.GetVertexInputState(), + }; + + pipelineDesc.assemblyInputInfo.topology = topology; + pipelineDesc.depthStencilInputInfo.depthTestEnable = testDepth; + pipelineDesc.rasterizer.cullMode = VK_CULL_MODE_NONE; + pipelineDesc.rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + + return PipelineConfig(shaderConfig, pipelineDesc); + + } + + } } diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index 02345cca9..063e8668a 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -20,6 +20,7 @@ namespace Atlas { VK_FORMAT_R8G8B8A8_UNORM); sobolSequenceTexture.SetData(noiseImage->GetData()); + ssrPipelineConfig = PipelineConfig("reflection/ssr.csh"); rtrPipelineConfig = PipelineConfig("reflection/rtreflection.csh"); upsamplePipelineConfig = PipelineConfig("reflection/upsample.csh"); temporalPipelineConfig = PipelineConfig("reflection/temporal.csh"); @@ -67,7 +68,7 @@ namespace Atlas { commandList->PipelineBarrier(imageBarriers, {}); } - Graphics::Profiler::BeginQuery("Trace rays"); + // Try to get a shadow map Ref shadow = nullptr; @@ -85,6 +86,7 @@ namespace Atlas { auto offsetTexture = downsampledRT->offsetTexture; auto velocityTexture = downsampledRT->velocityTexture; auto materialIdxTexture = downsampledRT->materialIdxTexture; + auto lightingTexture = &target->lightingTexture; // Bind the geometry normal texure and depth texture commandList->BindImage(normalTexture->image, normalTexture->sampler, 3, 1); @@ -96,13 +98,91 @@ namespace Atlas { commandList->BindImage(scramblingRankingTexture.image, scramblingRankingTexture.sampler, 3, 7); commandList->BindImage(sobolSequenceTexture.image, sobolSequenceTexture.sampler, 3, 8); + commandList->BindImage(lightingTexture->image, lightingTexture->sampler, 3, 9); + Texture::Texture2D* reflectionTexture = reflection->upsampleBeforeFiltering ? &target->swapReflectionTexture : &target->reflectionTexture; Texture::Texture2D* swapReflectionTexture = reflection->upsampleBeforeFiltering ? &target->reflectionTexture : &target->swapReflectionTexture; - // Cast rays and calculate radiance + static uint32_t frameCount = 0; + + RTRUniforms uniforms; + uniforms.radianceLimit = reflection->radianceLimit; + uniforms.bias = reflection->bias; + uniforms.roughnessCutoff = reflection->roughnessCutoff; + uniforms.frameSeed = frameCount++; + uniforms.sampleCount = reflection->sampleCount; + uniforms.lightSampleCount = reflection->lightSampleCount; + uniforms.textureLevel = reflection->textureLevel; + uniforms.halfRes = target->GetReflectionResolution() == HALF_RES ? 1 : 0; + uniforms.resolution = rayRes; + + if (shadow && reflection->useShadowMap) { + auto& shadowUniform = uniforms.shadow; + shadowUniform.distance = !shadow->longRange ? shadow->distance : shadow->longRangeDistance; + shadowUniform.bias = shadow->bias; + shadowUniform.edgeSoftness = shadow->edgeSoftness; + shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; + shadowUniform.cascadeCount = shadow->viewCount; + shadowUniform.resolution = vec2(shadow->resolution); + + commandList->BindImage(shadow->maps->image, shadowSampler, 3, 6); + + auto componentCount = shadow->viewCount; + for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { + if (i < componentCount) { + auto cascade = &shadow->views[i]; + auto frustum = Volume::Frustum(cascade->frustumMatrix); + auto corners = frustum.GetCorners(); + auto texelSize = glm::max(abs(corners[0].x - corners[1].x), + abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; + shadowUniform.cascades[i].distance = cascade->farDistance; + shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * + cascade->viewMatrix); + shadowUniform.cascades[i].texelSize = texelSize; + } + else { + auto cascade = &shadow->views[componentCount - 1]; + shadowUniform.cascades[i].distance = cascade->farDistance; + } + } + } + rtrUniformBuffer.SetData(&uniforms, 0); + + // Screen space reflections { - static uint32_t frameCount = 0; + Graphics::Profiler::BeginQuery("SSR"); + + ivec2 groupCount = ivec2(rayRes.x / 8, rayRes.y / 8); + groupCount.x += ((groupCount.x * 8 == rayRes.x) ? 0 : 1); + groupCount.y += ((groupCount.y * 8 == rayRes.y) ? 0 : 1); + + auto ddgiEnabled = scene->irradianceVolume && scene->irradianceVolume->enable; + auto ddgiVisibility = ddgiEnabled && scene->irradianceVolume->visibility; + + ssrPipelineConfig.ManageMacro("USE_SHADOW_MAP", reflection->useShadowMap && shadow); + ssrPipelineConfig.ManageMacro("DDGI", reflection->ddgi && ddgiEnabled); + ssrPipelineConfig.ManageMacro("DDGI_VISIBILITY", reflection->ddgi && ddgiVisibility); + ssrPipelineConfig.ManageMacro("OPACITY_CHECK", reflection->opacityCheck); + + auto pipeline = PipelineManager::GetPipeline(ssrPipelineConfig); + commandList->BindPipeline(pipeline); + commandList->ImageMemoryBarrier(reflectionTexture->image, + VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT); + + commandList->BindImage(reflectionTexture->image, 3, 0); + + commandList->BindBuffer(rtrUniformBuffer.Get(), 3, 10); + + commandList->Dispatch(groupCount.x, groupCount.y, 1); + + Graphics::Profiler::EndQuery(); + } + + Graphics::Profiler::BeginQuery("Trace rays"); + + // Cast rays and calculate radiance + { ivec2 groupCount = ivec2(rayRes.x / 8, rayRes.y / 4); groupCount.x += ((groupCount.x * 8 == rayRes.x) ? 0 : 1); groupCount.y += ((groupCount.y * 4 == rayRes.y) ? 0 : 1); @@ -118,56 +198,12 @@ namespace Atlas { auto pipeline = PipelineManager::GetPipeline(rtrPipelineConfig); commandList->ImageMemoryBarrier(reflectionTexture->image, - VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT); + VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); helper.DispatchAndHit(scene, commandList, pipeline, ivec3(groupCount, 1), [=]() { commandList->BindImage(reflectionTexture->image, 3, 0); - - RTRUniforms uniforms; - uniforms.radianceLimit = reflection->radianceLimit; - uniforms.bias = reflection->bias; - uniforms.roughnessCutoff = reflection->roughnessCutoff; - uniforms.frameSeed = frameCount++; - uniforms.sampleCount = reflection->sampleCount; - uniforms.lightSampleCount = reflection->lightSampleCount; - uniforms.textureLevel = reflection->textureLevel; - uniforms.halfRes = target->GetReflectionResolution() == HALF_RES ? 1 : 0; - uniforms.resolution = rayRes; - - if (shadow && reflection->useShadowMap) { - auto& shadowUniform = uniforms.shadow; - shadowUniform.distance = !shadow->longRange ? shadow->distance : shadow->longRangeDistance; - shadowUniform.bias = shadow->bias; - shadowUniform.edgeSoftness = shadow->edgeSoftness; - shadowUniform.cascadeBlendDistance = shadow->cascadeBlendDistance; - shadowUniform.cascadeCount = shadow->viewCount; - shadowUniform.resolution = vec2(shadow->resolution); - - commandList->BindImage(shadow->maps->image, shadowSampler, 3, 6); - - auto componentCount = shadow->viewCount; - for (int32_t i = 0; i < MAX_SHADOW_VIEW_COUNT + 1; i++) { - if (i < componentCount) { - auto cascade = &shadow->views[i]; - auto frustum = Volume::Frustum(cascade->frustumMatrix); - auto corners = frustum.GetCorners(); - auto texelSize = glm::max(abs(corners[0].x - corners[1].x), - abs(corners[1].y - corners[3].y)) / (float)shadow->resolution; - shadowUniform.cascades[i].distance = cascade->farDistance; - shadowUniform.cascades[i].cascadeSpace = glm::transpose(cascade->projectionMatrix * - cascade->viewMatrix); - shadowUniform.cascades[i].texelSize = texelSize; - } - else { - auto cascade = &shadow->views[componentCount - 1]; - shadowUniform.cascades[i].distance = cascade->farDistance; - } - } - } - rtrUniformBuffer.SetData(&uniforms, 0); commandList->BindBuffer(rtrUniformBuffer.Get(), 3, 9); - }); commandList->ImageMemoryBarrier(reflectionTexture->image, diff --git a/src/engine/renderer/RTReflectionRenderer.h b/src/engine/renderer/RTReflectionRenderer.h index 8c0be4e0e..8b990f6fd 100644 --- a/src/engine/renderer/RTReflectionRenderer.h +++ b/src/engine/renderer/RTReflectionRenderer.h @@ -51,6 +51,7 @@ namespace Atlas { Texture::Texture2D scramblingRankingTexture; Texture::Texture2D sobolSequenceTexture; + PipelineConfig ssrPipelineConfig; PipelineConfig rtrPipelineConfig; PipelineConfig upsamplePipelineConfig; PipelineConfig temporalPipelineConfig; diff --git a/src/engine/renderer/helper/CommonStructures.h b/src/engine/renderer/helper/CommonStructures.h index 47dec739f..1e2da71de 100644 --- a/src/engine/renderer/helper/CommonStructures.h +++ b/src/engine/renderer/helper/CommonStructures.h @@ -132,6 +132,8 @@ namespace Atlas { float deltaTime; uint32_t frameCount; float mipLodBias; + float cameraNearPlane; + float cameraFarPlane; }; struct alignas(16) DDGICascade { From 2276a8c2eccf5605de71beeb52878bd2ec3e4c97 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 20 Oct 2024 12:22:43 +0200 Subject: [PATCH 56/66] Fixed a few things --- data/shader/deferred/direct.csh | 4 +- data/shader/deferred/lightCulling.csh | 5 - data/shader/postprocessing.fsh | 27 +++- data/shader/reflection/rtreflection.csh | 6 +- data/shader/reflection/ssr.csh | 5 +- data/shader/volumetric/lightCulling.csh | 3 - .../panels/GPUProfilerPanel.cpp | 68 +--------- libs/ImguiExtension/panels/GPUProfilerPanel.h | 15 +-- libs/ImguiExtension/panels/MaterialsPanel.h | 2 +- .../panels/PerformanceGraphPanel.cpp | 91 ++++++++++++++ .../panels/PerformanceGraphPanel.h | 32 +++++ .../panels/PostProcessingPanel.cpp | 5 +- .../panels/PostProcessingPanel.h | 4 +- src/editor/App.cpp | 118 ++++++++++-------- src/editor/App.h | 4 + src/editor/tools/ResourcePayloadHelper.h | 1 - src/editor/ui/panels/ScenePropertiesPanel.h | 9 +- .../components/LuaScriptComponentPanel.cpp | 1 + src/engine/Serializer.cpp | 6 +- src/engine/audio/AudioSerializer.cpp | 2 +- src/engine/lighting/LightingSerializer.cpp | 2 +- src/engine/mesh/MeshSerializer.cpp | 16 +-- src/engine/physics/PhysicsSerializer.cpp | 2 +- src/engine/postprocessing/Bloom.h | 1 + .../PostProcessingSerializer.cpp | 5 +- src/engine/renderer/PostProcessRenderer.cpp | 4 + src/engine/renderer/PostProcessRenderer.h | 4 + src/engine/renderer/target/RenderTarget.cpp | 2 +- src/engine/scene/SceneRenderState.cpp | 2 +- .../scene/components/ComponentSerializer.cpp | 6 +- src/tests/App.cpp | 17 ++- src/tests/App.h | 2 + src/tests/Main.cpp | 2 + 33 files changed, 285 insertions(+), 188 deletions(-) create mode 100644 libs/ImguiExtension/panels/PerformanceGraphPanel.cpp create mode 100644 libs/ImguiExtension/panels/PerformanceGraphPanel.h diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 085a294d6..a2bf87864 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -55,9 +55,10 @@ float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometr void LoadGroupSharedData() { int lightBucketOffset = GetLightBucketsGroupOffset(); + int groupSize = int(gl_WorkGroupSize.x * gl_WorkGroupSize.y); int localOffset = int(gl_LocalInvocationIndex); - for (int i = localOffset; i < pushConstants.lightBucketCount; i++) { + for (int i = localOffset; i < pushConstants.lightBucketCount; i += groupSize) { sharedLightBuckets[i] = uint(lightBuckets[lightBucketOffset + i]); } @@ -79,6 +80,7 @@ void main() { int lightCount = 0; vec3 direct = imageLoad(image, pixel).rgb; + if (depth < 1.0) { vec3 geometryNormal; // We don't have any light direction, that's why we use vec3(0.0, -1.0, 0.0) as a placeholder diff --git a/data/shader/deferred/lightCulling.csh b/data/shader/deferred/lightCulling.csh index ecfc44c64..24193c19a 100644 --- a/data/shader/deferred/lightCulling.csh +++ b/data/shader/deferred/lightCulling.csh @@ -103,11 +103,6 @@ void main() { else if (lightType == SPOT_LIGHT) { sphere = CalculateSphereFromSpotLight(light.location, light.direction, radius); - vec3 lightToPoint = viewPos - light.location.xyz; - bool inFront = dot(lightToPoint, light.direction.xyz) > 0.0; - - visible = inFront; - startBin = clamp(int((light.location.z + radius - depthMin) * invBinSize), 0, 31); endBin = clamp(int((light.location.z - radius - depthMin) * invBinSize), 0, 31); } diff --git a/data/shader/postprocessing.fsh b/data/shader/postprocessing.fsh index d2c278179..30fddb3ed 100644 --- a/data/shader/postprocessing.fsh +++ b/data/shader/postprocessing.fsh @@ -9,6 +9,10 @@ layout (location = 0) in vec2 positionVS; layout(set = 3, binding = 0) uniform sampler2D hdrTexture; layout(set = 3, binding = 1) uniform sampler2D bloomTexture; +#ifdef BLOOM_DIRT +layout(set = 3, binding = 2) uniform sampler2D bloomDirtTexture; +#endif + layout(set = 3, binding = 4) uniform UniformBuffer { float exposure; float paperWhiteLuminance; @@ -17,11 +21,15 @@ layout(set = 3, binding = 4) uniform UniformBuffer { float contrast; float filmGrainStrength; float bloomStrength; + float bloomDirtStrength; float aberrationStrength; float aberrationReversed; float vignetteOffset; float vignettePower; float vignetteStrength; + float padding0; + float padding1; + float padding2; vec4 vignetteColor; vec4 tintColor; } Uniforms; @@ -87,29 +95,38 @@ void main() { vec2 texCoord = 0.5 * positionVS + 0.5; vec3 color = vec3(0.0); + vec3 bloom = vec3(0.0); + #ifdef CHROMATIC_ABERRATION vec2 uvRedChannel = (positionVS - positionVS * 0.005 * Uniforms.aberrationStrength * Uniforms.aberrationReversed) * 0.5 + 0.5; vec2 uvGreenChannel = (positionVS - positionVS * 0.0025 * Uniforms.aberrationStrength) * 0.5 + 0.5; vec2 uvBlueChannel = (positionVS - positionVS * 0.005 * Uniforms.aberrationStrength - * (1.0f - Uniforms.aberrationReversed)) * 0.5 + 0.5; + * (1.0 - Uniforms.aberrationReversed)) * 0.5 + 0.5; color.r = textureLod(hdrTexture, uvRedChannel, 0.0).r; color.g = textureLod(hdrTexture, uvGreenChannel, 0.0).g; color.b = textureLod(hdrTexture, uvBlueChannel, 0.0).b; + #ifdef BLOOM - color.r += Uniforms.bloomStrength * textureLod(bloomTexture, uvRedChannel, 0.0).r; - color.g += Uniforms.bloomStrength * textureLod(bloomTexture, uvGreenChannel, 0.0).g; - color.b += Uniforms.bloomStrength * textureLod(bloomTexture, uvBlueChannel, 0.0).b; + bloom.r += Uniforms.bloomStrength * textureLod(bloomTexture, uvRedChannel, 0.0).r; + bloom.g += Uniforms.bloomStrength * textureLod(bloomTexture, uvGreenChannel, 0.0).g; + bloom.b += Uniforms.bloomStrength * textureLod(bloomTexture, uvBlueChannel, 0.0).b; #endif #else color = textureLod(hdrTexture, texCoord, 0.0).rgb; #ifdef BLOOM - color += Uniforms.bloomStrength * textureLod(bloomTexture, texCoord, 0.0).rgb; + bloom += Uniforms.bloomStrength * textureLod(bloomTexture, texCoord, 0.0).rgb; #endif #endif +#ifdef BLOOM_DIRT + bloom = Uniforms.bloomDirtStrength * textureLod(bloomDirtTexture, texCoord, 0.0).r * bloom + bloom; +#endif + + color += bloom; + color *= Uniforms.exposure; #ifdef FILM_GRAIN diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index 661ec9ec6..06613e990 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -72,6 +72,8 @@ void main() { vec2 texCoord = (vec2(pixel) + vec2(0.5)) / vec2(resolution); + vec4 reflection = imageLoad(rtrImage, pixel); + // No need, there is no offset right now int offsetIdx = texelFetch(offsetTexture, pixel, 0).r; ivec2 offset = offsets[offsetIdx]; @@ -93,9 +95,7 @@ void main() { Material material = UnpackMaterial(materialIdx); float roughness = texelFetch(roughnessMetallicAoTexture, pixel, 0).r; - material.roughness *= material.roughnessMap ? roughness : 1.0; - - vec4 reflection = imageLoad(rtrImage, pixel); + material.roughness *= material.roughnessMap ? roughness : 1.0; if (material.roughness <= 1.0 && depth < 1.0 && reflection.a == 0.0) { diff --git a/data/shader/reflection/ssr.csh b/data/shader/reflection/ssr.csh index 11d4bc83d..cc38a80d4 100644 --- a/data/shader/reflection/ssr.csh +++ b/data/shader/reflection/ssr.csh @@ -104,10 +104,9 @@ void main() { for (int i = 0; i < sampleCount; i++) { int sampleIdx = int(uniforms.frameSeed) * sampleCount + i; - vec3 blueNoiseVec = vec3( + vec2 blueNoiseVec = vec2( SampleBlueNoise(pixel, sampleIdx, 0, scramblingRankingTexture, sobolSequenceTexture), - SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture), - SampleBlueNoise(pixel, i, 2, scramblingRankingTexture, sobolSequenceTexture) + SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) ); float alpha = sqr(material.roughness); diff --git a/data/shader/volumetric/lightCulling.csh b/data/shader/volumetric/lightCulling.csh index f5519279f..7ad475675 100644 --- a/data/shader/volumetric/lightCulling.csh +++ b/data/shader/volumetric/lightCulling.csh @@ -94,9 +94,6 @@ void main() { } else if (lightType == SPOT_LIGHT) { sphere = CalculateSphereFromSpotLight(light.location, light.direction, radius); - - vec3 lightToPoint = viewPos - light.location.xyz; - visible = dot(lightToPoint, light.direction.xyz) > 0.0; } visible = visible && SphereAABBIntersection(sphere, frustumAABB); diff --git a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp index eb49fbdcc..87818084f 100644 --- a/libs/ImguiExtension/panels/GPUProfilerPanel.cpp +++ b/libs/ImguiExtension/panels/GPUProfilerPanel.cpp @@ -14,10 +14,8 @@ namespace Atlas::ImguiExtension { ImGui::Checkbox("Show graph##Profiler", &showGraph); Graphics::Profiler::enable = enabled; - UpdateGraphData(); - if (showGraph) - RenderGraph(); + perfGraphPanel.Render(); else RenderTable(); @@ -91,68 +89,4 @@ namespace Atlas::ImguiExtension { } - void GPUProfilerPanel::RenderGraph() { - - auto dataSize = int32_t(frameTimes.size()); - - std::vector localFrameTimes(frameTimes.begin(), frameTimes.end()); - std::vector localGpuTimes(gpuTimes.begin(), gpuTimes.end()); - - auto availSize = ImGui::GetContentRegionAvail(); - - auto frameColor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); - ImPlot::PushStyleColor(ImPlotCol_PlotBorder, frameColor); - ImPlot::PushStyleColor(ImPlotCol_FrameBg, frameColor); - ImPlot::PushStyleVar(ImPlotStyleVar_PlotBorderSize, 0.0f); - - if (ImPlot::BeginPlot("Performance graph", availSize)) { - ImPlot::SetupAxes("Frames", "Time (ms)"); - ImPlot::SetupAxesLimits(0, timeWindowSize, 0, std::min(200.0f, maxFrameTime), ImPlotCond_Always); - ImPlot::SetupLegend(ImPlotLocation_SouthWest); - - ImPlot::PlotLine("Frame time", localFrameTimes.data(), dataSize); - ImPlot::PlotLine("GPU time", localGpuTimes.data(), dataSize); - - ImPlot::EndPlot(); - } - - ImPlot::PopStyleVar(); - ImPlot::PopStyleColor(); - ImPlot::PopStyleColor(); - - } - - void GPUProfilerPanel::UpdateGraphData() { - - auto gpuProfilerData = Graphics::Profiler::GetQueries(Graphics::Profiler::OrderBy::MAX_TIME); - - double slowestTime = 0.0; - for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { - const auto& threadData = gpuProfilerData[i]; - double threadTime = 0.0; - for (const auto& query : threadData.queries) { - threadTime += query.timer.elapsedTime; - } - if (threadTime > slowestTime) { - slowestTime = threadTime; - } - } - - frameTimes.push_back(Clock::GetDelta() * 1000.0f); - gpuTimes.push_back(float(slowestTime / 1000000.0)); - - if (int32_t(frameTimes.size()) > timeWindowSize) { - frameTimes.pop_front(); - gpuTimes.pop_front(); - } - - maxFrameTime = 0.0f; - maxGpuTime = 0.0f; - for (int32_t i = 0; i < timeWindowSize && i < int32_t(frameTimes.size()); i++) { - maxFrameTime = std::max(frameTimes[i], maxFrameTime); - maxGpuTime = std::max(gpuTimes[i], maxGpuTime); - } - - } - } \ No newline at end of file diff --git a/libs/ImguiExtension/panels/GPUProfilerPanel.h b/libs/ImguiExtension/panels/GPUProfilerPanel.h index 9e23e9941..fcc28b2d2 100644 --- a/libs/ImguiExtension/panels/GPUProfilerPanel.h +++ b/libs/ImguiExtension/panels/GPUProfilerPanel.h @@ -1,8 +1,7 @@ #pragma once #include "Panel.h" - -#include "lighting/IrradianceVolume.h" +#include "PerformanceGraphPanel.h" #include @@ -17,19 +16,9 @@ namespace Atlas::ImguiExtension { void RenderTable(); - void RenderGraph(); - - void UpdateGraphData(); - bool showGraph = false; - int32_t timeWindowSize = 1024; - - float maxFrameTime = 0.0f; - float maxGpuTime = 0.0f; - - std::deque frameTimes; - std::deque gpuTimes; + PerformanceGraphPanel perfGraphPanel; }; diff --git a/libs/ImguiExtension/panels/MaterialsPanel.h b/libs/ImguiExtension/panels/MaterialsPanel.h index 046f2baf5..f6c259175 100644 --- a/libs/ImguiExtension/panels/MaterialsPanel.h +++ b/libs/ImguiExtension/panels/MaterialsPanel.h @@ -11,7 +11,7 @@ namespace Atlas::ImguiExtension { class MaterialsPanel : public Panel { - using MaterialSelector = std::optional(ResourceHandle)>>; + using MaterialSelector = std::optional(ResourceHandle)>>; public: MaterialsPanel() : Panel("Materials properties") {} diff --git a/libs/ImguiExtension/panels/PerformanceGraphPanel.cpp b/libs/ImguiExtension/panels/PerformanceGraphPanel.cpp new file mode 100644 index 000000000..9b7f19e7f --- /dev/null +++ b/libs/ImguiExtension/panels/PerformanceGraphPanel.cpp @@ -0,0 +1,91 @@ +#include "PerformanceGraphPanel.h" + +#include "graphics/Profiler.h" +#include "Clock.h" + +namespace Atlas::ImguiExtension { + + void PerformanceGraphPanel::Render(ivec2 size, float alpha) { + + ImGui::PushID(GetNameID()); + + UpdateGraphData(); + + RenderGraph(size, alpha); + + ImGui::PopID(); + + } + + void PerformanceGraphPanel::RenderGraph(ivec2 size, float alpha) { + + auto dataSize = int32_t(frameTimes.size()); + + std::vector localFrameTimes(frameTimes.begin(), frameTimes.end()); + std::vector localGpuTimes(gpuTimes.begin(), gpuTimes.end()); + + auto availSize = ImGui::GetContentRegionAvail(); + if (size != ivec2(0)) + availSize = ImVec2(float(size.x), float(size.y)); + + auto frameColor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); + if (alpha >= 0.0f) + frameColor.w = alpha; + + ImPlot::PushStyleColor(ImPlotCol_PlotBorder, frameColor); + ImPlot::PushStyleColor(ImPlotCol_FrameBg, frameColor); + ImPlot::PushStyleColor(ImPlotCol_PlotBg, frameColor); + ImPlot::PushStyleColor(ImPlotCol_Fill, frameColor); + ImPlot::PushStyleVar(ImPlotStyleVar_PlotBorderSize, 0.0f); + + if (ImPlot::BeginPlot("Performance graph", availSize)) { + ImPlot::SetupAxes("Frames", "Time (ms)"); + ImPlot::SetupAxesLimits(0, timeWindowSize, 0, std::min(200.0f, maxFrameTime), ImPlotCond_Always); + ImPlot::SetupLegend(ImPlotLocation_SouthWest); + + ImPlot::PlotLine("Frame time", localFrameTimes.data(), dataSize); + ImPlot::PlotLine("GPU time", localGpuTimes.data(), dataSize); + + ImPlot::EndPlot(); + } + + ImPlot::PopStyleVar(); + ImPlot::PopStyleColor(); + ImPlot::PopStyleColor(); + + } + + void PerformanceGraphPanel::UpdateGraphData() { + + auto gpuProfilerData = Graphics::Profiler::GetQueries(Graphics::Profiler::OrderBy::MAX_TIME); + + double slowestTime = 0.0; + for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { + const auto& threadData = gpuProfilerData[i]; + double threadTime = 0.0; + for (const auto& query : threadData.queries) { + threadTime += query.timer.elapsedTime; + } + if (threadTime > slowestTime) { + slowestTime = threadTime; + } + } + + frameTimes.push_back(Clock::GetDelta() * 1000.0f); + gpuTimes.push_back(float(slowestTime / 1000000.0)); + + if (int32_t(frameTimes.size()) > timeWindowSize) { + frameTimes.pop_front(); + gpuTimes.pop_front(); + } + + maxFrameTime = 0.0f; + maxGpuTime = 0.0f; + for (int32_t i = 0; i < timeWindowSize && i < int32_t(frameTimes.size()); i++) { + maxFrameTime = std::max(frameTimes[i], maxFrameTime); + maxGpuTime = std::max(gpuTimes[i], maxGpuTime); + } + + } + +} \ No newline at end of file diff --git a/libs/ImguiExtension/panels/PerformanceGraphPanel.h b/libs/ImguiExtension/panels/PerformanceGraphPanel.h new file mode 100644 index 000000000..91d3e01ac --- /dev/null +++ b/libs/ImguiExtension/panels/PerformanceGraphPanel.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Panel.h" + +#include + +namespace Atlas::ImguiExtension { + + class PerformanceGraphPanel : public Panel { + + public: + PerformanceGraphPanel() : Panel("GPU profiler hierarchy") {} + + void Render(ivec2 size = ivec2(0), float alpha = -1.0f); + + void RenderGraph(ivec2 size, float alpha); + + void UpdateGraphData(); + + bool showGraph = false; + + int32_t timeWindowSize = 1024; + + float maxFrameTime = 0.0f; + float maxGpuTime = 0.0f; + + std::deque frameTimes; + std::deque gpuTimes; + + }; + +} \ No newline at end of file diff --git a/libs/ImguiExtension/panels/PostProcessingPanel.cpp b/libs/ImguiExtension/panels/PostProcessingPanel.cpp index 25094a544..a1b0dedf1 100644 --- a/libs/ImguiExtension/panels/PostProcessingPanel.cpp +++ b/libs/ImguiExtension/panels/PostProcessingPanel.cpp @@ -2,7 +2,7 @@ namespace Atlas::ImguiExtension { - void PostProcessingPanel::Render(PostProcessing::PostProcessing &postProcessing) { + void PostProcessingPanel::Render(PostProcessing::PostProcessing &postProcessing, TextureSelector textureSelector) { ImGui::PushID(GetNameID()); @@ -42,7 +42,10 @@ namespace Atlas::ImguiExtension { ImGui::Separator(); ImGui::Text("Bloom"); ImGui::Checkbox("Enable##Bloom", &postProcessing.bloom.enable); + if (textureSelector.has_value()) + postProcessing.bloom.dirtMap = textureSelector.value()(postProcessing.bloom.dirtMap); ImGui::DragFloat("Strength##Bloom", &postProcessing.bloom.strength, 0.001f, 0.0f, 1.0f); + ImGui::DragFloat("Dirt strength##Bloom", &postProcessing.bloom.dirtStrength, 0.01f, 0.0f, 10.0f); ImGui::DragFloat("Threshold##Bloom", &postProcessing.bloom.threshold, 0.01f, 0.0f, 10.0f); ImGui::DragFloat("Filter size##Bloom", &postProcessing.bloom.filterSize, 0.001f, 0.0f, 1.0f); auto mipLevels = int32_t(postProcessing.bloom.mipLevels); diff --git a/libs/ImguiExtension/panels/PostProcessingPanel.h b/libs/ImguiExtension/panels/PostProcessingPanel.h index 72742a8be..1da21855a 100644 --- a/libs/ImguiExtension/panels/PostProcessingPanel.h +++ b/libs/ImguiExtension/panels/PostProcessingPanel.h @@ -8,10 +8,12 @@ namespace Atlas::ImguiExtension { class PostProcessingPanel : public Panel { + using TextureSelector = std::optional(ResourceHandle)>>; + public: PostProcessingPanel() : Panel("Post process properties") {} - void Render(PostProcessing::PostProcessing& postProcessing); + void Render(PostProcessing::PostProcessing& postProcessing, TextureSelector textureSelector = {}); }; diff --git a/src/editor/App.cpp b/src/editor/App.cpp index e608b7a0c..5518beff0 100644 --- a/src/editor/App.cpp +++ b/src/editor/App.cpp @@ -29,8 +29,8 @@ namespace Atlas::Editor { ImGui::CreateContext(); ImPlot::CreateContext(); - ImGuiIO &io = ImGui::GetIO(); - (void) io; + ImGuiIO& io = ImGui::GetIO(); + (void)io; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; SetDefaultWindowResolution(); @@ -96,7 +96,7 @@ namespace Atlas::Editor { void App::Update(float deltaTime) { - const ImGuiIO &io = ImGui::GetIO(); + const ImGuiIO& io = ImGui::GetIO(); ContentDiscovery::Update(); Singletons::imguiWrapper->Update(&window, deltaTime); @@ -206,14 +206,14 @@ namespace Atlas::Editor { sceneWindow->isActiveWindow = true; else sceneWindow->isActiveWindow = false; - + // Need to reset this each frame in order to reenable selection sceneWindow->lockSelection = false; sceneWindow->Update(deltaTime); } ImGuizmo::Enable(activeSceneWindow->needGuizmoEnabled); - + } void App::Render(float deltaTime) { @@ -239,7 +239,7 @@ namespace Atlas::Editor { // ImGui::ShowDemoWindow(); // ImPlot::ShowDemoWindow(); - ImGuiViewport *viewport = ImGui::GetMainViewport(); + ImGuiViewport* viewport = ImGui::GetMainViewport(); bool playingMaximized = false; auto activeSceneWindow = sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]; @@ -345,60 +345,70 @@ namespace Atlas::Editor { ImGui::End(); } else { - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus | - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoMove; + RenderSceneMaximized(); + } - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + Notifications::Display(); - ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); - ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); - ImGui::Begin("RenderWindow", nullptr, window_flags); - - auto renderArea = ImGui::GetContentRegionAvail(); - activeSceneWindow->viewportPanel.RenderScene(activeSceneWindow->scene.Get(), - ivec2(0), ivec2(int32_t(renderArea.x), int32_t(renderArea.y)), true); - auto set = Singletons::imguiWrapper->GetTextureDescriptorSet(&activeSceneWindow->viewportPanel.viewportTexture); - ImGui::Image(set, renderArea); - - if (activeSceneWindow->perfOverlayMaximized) { - ImGui::SetCursorPos(ImVec2(0.0f, 0.0f)); - auto gpuProfilerData = Graphics::Profiler::GetQueriesAverage(32, Graphics::Profiler::OrderBy::MAX_TIME); - - std::string perfString; - double slowestTime = 0.0; - for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { - const auto& threadData = gpuProfilerData[i]; - double threadTime = 0.0; - for (const auto& query : threadData.queries) { - threadTime += query.timer.elapsedTime; - } - if (threadTime > slowestTime) { - slowestTime = threadTime; - } - } + ImGui::Render(); + Singletons::imguiWrapper->Render(true); + + } - auto target = Singletons::renderTarget; + void App::RenderSceneMaximized() { - ImGui::SetWindowFontScale(1.5f); - ImGui::Text("Frame time: %.3fms, GPU time: %.3f", Clock::GetAverage() * 1000.0f, float(slowestTime / 1000000.0)); - ImGui::Text("Resolution %dx%d upscaled from %dx%d", target->GetWidth(), target->GetHeight(), target->GetScaledWidth(), target->GetScaledHeight()); - ImGui::SetWindowFontScale(1.0f); + auto activeSceneWindow = sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]; + + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus | + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove; + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); + ImGui::Begin("RenderWindow", nullptr, window_flags); + + auto renderArea = ImGui::GetContentRegionAvail(); + activeSceneWindow->viewportPanel.RenderScene(activeSceneWindow->scene.Get(), + ivec2(0), ivec2(int32_t(renderArea.x), int32_t(renderArea.y)), true); + auto set = Singletons::imguiWrapper->GetTextureDescriptorSet(&activeSceneWindow->viewportPanel.viewportTexture); + ImGui::Image(set, renderArea); + + if (activeSceneWindow->perfOverlayMaximized) { + ImGui::SetCursorPos(ImVec2(0.0f, 0.0f)); + auto gpuProfilerData = Graphics::Profiler::GetQueriesAverage(32, Graphics::Profiler::OrderBy::MAX_TIME); + + std::string perfString; + double slowestTime = 0.0; + for (int32_t i = 0; i < int32_t(gpuProfilerData.size()); i++) { + const auto& threadData = gpuProfilerData[i]; + double threadTime = 0.0; + for (const auto& query : threadData.queries) { + threadTime += query.timer.elapsedTime; + } + if (threadTime > slowestTime) { + slowestTime = threadTime; + } } - ImGui::PopStyleVar(); - ImGui::PopStyleVar(); - ImGui::PopStyleVar(); + auto target = Singletons::renderTarget; - ImGui::End(); + ImGui::SetWindowFontScale(1.5f); + ImGui::Text("Frame time: %.3fms, GPU time: %.3fms", Clock::GetAverage() * 1000.0f, float(slowestTime / 1000000.0)); + ImGui::Text("Resolution %dx%d upscaled from %dx%d", target->GetWidth(), target->GetHeight(), target->GetScaledWidth(), target->GetScaledHeight()); + ImGui::SetWindowFontScale(1.0f); + + performanceGraphPanel.Render(ivec2(400, 300), 0.05f); } - Notifications::Display(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); - ImGui::Render(); - Singletons::imguiWrapper->Render(true); + ImGui::End(); } @@ -448,9 +458,9 @@ namespace Atlas::Editor { ResourceManager::Subscribe(ResourceTopic::ResourceCreate, [&](Ref>& scene) { - waitToLoadScenes.push_back(ResourceHandle(scene)); - Singletons::config->openedScenes.push_back(ResourceHandle(scene)); - }); + waitToLoadScenes.push_back(ResourceHandle(scene)); + Singletons::config->openedScenes.push_back(ResourceHandle(scene)); + }); // Also kind of a resource event Events::EventManager::DropEventDelegate.Subscribe([&](Events::DropEvent event) { @@ -459,7 +469,7 @@ namespace Atlas::Editor { FileSystemHelper::Copy(event.file, destinationDirectory); } - }); + }); } diff --git a/src/editor/App.h b/src/editor/App.h index 295414b9d..26915705c 100644 --- a/src/editor/App.h +++ b/src/editor/App.h @@ -34,6 +34,8 @@ namespace Atlas::Editor { virtual void Render(float deltaTime) final; private: + void RenderSceneMaximized(); + void SetupMainDockspace(ImGuiID dsID); void SubscribeToResourceEvents(); @@ -48,6 +50,8 @@ namespace Atlas::Editor { UI::ProfilerWindow profilerWindow = UI::ProfilerWindow(false); UI::GeometryBrushWindow geometryBrushWindow = UI::GeometryBrushWindow(false); + ImguiExtension::PerformanceGraphPanel performanceGraphPanel; + std::vector> waitToLoadScenes; std::vector> sceneWindows; diff --git a/src/editor/tools/ResourcePayloadHelper.h b/src/editor/tools/ResourcePayloadHelper.h index 7e2f9aa5b..ac8a5686d 100644 --- a/src/editor/tools/ResourcePayloadHelper.h +++ b/src/editor/tools/ResourcePayloadHelper.h @@ -28,7 +28,6 @@ namespace Atlas::Editor { } if (compatible && ImGui::AcceptDragDropPayload("ContentBrowserResource")) { - Log::Warning("Valid file"); handle = FileImporter::ImportFile(resourcePath); } diff --git a/src/editor/ui/panels/ScenePropertiesPanel.h b/src/editor/ui/panels/ScenePropertiesPanel.h index 76deec600..e332c71fb 100644 --- a/src/editor/ui/panels/ScenePropertiesPanel.h +++ b/src/editor/ui/panels/ScenePropertiesPanel.h @@ -75,13 +75,19 @@ namespace Atlas::Editor::UI { } else if constexpr (std::is_same_v) { RenderHeading("Post processing"); - postProcessingPanel.Render(t); + postProcessingPanel.Render(t, + [&](ResourceHandle handle) { + return textureSelectionPanel.Render(handle); + }); } else if constexpr (std::is_same_v>) { RenderHeading("Scene statistics"); sceneStatisticsPanel.Render(t); } + cubemapSelectionPanel.Reset(); + textureSelectionPanel.Reset(); + ImGui::End(); } @@ -103,6 +109,7 @@ namespace Atlas::Editor::UI { SceneStatisticsPanel sceneStatisticsPanel; ResourceSelectionPanel cubemapSelectionPanel; + ResourceSelectionPanel textureSelectionPanel; ImguiExtension::FogPanel fogPanel; ImguiExtension::VolumetricCloudsPanel volumetricCloudsPanel; diff --git a/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp b/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp index 9e9f3f87a..c16c5630f 100644 --- a/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp +++ b/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp @@ -59,6 +59,7 @@ namespace Atlas::Editor::UI ImGui::DragFloat3(name.c_str(), glm::value_ptr(property.vec3Value)); break; case LuaScriptComponent::PropertyType::Undefined: + default: break; } } diff --git a/src/engine/Serializer.cpp b/src/engine/Serializer.cpp index 83bdbdcdb..a9e179f86 100644 --- a/src/engine/Serializer.cpp +++ b/src/engine/Serializer.cpp @@ -153,7 +153,7 @@ namespace Atlas { [&](JobData& data) { auto& mesh = meshes[data.idx]; - if (!mesh.IsLoaded()) return; + if (!mesh.IsLoaded() || mesh.IsGenerated()) return; Loader::MeshLoader::SaveMesh(mesh.Get(), mesh.GetResource()->path, true); }); @@ -164,7 +164,7 @@ namespace Atlas { for (const auto& mesh : meshes) { if (!mesh.IsLoaded()) continue; - if (!multithreaded) + if (!multithreaded && !mesh.IsGenerated()) Loader::MeshLoader::SaveMesh(mesh.Get(), mesh.GetResource()->path, true); for (const auto& material : mesh->data.materials) @@ -172,7 +172,7 @@ namespace Atlas { } for (const auto& [_, material] : materials) { - if (!material.IsLoaded()) continue; + if (!material.IsLoaded() || material.IsGenerated()) continue; Loader::MaterialLoader::SaveMaterial(material.Get(), material.GetResource()->path); } diff --git a/src/engine/audio/AudioSerializer.cpp b/src/engine/audio/AudioSerializer.cpp index 00c28272e..f291b3ecd 100644 --- a/src/engine/audio/AudioSerializer.cpp +++ b/src/engine/audio/AudioSerializer.cpp @@ -11,7 +11,7 @@ namespace Atlas::Audio { {"loop", p.loop}, }; - if (p.data.IsValid()) + if (p.data.IsValid() && !p.data.IsGenerated()) j["resourcePath"] = p.data.GetResource()->path; } diff --git a/src/engine/lighting/LightingSerializer.cpp b/src/engine/lighting/LightingSerializer.cpp index c165d38b1..2a8f88ef4 100644 --- a/src/engine/lighting/LightingSerializer.cpp +++ b/src/engine/lighting/LightingSerializer.cpp @@ -31,7 +31,7 @@ namespace Atlas::Lighting { {"position", p.GetPosition()} }; - if (p.cubemap.IsValid()) { + if (p.cubemap.IsValid() && !p.cubemap.IsGenerated()) { j["cubemapPath"] = p.cubemap.GetResource()->path; } } diff --git a/src/engine/mesh/MeshSerializer.cpp b/src/engine/mesh/MeshSerializer.cpp index 548407575..9089c7b22 100644 --- a/src/engine/mesh/MeshSerializer.cpp +++ b/src/engine/mesh/MeshSerializer.cpp @@ -198,21 +198,21 @@ namespace Atlas { {"uvAnimation", p.uvAnimation}, }; - if (p.baseColorMap.IsValid()) + if (p.baseColorMap.IsValid() && !p.baseColorMap.IsGenerated()) j["baseColorMapPath"] = p.baseColorMap.GetResource()->path; - if (p.opacityMap.IsValid()) + if (p.opacityMap.IsValid() && !p.opacityMap.IsGenerated()) j["opacityMapPath"] = p.opacityMap.GetResource()->path; - if (p.normalMap.IsValid()) + if (p.normalMap.IsValid() && !p.normalMap.IsGenerated()) j["normalMapPath"] = p.normalMap.GetResource()->path; - if (p.roughnessMap.IsValid()) + if (p.roughnessMap.IsValid() && !p.roughnessMap.IsGenerated()) j["roughnessMapPath"] = p.roughnessMap.GetResource()->path; - if (p.metalnessMap.IsValid()) + if (p.metalnessMap.IsValid() && !p.metalnessMap.IsGenerated()) j["metalnessMapPath"] = p.metalnessMap.GetResource()->path; - if (p.aoMap.IsValid()) + if (p.aoMap.IsValid() && !p.aoMap.IsGenerated()) j["aoMapPath"] = p.aoMap.GetResource()->path; - if (p.displacementMap.IsValid()) + if (p.displacementMap.IsValid() && !p.displacementMap.IsGenerated()) j["displacementMapPath"] = p.displacementMap.GetResource()->path; - if (p.emissiveMap.IsValid()) + if (p.emissiveMap.IsValid() && !p.emissiveMap.IsGenerated()) j["emissiveMapPath"] = p.emissiveMap.GetResource()->path; } diff --git a/src/engine/physics/PhysicsSerializer.cpp b/src/engine/physics/PhysicsSerializer.cpp index 742fc0cc6..b2234fc6c 100644 --- a/src/engine/physics/PhysicsSerializer.cpp +++ b/src/engine/physics/PhysicsSerializer.cpp @@ -13,7 +13,7 @@ namespace Atlas::Physics { {"scale", p.scale}, }; - if (p.mesh.IsValid()) { + if (p.mesh.IsValid() && !p.mesh.IsGenerated()) { j["resourcePath"] = p.mesh.GetResource()->path; } } diff --git a/src/engine/postprocessing/Bloom.h b/src/engine/postprocessing/Bloom.h index 363e19633..49638215a 100644 --- a/src/engine/postprocessing/Bloom.h +++ b/src/engine/postprocessing/Bloom.h @@ -14,6 +14,7 @@ namespace Atlas::PostProcessing { bool enable = true; float strength = 0.01f; + float dirtStrength = 2.0f; float threshold = 1.0f; float filterSize = 0.02f; diff --git a/src/engine/postprocessing/PostProcessingSerializer.cpp b/src/engine/postprocessing/PostProcessingSerializer.cpp index 365e6f1ae..afd6110c1 100644 --- a/src/engine/postprocessing/PostProcessingSerializer.cpp +++ b/src/engine/postprocessing/PostProcessingSerializer.cpp @@ -78,10 +78,11 @@ namespace Atlas::PostProcessing { {"filterSize", p.filterSize}, {"mipLevels", p.mipLevels}, {"strength", p.strength}, + {"dirtStrength", p.dirtStrength}, {"threshold", p.threshold}, }; - if (p.dirtMap.IsValid()) + if (p.dirtMap.IsValid() && !p.dirtMap.IsGenerated()) j["dirtMap"] = p.dirtMap.GetResource()->path; } @@ -93,6 +94,8 @@ namespace Atlas::PostProcessing { j.at("strength").get_to(p.strength); j.at("threshold").get_to(p.threshold); + try_get_json(j, "dirtStrength", p.dirtStrength); + if (j.contains("dirtMap")) p.dirtMap = ResourceManager::GetOrLoadResource(j["dirtMap"], false, Texture::Wrapping::Repeat, Texture::Filtering::Linear, 0); diff --git a/src/engine/renderer/PostProcessRenderer.cpp b/src/engine/renderer/PostProcessRenderer.cpp index a66f4b175..1742090e6 100644 --- a/src/engine/renderer/PostProcessRenderer.cpp +++ b/src/engine/renderer/PostProcessRenderer.cpp @@ -151,12 +151,15 @@ namespace Atlas { pipelineConfig.ManageMacro("CHROMATIC_ABERRATION", postProcessing.chromaticAberration.enable); pipelineConfig.ManageMacro("FILM_GRAIN", postProcessing.filmGrain.enable); pipelineConfig.ManageMacro("BLOOM", postProcessing.bloom.enable); + pipelineConfig.ManageMacro("BLOOM_DIRT", postProcessing.bloom.enable && postProcessing.bloom.dirtMap.IsLoaded()); auto pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); if (bloom.enable) { target->bloomTexture.Bind(commandList, 3, 1); + if (bloom.dirtMap.IsLoaded()) + bloom.dirtMap->Bind(commandList, 3, 2); } SetUniforms(camera, scene); @@ -360,6 +363,7 @@ namespace Atlas { if (bloom.enable) { uniforms.bloomStrength = bloom.strength; + uniforms.bloomDirtStrength = bloom.dirtStrength; } uniformBuffer->SetData(&uniforms, 0, sizeof(Uniforms)); diff --git a/src/engine/renderer/PostProcessRenderer.h b/src/engine/renderer/PostProcessRenderer.h index 87ae3014c..f4be22195 100644 --- a/src/engine/renderer/PostProcessRenderer.h +++ b/src/engine/renderer/PostProcessRenderer.h @@ -29,11 +29,15 @@ namespace Atlas { float contrast; float filmGrainStrength; float bloomStrength; + float bloomDirtStrength; float aberrationStrength; float aberrationReversed; float vignetteOffset; float vignettePower; float vignetteStrength; + float padding0; + float padding1; + float padding2; vec4 vignetteColor; vec4 tintColor; }; diff --git a/src/engine/renderer/target/RenderTarget.cpp b/src/engine/renderer/target/RenderTarget.cpp index 1e10f5f7d..a3c1e1e5d 100644 --- a/src/engine/renderer/target/RenderTarget.cpp +++ b/src/engine/renderer/target/RenderTarget.cpp @@ -24,7 +24,7 @@ namespace Atlas::Renderer { Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); swapHistoryTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R16G16B16A16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); - lightingTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R16G16B16A16_SFLOAT, + lightingTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_A2B10G10R10_UNORM_PACK32, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); reactiveMaskTexture = Texture::Texture2D(scaledWidth, scaledWidth, VK_FORMAT_R8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index f217d43b2..4fc24ab2d 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -198,7 +198,7 @@ namespace Atlas::Scene { if (!mesh.IsLoaded()) continue; // Not all meshes might have a bvh and not all blases will be built in frame, so skip them if they are not ready - if (!mesh->IsBVHBuilt() || mesh->IsBVHBuilt() && !mesh->blas->isDynamic && !mesh->blas->isBuilt) + if (!mesh->IsBVHBuilt() || mesh->IsBVHBuilt() && mesh->blas && !mesh->blas->isDynamic && !mesh->blas->isBuilt) continue; meshIdToBindlessIdx[mesh.GetID()] = bufferIdx++; diff --git a/src/engine/scene/components/ComponentSerializer.cpp b/src/engine/scene/components/ComponentSerializer.cpp index 866c5e5a5..32019e84c 100644 --- a/src/engine/scene/components/ComponentSerializer.cpp +++ b/src/engine/scene/components/ComponentSerializer.cpp @@ -185,7 +185,7 @@ namespace Atlas::Scene::Components { {"dontCull", p.dontCull} }; - if (p.mesh.IsValid()) + if (p.mesh.IsValid() && !p.mesh.IsGenerated()) j["resourcePath"] = p.mesh.GetResource()->path; } @@ -243,7 +243,7 @@ namespace Atlas::Scene::Components { {"textScale", p.textScale}, }; - if (p.font.IsValid()) + if (p.font.IsValid() && !p.font.IsGenerated()) j["resourcePath"] = p.font.GetResource()->path; } @@ -321,7 +321,7 @@ namespace Atlas::Scene::Components { void to_json(json &j, const LuaScriptComponent &p) { j = json{}; - if (p.script.IsValid()) + if (p.script.IsValid() && !p.script.IsGenerated()) j["resourcePath"] = p.script.GetResource()->path; j["permanentExecution"] = p.permanentExecution; diff --git a/src/tests/App.cpp b/src/tests/App.cpp index 7fb4c4136..054678ac0 100644 --- a/src/tests/App.cpp +++ b/src/tests/App.cpp @@ -17,7 +17,7 @@ void App::LoadContent(AppConfiguration config) { this->config = config; // Use lower resolution, we care only about correctness - renderTarget = Atlas::CreateRef(320, 240); + renderTarget = Atlas::CreateRef(240, 160); viewport = Atlas::CreateRef(0, 0, renderTarget->GetWidth(), renderTarget->GetHeight()); @@ -82,6 +82,10 @@ void App::LoadContent(AppConfiguration config) { scene->irradianceVolume->strength = 1.5f; } + if (config.rtgi) { + scene->rtgi = Atlas::CreateRef(); + } + if (config.ssgi) { scene->ssgi = Atlas::CreateRef(); } @@ -92,6 +96,9 @@ void App::LoadContent(AppConfiguration config) { scene->fog->density = 0.0068f; scene->fog->heightFalloff = 0.0284f; scene->fog->height = 0.0f; + + scene->fog->rayMarching = config.volumetric; + scene->fog->localLights = config.localVolumetric; } if (config.clouds) { @@ -116,14 +123,6 @@ void App::LoadContent(AppConfiguration config) { scene->sss = Atlas::CreateRef(); } - if (config.fog) { - if (config.volumetric) { - scene->fog->rayMarching = true; - } else { - scene->fog->rayMarching = false; - } - } - if (config.ocean) { scene->ocean = Atlas::CreateRef(9, 4096.0f, glm::vec3(0.0f, 5.0f, 0.0f), 128, 86); diff --git a/src/tests/App.h b/src/tests/App.h index 727c2bae5..c9be26f08 100644 --- a/src/tests/App.h +++ b/src/tests/App.h @@ -22,8 +22,10 @@ struct AppConfiguration { bool sharpen = false; bool ssgi = true; bool ddgi = true; + bool rtgi = true; bool reflection = true; bool volumetric = true; + bool localVolumetric = true; bool ocean = true; bool light = true; bool fsr = true; diff --git a/src/tests/Main.cpp b/src/tests/Main.cpp index 1a1bb892c..3e03fe87c 100644 --- a/src/tests/Main.cpp +++ b/src/tests/Main.cpp @@ -96,9 +96,11 @@ auto testingValues = testing::Values( AppConfiguration { .ocean = false }, #ifdef AE_BINDLESS AppConfiguration { .ddgi = false }, + AppConfiguration { .rtgi = false }, AppConfiguration { .reflection = false }, #endif AppConfiguration { .volumetric = false }, + AppConfiguration { .localVolumetric = false }, AppConfiguration { .sharpen = false }, AppConfiguration { .light = false }, AppConfiguration { .fsr = false }, From ae495dc19108adf2a05f4f4a2cd55c1485c25c9b Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 24 Oct 2024 09:06:16 +0200 Subject: [PATCH 57/66] Some important fixes --- data/shader/ddgi/ddgi.hsh | 5 ++- data/shader/upsampleSpatial.csh | 2 +- data/shader/volumetric/lightCulling.csh | 6 +-- data/shader/volumetric/volumetric.csh | 4 +- src/engine/jobsystem/Job.h | 9 +++++ src/engine/jobsystem/JobSystem.cpp | 38 ++++++++++++++++--- src/engine/lighting/Reflection.h | 1 + src/engine/renderer/IndirectLightRenderer.cpp | 2 +- src/engine/renderer/RTReflectionRenderer.cpp | 10 ++--- src/engine/renderer/ShadowRenderer.cpp | 18 ++++----- src/engine/renderer/VolumetricRenderer.cpp | 8 ++-- src/engine/renderer/target/RenderTarget.cpp | 2 +- 12 files changed, 68 insertions(+), 37 deletions(-) diff --git a/data/shader/ddgi/ddgi.hsh b/data/shader/ddgi/ddgi.hsh index 0c0d46dc9..703860a52 100644 --- a/data/shader/ddgi/ddgi.hsh +++ b/data/shader/ddgi/ddgi.hsh @@ -10,7 +10,8 @@ #define PROBE_STATE_NEW 0 #define PROBE_STATE_ACTIVE 1 -#define PROBE_STATE_INACTIVE 2 +#define PROBE_STATE_INVISIBLE 2 +#define PROBE_STATE_INACTIVE 3 #define VOLUME_CASCADE_COUNT 8 layout(set = 2, binding = 24) uniform sampler2DArray irradianceVolume; @@ -98,7 +99,7 @@ PackedRayHit PackRayHit(RayHit hit) { } uint GetProbeRayCount(uint state) { - return state == PROBE_STATE_INACTIVE ? ddgiData.inactiveRayCount : ddgiData.rayCount; + return state == PROBE_STATE_INACTIVE || state == PROBE_STATE_INVISIBLE ? ddgiData.inactiveRayCount : ddgiData.rayCount; } vec3 GetProbePosition(ivec3 probeIdx, int cascadeIndex) { diff --git a/data/shader/upsampleSpatial.csh b/data/shader/upsampleSpatial.csh index 9cf2fdd2f..08e53fc29 100644 --- a/data/shader/upsampleSpatial.csh +++ b/data/shader/upsampleSpatial.csh @@ -65,7 +65,7 @@ void main() { pixel.y > imageSize(textureOut).y) return; - vec2 uv = (vec2(pixel) + vec2(0.5)) / vec2(imageSize(textureOut)); + vec2 uv = (vec2(pixel)) / vec2(imageSize(textureOut)); vec4 color = SampleCatmullRom(uv); diff --git a/data/shader/volumetric/lightCulling.csh b/data/shader/volumetric/lightCulling.csh index 7ad475675..e2928118f 100644 --- a/data/shader/volumetric/lightCulling.csh +++ b/data/shader/volumetric/lightCulling.csh @@ -55,9 +55,7 @@ void main() { barrier(); - if (depth != 1.0) { - atomicMax(sharedDepthMax, floatBitsToUint(depth)); - } + atomicMax(sharedDepthMax, floatBitsToUint(depth)); barrier(); @@ -89,8 +87,6 @@ void main() { if (lightType == POINT_LIGHT) { sphere.center = light.location.xyz; sphere.radius = radius; - - visible = SphereAABBIntersection(sphere, frustumAABB); } else if (lightType == SPOT_LIGHT) { sphere = CalculateSphereFromSpotLight(light.location, light.direction, radius); diff --git a/data/shader/volumetric/volumetric.csh b/data/shader/volumetric/volumetric.csh index 72d195df6..d69dcde57 100644 --- a/data/shader/volumetric/volumetric.csh +++ b/data/shader/volumetric/volumetric.csh @@ -99,7 +99,7 @@ void LoadLightTypeData(uint requestedLightType) { barrier(); if (localOffset == 0) { - sharedLightIndicesCount = lightCount; + sharedLightIndicesCount = min(lightCount, sharedLightIndicesCount); } barrier(); @@ -349,7 +349,7 @@ vec4 ComputeVolumetricPunctualLights(uint lightType, vec3 fragPos, float startDe } // No shadows for now - // shadowValue = 1.0; + //shadowValue = 1.0; float phaseFunction = uniforms.fogEnabled > 0 ? ComputeScattering(uniforms.fog.scatteringAnisotropy, NdotL) : 1.0; diff --git a/src/engine/jobsystem/Job.h b/src/engine/jobsystem/Job.h index 22548694c..5bc1c0d0a 100644 --- a/src/engine/jobsystem/Job.h +++ b/src/engine/jobsystem/Job.h @@ -30,6 +30,15 @@ namespace Atlas { std::function function; void* userData = nullptr; + + inline JobData GetJobData(int32_t workerIdx = 0) const { + return JobData { + .idx = idx, + .workerIdx = 0, + .priority = priority, + .userData = userData + }; + } }; } \ No newline at end of file diff --git a/src/engine/jobsystem/JobSystem.cpp b/src/engine/jobsystem/JobSystem.cpp index 575ce24e6..bab9b45f5 100644 --- a/src/engine/jobsystem/JobSystem.cpp +++ b/src/engine/jobsystem/JobSystem.cpp @@ -10,6 +10,9 @@ #include #endif +// Use this macro to make the job system single threaded +// #define JOBS_SINGLE_THREADED + namespace Atlas { PriorityPool JobSystem::priorityPools[static_cast(JobPriority::Count)]; @@ -53,9 +56,6 @@ namespace Atlas { void JobSystem::Execute(JobGroup& group, std::function func, void* userData) { - auto& priorityPool = priorityPools[static_cast(group.priority)]; - group.counter.fetch_add(1); - Job job = { .priority = group.priority, .counter = &group.counter, @@ -63,6 +63,15 @@ namespace Atlas { .userData = userData }; +#ifdef JOBS_SINGLE_THREADED + auto jobData = job.GetJobData(); + job.function(jobData); + return; +#endif + + auto& priorityPool = priorityPools[static_cast(group.priority)]; + group.counter.fetch_add(1); + auto& worker = priorityPool.GetNextWorker(); worker.queue.Push(job); worker.signal.Notify(); @@ -71,9 +80,6 @@ namespace Atlas { void JobSystem::ExecuteMultiple(JobGroup& group, int32_t count, std::function func, void* userData) { - auto& priorityPool = priorityPools[static_cast(group.priority)]; - group.counter += count; - Job job = { .priority = group.priority, .counter = &group.counter, @@ -81,6 +87,18 @@ namespace Atlas { .userData = userData }; +#ifdef JOBS_SINGLE_THREADED + for (size_t i = 0; i < count; i++) { + job.idx = int32_t(i); + auto jobData = job.GetJobData(); + job.function(jobData); + } + return; +#endif + + auto& priorityPool = priorityPools[static_cast(group.priority)]; + group.counter += count; + if (count <= priorityPool.workerCount) { for (int32_t i = 0; i < count; i++) { auto& worker = priorityPool.GetNextWorker(); @@ -120,6 +138,10 @@ namespace Atlas { void JobSystem::Wait(JobSignal& signal, JobPriority priority) { +#ifdef JOBS_SINGLE_THREADED + return; +#endif + auto& priorityPool = priorityPools[static_cast(priority)]; while (!signal.TryAquire()) { @@ -131,6 +153,10 @@ namespace Atlas { void JobSystem::Wait(JobGroup& group) { +#ifdef JOBS_SINGLE_THREADED + return; +#endif + if (!group.HasFinished()) { auto& priorityPool = priorityPools[static_cast(group.priority)]; diff --git a/src/engine/lighting/Reflection.h b/src/engine/lighting/Reflection.h index e053b9e86..4b009dd5e 100644 --- a/src/engine/lighting/Reflection.h +++ b/src/engine/lighting/Reflection.h @@ -27,6 +27,7 @@ namespace Atlas { bool enable = true; bool rt = true; + bool ssr = true; bool ddgi = true; bool useShadowMap = false; bool useNormalMaps = true; diff --git a/src/engine/renderer/IndirectLightRenderer.cpp b/src/engine/renderer/IndirectLightRenderer.cpp index ece269629..fe6c7cce4 100644 --- a/src/engine/renderer/IndirectLightRenderer.cpp +++ b/src/engine/renderer/IndirectLightRenderer.cpp @@ -29,7 +29,7 @@ namespace Atlas { auto rtgiEnabled = rtgi && rtgi->enable && rtDataValid; auto ddgiEnabled = volume && volume->enable && !rtgiEnabled && rtDataValid; auto ddgiVisibility = volume && volume->enable && rtDataValid && volume->visibility; - auto reflectionEnabled = reflection && reflection->enable && rtDataValid; + auto reflectionEnabled = reflection && reflection->enable && (rtDataValid || reflection->ssr); auto aoEnabled = ao && ao->enable && (!ao->rt || rtDataValid) && !rtgiEnabled; auto ssgiEnabled = ssgi && ssgi->enable && !rtgiEnabled; bool ssgiAo = ssgiEnabled && ssgi->enableAo; diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index 063e8668a..7c2450559 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -43,7 +43,7 @@ namespace Atlas { void RTReflectionRenderer::Render(Ref target, Ref scene, Graphics::CommandList* commandList) { auto reflection = scene->reflection; - if (!reflection || !reflection->enable || !scene->IsRtDataValid()) return; + if (!reflection || !reflection->enable) return; if (reflection->halfResolution && !reflection->upsampleBeforeFiltering && target->GetReflectionResolution() == FULL_RES) target->SetReflectionResolution(HALF_RES); @@ -66,9 +66,7 @@ namespace Atlas { {target->historyReflectionMomentsTexture.image, layout, access}, }; commandList->PipelineBarrier(imageBarriers, {}); - } - - + } // Try to get a shadow map Ref shadow = nullptr; @@ -149,7 +147,7 @@ namespace Atlas { rtrUniformBuffer.SetData(&uniforms, 0); // Screen space reflections - { + if (reflection->ssr) { Graphics::Profiler::BeginQuery("SSR"); ivec2 groupCount = ivec2(rayRes.x / 8, rayRes.y / 8); @@ -182,7 +180,7 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Trace rays"); // Cast rays and calculate radiance - { + if (scene->IsRtDataValid()) { ivec2 groupCount = ivec2(rayRes.x / 8, rayRes.y / 4); groupCount.x += ((groupCount.x * 8 == rayRes.x) ? 0 : 1); groupCount.y += ((groupCount.y * 4 == rayRes.y) ? 0 : 1); diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index eb586ce9f..7ef57a7c4 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -72,12 +72,7 @@ namespace Atlas { return; auto sceneState = &scene->renderState; - - Ref frameBuffer = nullptr; - if (lightMap.contains(lightEntity)) - frameBuffer = lightMap[lightEntity]; - else - frameBuffer = GetOrCreateFrameBuffer(lightEntity); + auto frameBuffer = GetOrCreateFrameBuffer(lightEntity); lightMap[lightEntity] = frameBuffer; @@ -207,9 +202,14 @@ namespace Atlas { if (prevLightMap.contains(entity)) { auto frameBuffer = prevLightMap[entity]; - if (frameBuffer->extent.width == shadow->resolution || - frameBuffer->extent.height == shadow->resolution) { - return frameBuffer; + // The image for a light entity might change + if (light.shadow->useCubemap && frameBuffer->GetDepthImage() == light.shadow->cubemap->image || + !light.shadow->useCubemap && frameBuffer->GetDepthImage() == light.shadow->maps->image) { + // Also check if the resolution stayed the same + if (frameBuffer->extent.width == shadow->resolution || + frameBuffer->extent.height == shadow->resolution) { + return frameBuffer; + } } } diff --git a/src/engine/renderer/VolumetricRenderer.cpp b/src/engine/renderer/VolumetricRenderer.cpp index b65c7c9d4..497915b0a 100644 --- a/src/engine/renderer/VolumetricRenderer.cpp +++ b/src/engine/renderer/VolumetricRenderer.cpp @@ -183,12 +183,9 @@ namespace Atlas { cloudShadowUniform.ivMatrix = glm::inverse(cloudShadowUniform.vMatrix); cloudShadowUniform.ipMatrix = glm::inverse(cloudShadowUniform.pMatrix); } - - volumetricUniformBuffer.SetData(&uniforms, 0); + commandList->BindSampler(shadowSampler, 3, 6); - commandList->BindBuffer(volumetricUniformBuffer.Get(), 3, 7); - #ifndef AE_BINDLESS std::vector> cascadeMaps; std::vector> cubeMaps; @@ -213,6 +210,9 @@ namespace Atlas { commandList->BindSampledImages(cubeMaps, 3, 19); #endif + volumetricUniformBuffer.SetData(&uniforms, 0); + commandList->BindBuffer(volumetricUniformBuffer.Get(), 3, 7); + volumetricPipelineConfig.ManageMacro("CLOUDS", cloudsEnabled); volumetricPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowsEnabled); volumetricPipelineConfig.ManageMacro("OCEAN", oceanEnabled); diff --git a/src/engine/renderer/target/RenderTarget.cpp b/src/engine/renderer/target/RenderTarget.cpp index a3c1e1e5d..1e10f5f7d 100644 --- a/src/engine/renderer/target/RenderTarget.cpp +++ b/src/engine/renderer/target/RenderTarget.cpp @@ -24,7 +24,7 @@ namespace Atlas::Renderer { Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); swapHistoryTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R16G16B16A16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); - lightingTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_A2B10G10R10_UNORM_PACK32, + lightingTexture = Texture::Texture2D(scaledWidth, scaledHeight, VK_FORMAT_R16G16B16A16_SFLOAT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); reactiveMaskTexture = Texture::Texture2D(scaledWidth, scaledWidth, VK_FORMAT_R8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Linear, false, true); From ba953d3bb02b1756852ebb74cfe4994610ae12b9 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 26 Oct 2024 12:01:49 +0200 Subject: [PATCH 58/66] Working on more general BLASes (e.g. terrain) --- src/engine/graphics/ASBuilder.cpp | 4 +- src/engine/graphics/ASBuilder.h | 4 +- src/engine/loader/TerrainLoader.cpp | 2 + src/engine/mesh/Mesh.cpp | 55 ++--- src/engine/mesh/Mesh.h | 13 +- src/engine/mesh/MeshData.cpp | 156 +------------- src/engine/mesh/MeshData.h | 14 +- src/engine/raytracing/BLAS.cpp | 215 ++++++++++++++++++++ src/engine/raytracing/BLAS.h | 68 +++++++ src/engine/raytracing/RayTracingManager.cpp | 8 +- src/engine/raytracing/RayTracingWorld.cpp | 32 +-- src/engine/renderer/MainRenderer.cpp | 45 ++-- src/engine/scene/Scene.cpp | 8 +- src/engine/scene/SceneRenderState.cpp | 51 +++-- src/engine/scene/SceneRenderState.h | 8 +- src/engine/terrain/TerrainStorageCell.cpp | 70 +++++++ src/engine/terrain/TerrainStorageCell.h | 4 + 17 files changed, 467 insertions(+), 290 deletions(-) create mode 100644 src/engine/raytracing/BLAS.cpp create mode 100644 src/engine/raytracing/BLAS.h diff --git a/src/engine/graphics/ASBuilder.cpp b/src/engine/graphics/ASBuilder.cpp index 396a15902..32b24d760 100644 --- a/src/engine/graphics/ASBuilder.cpp +++ b/src/engine/graphics/ASBuilder.cpp @@ -7,7 +7,7 @@ namespace Atlas { namespace Graphics { BLASDesc ASBuilder::GetBLASDescForTriangleGeometry(Ref vertexBuffer, Ref indexBuffer, - size_t vertexCount, size_t vertexSize, size_t indexSize, std::vector regions) { + size_t vertexCount, size_t vertexSize, size_t indexSize, std::span regions) { VkDeviceAddress vertexAddress = vertexBuffer->GetDeviceAddress(); VkDeviceAddress indexAddress = indexBuffer->GetDeviceAddress(); @@ -25,7 +25,7 @@ namespace Atlas { BLASDesc desc; - for (auto& region : regions) { + for (const auto& region : regions) { VkAccelerationStructureGeometryKHR geometry = {}; geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; diff --git a/src/engine/graphics/ASBuilder.h b/src/engine/graphics/ASBuilder.h index 247ffd207..3fc5b129d 100644 --- a/src/engine/graphics/ASBuilder.h +++ b/src/engine/graphics/ASBuilder.h @@ -7,6 +7,8 @@ #include "QueryPool.h" #include "CommandList.h" +#include + namespace Atlas { namespace Graphics { @@ -24,7 +26,7 @@ namespace Atlas { ASBuilder() = default; BLASDesc GetBLASDescForTriangleGeometry(Ref vertexBuffer, Ref indexBuffer, - size_t vertexCount, size_t vertexSize, size_t indexSize, std::vector regions); + size_t vertexCount, size_t vertexSize, size_t indexSize, std::span regions); int32_t BuildBLAS(std::vector>& blases, CommandList* commandList = nullptr); diff --git a/src/engine/loader/TerrainLoader.cpp b/src/engine/loader/TerrainLoader.cpp index c2a8025e4..a456f03d3 100644 --- a/src/engine/loader/TerrainLoader.cpp +++ b/src/engine/loader/TerrainLoader.cpp @@ -282,6 +282,8 @@ namespace Atlas { fileStream.close(); + cell->BuildBVH(); + } int32_t TerrainLoader::ReadInt(const char* ptr, std::string line, size_t& offset) { diff --git a/src/engine/mesh/Mesh.cpp b/src/engine/mesh/Mesh.cpp index a4cd92af6..a057625cc 100644 --- a/src/engine/mesh/Mesh.cpp +++ b/src/engine/mesh/Mesh.cpp @@ -91,7 +91,7 @@ namespace Atlas { normal = vec4(-vec3(normal.x, normal.y, normal.z), normal.w); UpdateData(); - isBvhBuilt = false; + blas->isBvhBuilt = false; } @@ -105,25 +105,15 @@ namespace Atlas { if (data.indexCount == 0 || !bindless || !vertexBuffer.elementCount || !indexBuffer.elementCount) return; - data.BuildBVH(parallelBuild); - - triangleBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(GPUTriangle)); - triangleBuffer.SetSize(data.gpuTriangles.size()); - triangleBuffer.SetData(data.gpuTriangles.data(), 0, data.gpuTriangles.size()); + std::vector triangles; + data.BuildBVHData(triangles); - if (!hardwareRayTracing) { - blasNodeBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(GPUBVHNode)); - blasNodeBuffer.SetSize(data.gpuBvhNodes.size()); - blasNodeBuffer.SetData(data.gpuBvhNodes.data(), 0, data.gpuBvhNodes.size()); - - bvhTriangleBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(GPUBVHTriangle)); - bvhTriangleBuffer.SetSize(data.gpuBvhTriangles.size()); - bvhTriangleBuffer.SetData(data.gpuBvhTriangles.data(), 0, data.gpuBvhTriangles.size()); - } - else { - Graphics::ASBuilder asBuilder; + blas = CreateRef(); + if (hardwareRayTracing) { std::vector geometryRegions; + geometryRegions.reserve(data.subData.size()); + for (auto& subData : data.subData) { geometryRegions.emplace_back(Graphics::ASGeometryRegion{ .indexCount = subData.indicesCount, @@ -132,35 +122,17 @@ namespace Atlas { }); } - auto blasDesc = asBuilder.GetBLASDescForTriangleGeometry(vertexBuffer.buffer, indexBuffer.buffer, - vertexBuffer.elementCount, vertexBuffer.elementSize, indexBuffer.elementSize, geometryRegions); - - blas = device->CreateBLAS(blasDesc); - - std::vector triangleOffsets; - for (const auto& subData : data.subData) { - auto triangleOffset = subData.indicesOffset / 3; - triangleOffsets.push_back(triangleOffset); - } - - triangleOffsetBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(uint32_t)); - triangleOffsetBuffer.SetSize(triangleOffsets.size(), triangleOffsets.data()); - - needsBvhRefresh = true; + blas->Build(triangles, data.materials, vertexBuffer, indexBuffer, geometryRegions); + } + else { + blas->Build(triangles, data.materials); } - - data.gpuBvhNodes.clear(); - data.gpuBvhNodes.shrink_to_fit(); - - data.gpuBvhTriangles.clear(); - data.gpuBvhTriangles.shrink_to_fit(); - - isBvhBuilt = true; } void Mesh::ClearBVH() { + /* // This whole operation can only be done when no ray tracing jobs or bindless updates are running isBvhBuilt = false; @@ -183,12 +155,13 @@ namespace Atlas { else { triangleOffsetBuffer.Reset(); } + */ } bool Mesh::IsBVHBuilt() const { - return isBvhBuilt; + return blas && blas->IsBuilt(); } diff --git a/src/engine/mesh/Mesh.h b/src/engine/mesh/Mesh.h index a719a009e..a86d67cfe 100644 --- a/src/engine/mesh/Mesh.h +++ b/src/engine/mesh/Mesh.h @@ -4,6 +4,7 @@ #include "../Material.h" #include "resource/Resource.h" #include "../buffer/VertexArray.h" +#include "../raytracing/BLAS.h" #include "MeshData.h" #include "Impostor.h" @@ -85,13 +86,7 @@ namespace Atlas { Buffer::VertexBuffer tangentBuffer; Buffer::VertexBuffer colorBuffer; - Buffer::Buffer blasNodeBuffer; - Buffer::Buffer triangleBuffer; - Buffer::Buffer bvhTriangleBuffer; - Buffer::Buffer triangleOffsetBuffer; - - Ref blas = nullptr; - + Ref blas = nullptr; Ref impostor = nullptr; bool cullBackFaces = true; @@ -115,12 +110,8 @@ namespace Atlas { bool invertUVs = false; - std::atomic_bool needsBvhRefresh = false; - private: bool isLoaded = false; - - std::atomic_bool isBvhBuilt = false; }; diff --git a/src/engine/mesh/MeshData.cpp b/src/engine/mesh/MeshData.cpp index 6e020758b..0e615ab0c 100644 --- a/src/engine/mesh/MeshData.cpp +++ b/src/engine/mesh/MeshData.cpp @@ -60,42 +60,18 @@ namespace Atlas { } - void MeshData::BuildBVH(bool parallelBuild) { + void MeshData::BuildBVHData(std::vector& triangles) { auto device = Graphics::GraphicsDevice::DefaultDevice; bool hardwareRayTracing = device->support.hardwareRayTracing; - struct Triangle { - vec3 v0; - vec3 v1; - vec3 v2; - - vec3 n0; - vec3 n1; - vec3 n2; - - vec2 uv0; - vec2 uv1; - vec2 uv2; - - vec4 color0; - vec4 color1; - vec4 color2; - - int32_t materialIdx; - float opacity; - }; - uint32_t triangleCount = 0; for (auto& sub : subData) { triangleCount += sub.indicesCount / 3; } - std::vector triangles(triangleCount); - - std::vector aabbs(triangleCount); - std::vector bvhTriangles(triangleCount); + triangles.resize(triangleCount); triangleCount = 0; @@ -140,140 +116,12 @@ namespace Atlas { triangles[k].materialIdx = sub.materialIdx; triangles[k].opacity = sub.material->HasOpacityMap() ? -1.0f : sub.material->opacity; - auto min = glm::min(glm::min(triangles[k].v0, - triangles[k].v1), triangles[k].v2); - auto max = glm::max(glm::max(triangles[k].v0, - triangles[k].v1), triangles[k].v2); - - bvhTriangles[k].v0 = triangles[k].v0; - bvhTriangles[k].v1 = triangles[k].v1; - bvhTriangles[k].v2 = triangles[k].v2; - bvhTriangles[k].idx = k; - - aabbs[k] = Volume::AABB(min, max); - } triangleCount += subDataTriangleCount; } - Volume::BVH bvh; - if (!hardwareRayTracing) { - // Generate BVH - bvh = Volume::BVH(aabbs, bvhTriangles, parallelBuild); - - bvhTriangles.clear(); - bvhTriangles.shrink_to_fit(); - } - - auto& data = hardwareRayTracing ? bvhTriangles : bvh.data; - - for (auto& bvhTriangle : data) { - - auto& triangle = triangles[bvhTriangle.idx]; - - auto v0v1 = triangle.v1 - triangle.v0; - auto v0v2 = triangle.v2 - triangle.v0; - - auto uv0uv1 = triangle.uv1 - triangle.uv0; - auto uv0uv2 = triangle.uv2 - triangle.uv0; - - auto r = 1.0f / (uv0uv1.x * uv0uv2.y - uv0uv2.x * uv0uv1.y); - - auto s = vec3(uv0uv2.y * v0v1.x - uv0uv1.y * v0v2.x, - uv0uv2.y * v0v1.y - uv0uv1.y * v0v2.y, - uv0uv2.y * v0v1.z - uv0uv1.y * v0v2.z) * r; - - auto t = vec3(uv0uv1.x * v0v2.x - uv0uv2.x * v0v1.x, - uv0uv1.x * v0v2.y - uv0uv2.x * v0v1.y, - uv0uv1.x * v0v2.z - uv0uv2.x * v0v1.z) * r; - - auto normal = glm::normalize(triangle.n0 + triangle.n1 + triangle.n2); - - auto tangent = glm::normalize(s - normal * dot(normal, s)); - auto handedness = (glm::dot(glm::cross(tangent, normal), t) < 0.0f ? 1.0f : -1.0f); - - auto bitangent = handedness * glm::normalize(glm::cross(tangent, normal)); - - // Compress data - auto pn0 = Common::Packing::PackSignedVector3x10_1x2(vec4(triangle.n0, 0.0f)); - auto pn1 = Common::Packing::PackSignedVector3x10_1x2(vec4(triangle.n1, 0.0f)); - auto pn2 = Common::Packing::PackSignedVector3x10_1x2(vec4(triangle.n2, 0.0f)); - - auto pt = Common::Packing::PackSignedVector3x10_1x2(vec4(tangent, 0.0f)); - auto pbt = Common::Packing::PackSignedVector3x10_1x2(vec4(bitangent, 0.0f)); - - auto puv0 = glm::packHalf2x16(triangle.uv0); - auto puv1 = glm::packHalf2x16(triangle.uv1); - auto puv2 = glm::packHalf2x16(triangle.uv2); - - auto pc0 = glm::packUnorm4x8(triangle.color0); - auto pc1 = glm::packUnorm4x8(triangle.color1); - auto pc2 = glm::packUnorm4x8(triangle.color2); - - auto cn0 = reinterpret_cast(pn0); - auto cn1 = reinterpret_cast(pn1); - auto cn2 = reinterpret_cast(pn2); - - auto ct = reinterpret_cast(pt); - auto cbt = reinterpret_cast(pbt); - - auto cuv0 = reinterpret_cast(puv0); - auto cuv1 = reinterpret_cast(puv1); - auto cuv2 = reinterpret_cast(puv2); - - auto cc0 = reinterpret_cast(pc0); - auto cc1 = reinterpret_cast(pc1); - auto cc2 = reinterpret_cast(pc2); - - GPUTriangle gpuTriangle; - - gpuTriangle.v0 = vec4(triangle.v0, cn0); - gpuTriangle.v1 = vec4(triangle.v1, cn1); - gpuTriangle.v2 = vec4(triangle.v2, cn2); - gpuTriangle.d0 = vec4(cuv0, cuv1, cuv2, reinterpret_cast(triangle.materialIdx)); - gpuTriangle.d1 = vec4(ct, cbt, bvhTriangle.endOfNode ? 1.0f : -1.0f, 0.0f); - gpuTriangle.d2 = vec4(cc0, cc1, cc2, triangle.opacity); - - gpuTriangles.push_back(gpuTriangle); - - if (!hardwareRayTracing) { - GPUBVHTriangle gpuBvhTriangle; - gpuBvhTriangle.v0 = vec4(triangle.v0, bvhTriangle.endOfNode ? 1.0f : -1.0f); - gpuBvhTriangle.v1 = vec4(triangle.v1, reinterpret_cast(triangle.materialIdx)); - gpuBvhTriangle.v2 = vec4(triangle.v2, triangle.opacity); - - gpuBvhTriangles.push_back(gpuBvhTriangle); - } - - } - - if (!hardwareRayTracing) { - triangles.clear(); - triangles.shrink_to_fit(); - - auto& nodes = bvh.GetTree(); - gpuBvhNodes = std::vector(nodes.size()); - // Copy to GPU format - for (size_t i = 0; i < nodes.size(); i++) { - gpuBvhNodes[i].leftPtr = nodes[i].leftPtr; - gpuBvhNodes[i].rightPtr = nodes[i].rightPtr; - - gpuBvhNodes[i].leftAABB.min = nodes[i].leftAABB.min; - gpuBvhNodes[i].leftAABB.max = nodes[i].leftAABB.max; - - gpuBvhNodes[i].rightAABB.min = nodes[i].rightAABB.min; - gpuBvhNodes[i].rightAABB.max = nodes[i].rightAABB.max; - } - } - - } - - bool MeshData::IsBVHBuilt() { - - return gpuBvhTriangles.size() > 0; - } void MeshData::DeepCopy(const MeshData& that) { diff --git a/src/engine/mesh/MeshData.h b/src/engine/mesh/MeshData.h index 1e7a5d982..dd4f77e56 100644 --- a/src/engine/mesh/MeshData.h +++ b/src/engine/mesh/MeshData.h @@ -2,7 +2,7 @@ #include "../System.h" #include "../volume/AABB.h" -#include "raytracing/RTStructures.h" +#include "raytracing/BLAS.h" #include "resource/Resource.h" #include "DataComponent.h" #include "Material.h" @@ -85,13 +85,7 @@ namespace Atlas { /** * Builds a blas from the data */ - void BuildBVH(bool parallelBuild); - - /** - * - * @return - */ - bool IsBVHBuilt(); + void BuildBVHData(std::vector& triangles); std::string name; @@ -117,10 +111,6 @@ namespace Atlas { int32_t indexCount = 0; int32_t vertexCount = 0; - std::vector gpuTriangles; - std::vector gpuBvhTriangles; - std::vector gpuBvhNodes; - }; } diff --git a/src/engine/raytracing/BLAS.cpp b/src/engine/raytracing/BLAS.cpp new file mode 100644 index 000000000..c0cb6f196 --- /dev/null +++ b/src/engine/raytracing/BLAS.cpp @@ -0,0 +1,215 @@ +#include "BLAS.h" + +#include "../volume/BVH.h" +#include "../common/Packing.h" + +namespace Atlas::RayTracing { + + void BLAS::Build(std::vector& triangles, std::vector>& materials) { + + BuildBuffers(triangles, materials); + + isBvhBuilt = true; + + } + + void BLAS::Build(std::vector& triangles, std::vector>& materials, + Buffer::VertexBuffer& vertexBuffer, Buffer::IndexBuffer& indexBuffer, std::span geometryRegions) { + + auto device = Graphics::GraphicsDevice::DefaultDevice; + bool hardwareRayTracing = device->support.hardwareRayTracing; + + BuildBuffers(triangles, materials); + + + if (hardwareRayTracing) { + Graphics::ASBuilder asBuilder; + + auto blasDesc = asBuilder.GetBLASDescForTriangleGeometry(vertexBuffer.buffer, indexBuffer.buffer, + vertexBuffer.elementCount, vertexBuffer.elementSize, indexBuffer.elementSize, geometryRegions); + + blas = device->CreateBLAS(blasDesc); + + std::vector triangleOffsets; + triangleOffsets.reserve(geometryRegions.size()); + + for (const auto& region : geometryRegions) { + auto triangleOffset = uint32_t(region.indexOffset) / 3; + triangleOffsets.push_back(triangleOffset); + } + + triangleOffsetBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(uint32_t)); + triangleOffsetBuffer.SetSize(triangleOffsets.size(), triangleOffsets.data()); + + needsBvhRefresh = true; + } + + isBvhBuilt = true; + + } + + bool BLAS::IsBuilt() const { + + return isBvhBuilt; + + } + + void BLAS::BuildBuffers(std::vector& triangles, std::vector>& materials) { + + auto device = Graphics::GraphicsDevice::DefaultDevice; + bool hardwareRayTracing = device->support.hardwareRayTracing; + + this->materials = materials; + + auto triangleCount = triangles.size(); + + std::vector aabbs(triangleCount); + std::vector bvhTriangles(triangleCount); + + for (size_t i = 0; i < triangleCount; i++) { + auto min = glm::min(glm::min(triangles[i].v0, + triangles[i].v1), triangles[i].v2); + auto max = glm::max(glm::max(triangles[i].v0, + triangles[i].v1), triangles[i].v2); + + bvhTriangles[i].v0 = triangles[i].v0; + bvhTriangles[i].v1 = triangles[i].v1; + bvhTriangles[i].v2 = triangles[i].v2; + bvhTriangles[i].idx = i; + + aabbs[i] = Volume::AABB(min, max); + } + + Volume::BVH bvh; + if (!hardwareRayTracing) { + // Generate BVH + bvh = Volume::BVH(aabbs, bvhTriangles); + + bvhTriangles.clear(); + bvhTriangles.shrink_to_fit(); + + aabbs.clear(); + aabbs.shrink_to_fit(); + } + + auto& data = hardwareRayTracing ? bvhTriangles : bvh.data; + + std::vector gpuTriangles; + std::vector gpuBvhTriangles; + + gpuTriangles.reserve(triangleCount); + if (!hardwareRayTracing) + gpuBvhTriangles.reserve(triangleCount); + + + for (auto& bvhTriangle : data) { + + auto& triangle = triangles[bvhTriangle.idx]; + + auto v0v1 = triangle.v1 - triangle.v0; + auto v0v2 = triangle.v2 - triangle.v0; + + auto uv0uv1 = triangle.uv1 - triangle.uv0; + auto uv0uv2 = triangle.uv2 - triangle.uv0; + + auto r = 1.0f / (uv0uv1.x * uv0uv2.y - uv0uv2.x * uv0uv1.y); + + auto s = vec3(uv0uv2.y * v0v1.x - uv0uv1.y * v0v2.x, + uv0uv2.y * v0v1.y - uv0uv1.y * v0v2.y, + uv0uv2.y * v0v1.z - uv0uv1.y * v0v2.z) * r; + + auto t = vec3(uv0uv1.x * v0v2.x - uv0uv2.x * v0v1.x, + uv0uv1.x * v0v2.y - uv0uv2.x * v0v1.y, + uv0uv1.x * v0v2.z - uv0uv2.x * v0v1.z) * r; + + auto normal = glm::normalize(triangle.n0 + triangle.n1 + triangle.n2); + + auto tangent = glm::normalize(s - normal * dot(normal, s)); + auto handedness = (glm::dot(glm::cross(tangent, normal), t) < 0.0f ? 1.0f : -1.0f); + + auto bitangent = handedness * glm::normalize(glm::cross(tangent, normal)); + + // Compress data + auto pn0 = Common::Packing::PackSignedVector3x10_1x2(vec4(triangle.n0, 0.0f)); + auto pn1 = Common::Packing::PackSignedVector3x10_1x2(vec4(triangle.n1, 0.0f)); + auto pn2 = Common::Packing::PackSignedVector3x10_1x2(vec4(triangle.n2, 0.0f)); + + auto pt = Common::Packing::PackSignedVector3x10_1x2(vec4(tangent, 0.0f)); + auto pbt = Common::Packing::PackSignedVector3x10_1x2(vec4(bitangent, 0.0f)); + + auto puv0 = glm::packHalf2x16(triangle.uv0); + auto puv1 = glm::packHalf2x16(triangle.uv1); + auto puv2 = glm::packHalf2x16(triangle.uv2); + + auto pc0 = glm::packUnorm4x8(triangle.color0); + auto pc1 = glm::packUnorm4x8(triangle.color1); + auto pc2 = glm::packUnorm4x8(triangle.color2); + + auto cn0 = reinterpret_cast(pn0); + auto cn1 = reinterpret_cast(pn1); + auto cn2 = reinterpret_cast(pn2); + + auto ct = reinterpret_cast(pt); + auto cbt = reinterpret_cast(pbt); + + auto cuv0 = reinterpret_cast(puv0); + auto cuv1 = reinterpret_cast(puv1); + auto cuv2 = reinterpret_cast(puv2); + + auto cc0 = reinterpret_cast(pc0); + auto cc1 = reinterpret_cast(pc1); + auto cc2 = reinterpret_cast(pc2); + + GPUTriangle gpuTriangle; + + gpuTriangle.v0 = vec4(triangle.v0, cn0); + gpuTriangle.v1 = vec4(triangle.v1, cn1); + gpuTriangle.v2 = vec4(triangle.v2, cn2); + gpuTriangle.d0 = vec4(cuv0, cuv1, cuv2, reinterpret_cast(triangle.materialIdx)); + gpuTriangle.d1 = vec4(ct, cbt, bvhTriangle.endOfNode ? 1.0f : -1.0f, 0.0f); + gpuTriangle.d2 = vec4(cc0, cc1, cc2, triangle.opacity); + + gpuTriangles.push_back(gpuTriangle); + + if (!hardwareRayTracing) { + GPUBVHTriangle gpuBvhTriangle; + gpuBvhTriangle.v0 = vec4(triangle.v0, bvhTriangle.endOfNode ? 1.0f : -1.0f); + gpuBvhTriangle.v1 = vec4(triangle.v1, reinterpret_cast(triangle.materialIdx)); + gpuBvhTriangle.v2 = vec4(triangle.v2, triangle.opacity); + + gpuBvhTriangles.push_back(gpuBvhTriangle); + } + + } + + triangleBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(GPUTriangle)); + triangleBuffer.SetSize(gpuTriangles.size(), gpuTriangles.data()); + + if (!hardwareRayTracing) { + bvhTriangleBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(GPUBVHTriangle)); + bvhTriangleBuffer.SetSize(gpuBvhTriangles.size(), gpuBvhTriangles.data()); + + gpuBvhTriangles.clear(); + gpuBvhTriangles.shrink_to_fit(); + + auto& nodes = bvh.GetTree(); + std::vector gpuBvhNodes(nodes.size()); + // Copy to GPU format + for (size_t i = 0; i < nodes.size(); i++) { + gpuBvhNodes[i].leftPtr = nodes[i].leftPtr; + gpuBvhNodes[i].rightPtr = nodes[i].rightPtr; + + gpuBvhNodes[i].leftAABB.min = nodes[i].leftAABB.min; + gpuBvhNodes[i].leftAABB.max = nodes[i].leftAABB.max; + + gpuBvhNodes[i].rightAABB.min = nodes[i].rightAABB.min; + gpuBvhNodes[i].rightAABB.max = nodes[i].rightAABB.max; + } + + blasNodeBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit | Buffer::BufferUsageBits::DedicatedMemoryBit, sizeof(GPUBVHNode)); + blasNodeBuffer.SetSize(gpuBvhNodes.size(), gpuBvhNodes.data()); + } + + } + +} \ No newline at end of file diff --git a/src/engine/raytracing/BLAS.h b/src/engine/raytracing/BLAS.h new file mode 100644 index 000000000..4a61b8190 --- /dev/null +++ b/src/engine/raytracing/BLAS.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +#include "Material.h" +#include "resource/Resource.h" +#include "buffer/Buffer.h" +#include "buffer/IndexBuffer.h" +#include "buffer/VertexBuffer.h" +#include "graphics/BLAS.h" +#include "graphics/ASBuilder.h" +#include "RTStructures.h" + +namespace Atlas::RayTracing { + + class BLAS { + + public: + struct Triangle { + vec3 v0; + vec3 v1; + vec3 v2; + + vec3 n0; + vec3 n1; + vec3 n2; + + vec2 uv0; + vec2 uv1; + vec2 uv2; + + vec4 color0; + vec4 color1; + vec4 color2; + + int32_t materialIdx; + float opacity; + }; + + BLAS() = default; + + void Build(std::vector& triangles, std::vector>& materials); + + void Build(std::vector& triangles, std::vector>& materials, + Buffer::VertexBuffer& vertexBuffer, Buffer::IndexBuffer& indexBuffer, std::span geometryRegions); + + bool IsBuilt() const; + + std::vector> materials; + + std::vector gpuTriangles; + + Buffer::Buffer blasNodeBuffer; + Buffer::Buffer triangleBuffer; + Buffer::Buffer bvhTriangleBuffer; + Buffer::Buffer triangleOffsetBuffer; + + Ref blas = nullptr; + + std::atomic_bool needsBvhRefresh{ false }; + std::atomic_bool isBvhBuilt { false }; + + private: + void BuildBuffers(std::vector& triangles, std::vector>& materials); + + }; + +} \ No newline at end of file diff --git a/src/engine/raytracing/RayTracingManager.cpp b/src/engine/raytracing/RayTracingManager.cpp index 5bd9a4ce0..a907c778f 100644 --- a/src/engine/raytracing/RayTracingManager.cpp +++ b/src/engine/raytracing/RayTracingManager.cpp @@ -55,11 +55,11 @@ namespace Atlas::RayTracing { auto& mesh = *it; // Only want static meshes - if (!mesh.IsLoaded() || !mesh->IsBVHBuilt() || !mesh->needsBvhRefresh || mesh->blas->isDynamic) { + if (!mesh.IsLoaded() || !mesh->IsBVHBuilt() || !mesh->blas->needsBvhRefresh || mesh->blas->blas->isDynamic) { it = meshes.erase(it); } else { - blases.push_back(mesh->blas); + blases.push_back(mesh->blas->blas); ++it; } } @@ -71,8 +71,8 @@ namespace Atlas::RayTracing { // Copy the non-compacted versions over for (size_t i = 0; i < blasBuiltCount; i++) { - meshes[i]->blas = blases[i]; - meshes[i]->needsBvhRefresh = false; + meshes[i]->blas->blas = blases[i]; + meshes[i]->blas->needsBvhRefresh = false; } blases.clear(); diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index ec7208ccb..deb93fa00 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -45,14 +45,14 @@ namespace Atlas { auto meshes = scene->GetMeshes(); int32_t meshCount = 0; - JobSystem::Wait(renderState->bindlessMeshMapUpdateJob); + JobSystem::Wait(renderState->bindlessBlasMapUpdateJob); std::swap(prevMeshInfos, meshInfos); meshInfos.clear(); for (auto& mesh : meshes) { // Only need to check for this, since that means that the BVH was built and the mesh is loaded - if (!renderState->meshIdToBindlessIdx.contains(mesh.GetID())) + if (!renderState->blasToBindlessIdx.contains(mesh->blas)) continue; if (!prevMeshInfos.contains(mesh.GetID())) { @@ -64,17 +64,17 @@ namespace Atlas { } auto &meshInfo = meshInfos[mesh.GetID()]; - meshInfo.offset = int32_t(renderState->meshIdToBindlessIdx[mesh.GetID()]); + meshInfo.offset = int32_t(renderState->blasToBindlessIdx[mesh->blas]); meshInfo.cullingDistanceSqr = mesh->rayTraceDistanceCulling * mesh->rayTraceDistanceCulling; // Some extra path for hardware raytracing, don't want to do work twice if (hardwareRayTracing) { - if (mesh->needsBvhRefresh && mesh->blas->isDynamic) { - blases.push_back(mesh->blas); - mesh->needsBvhRefresh = false; + if (mesh->blas->needsBvhRefresh && mesh->blas->blas->isDynamic) { + blases.push_back(mesh->blas->blas); + mesh->blas->needsBvhRefresh = false; } - meshInfo.blas = mesh->blas; + meshInfo.blas = mesh->blas->blas; meshInfo.idx = meshCount++; } } @@ -116,7 +116,7 @@ namespace Atlas { for (auto entity : subset) { const auto& [meshComponent, transformComponent] = subset.Get(entity); - if (!renderState->meshIdToBindlessIdx.contains(meshComponent.mesh.GetID())) + if (!renderState->blasToBindlessIdx.contains(meshComponent.mesh->blas)) continue; auto &meshInfo = meshInfos[meshComponent.mesh.GetID()]; @@ -125,7 +125,7 @@ namespace Atlas { cameraLocation); if (hasCamera && distSqd > meshInfo.cullingDistanceSqr) continue; - if (hardwareRayTracing && !meshComponent.mesh->blas->isBuilt || meshComponent.mesh->needsBvhRefresh) + if (hardwareRayTracing && !meshComponent.mesh->blas->blas->isBuilt || meshComponent.mesh->blas->needsBvhRefresh) continue; actorAABBs.push_back(meshComponent.aabb); @@ -158,7 +158,7 @@ namespace Atlas { inst.transform = transform; inst.instanceCustomIndex = meshInfo.offset; - inst.accelerationStructureReference = meshComponent.mesh->blas->bufferDeviceAddress; + inst.accelerationStructureReference = meshComponent.mesh->blas->blas->bufferDeviceAddress; inst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; inst.mask = mask; inst.instanceShaderBindingTableRecordOffset = 0; @@ -166,6 +166,14 @@ namespace Atlas { } } + if (scene->terrain) { + for (auto node : scene->terrain->renderList) { + + + + } + } + if (gpuBvhInstances.empty()) { // Need to reset the TLAS in this case, since it might contain invalid memory addresses tlas = nullptr; @@ -367,8 +375,8 @@ namespace Atlas { void RayTracingWorld::BuildTriangleLightsForMesh(ResourceHandle &mesh) { - auto& gpuTriangles = mesh->data.gpuTriangles; - auto& materials = mesh->data.materials; + auto& gpuTriangles = mesh->blas->gpuTriangles; + auto& materials = mesh->blas->materials; auto& meshInfo = meshInfos[mesh.GetID()]; meshInfo.triangleLights.clear(); diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index c7df25904..b4ed8f75a 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -138,7 +138,7 @@ namespace Atlas { renderState->materialBuffer.Bind(commandList, 1, 15); // Wait as long as possible for this to finish - JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(renderState->prepareBindlessBlasesJob); JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); JobSystem::WaitSpin(renderState->bindlessOtherTextureMapUpdateJob); commandList->BindBuffers(renderState->triangleBuffers, 0, 1); @@ -436,24 +436,29 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Buffer operations"); auto globalUniforms = GlobalUniforms{ - .vMatrix = camera.viewMatrix, - .pMatrix = camera.projectionMatrix, - .ivMatrix = camera.invViewMatrix, - .ipMatrix = camera.invProjectionMatrix, - .pvMatrixLast = camera.GetLastJitteredMatrix(), - .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, - .vMatrixLast = camera.GetLastViewMatrix(), - .jitterLast = camera.GetJitter(), - .jitterCurrent = camera.GetLastJitter(), - .cameraLocation = vec4(camera.GetLocation(), 0.0f), - .cameraDirection = vec4(camera.direction, 0.0f), - .cameraUp = vec4(camera.up, 0.0f), - .cameraRight = vec4(camera.right, 0.0f), - .planetCenter = vec4(scene->sky.planetCenter, 0.0f), - .planetRadius = scene->sky.planetRadius, - .time = Clock::Get(), - .deltaTime = Clock::GetDelta(), - .frameCount = frameCount, + .vMatrix = camera.viewMatrix, + .pMatrix = camera.projectionMatrix, + .ivMatrix = camera.invViewMatrix, + .ipMatrix = camera.invProjectionMatrix, + .pvMatrixLast = camera.GetLastJitteredMatrix(), + .pvMatrixCurrent = camera.projectionMatrix * camera.viewMatrix, + .ipvMatrixLast = glm::inverse(camera.GetLastJitteredMatrix()), + .ipvMatrixCurrent = glm::inverse(camera.projectionMatrix * camera.viewMatrix), + .vMatrixLast = camera.GetLastViewMatrix(), + .jitterLast = camera.GetLastJitter(), + .jitterCurrent = camera.GetJitter(), + .cameraLocation = vec4(camera.GetLocation(), 0.0f), + .cameraDirection = vec4(camera.direction, 0.0f), + .cameraUp = vec4(camera.up, 0.0f), + .cameraRight = vec4(camera.right, 0.0f), + .planetCenter = vec4(scene->sky.planetCenter, 0.0f), + .windDir = glm::normalize(scene->wind.direction), + .windSpeed = scene->wind.speed, + .planetRadius = scene->sky.planetRadius, + .time = Clock::Get(), + .deltaTime = Clock::GetDelta(), + .frameCount = frameCount, + .mipLodBias = -1.0f / target->GetScalingFactor(), .cameraNearPlane = camera.nearPlane, .cameraFarPlane = camera.farPlane, }; @@ -461,7 +466,7 @@ namespace Atlas { pathTraceGlobalUniformBuffer->SetData(&globalUniforms, 0, sizeof(GlobalUniforms)); JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); - JobSystem::WaitSpin(renderState->prepareBindlessMeshesJob); + JobSystem::WaitSpin(renderState->prepareBindlessBlasesJob); JobSystem::WaitSpin(renderState->bindlessTextureMapUpdateJob); commandList->BindBuffer(pathTraceGlobalUniformBuffer, 1, 31); diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index f597d9aef..fbd3fd9fa 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -112,7 +112,7 @@ namespace Atlas { // Can only update after scripts were run #ifdef AE_BINDLESS - renderState.UpdateMeshBindlessData(); + renderState.UpdateBlasBindlessData(); renderState.UpdateTextureBindlessData(); renderState.UpdateOtherTextureBindlessData(); #endif @@ -397,7 +397,7 @@ namespace Atlas { if (camera.isMain && !mainCameraEntity.IsValid()) { mainCameraEntity = { entity, &entityManager }; } - } + } renderState.mainCameraSignal.Release(); @@ -408,6 +408,10 @@ namespace Atlas { auto& mainCamera = mainCameraEntity.GetComponent(); + if (terrain) { + terrain->Update(mainCamera); + } + auto audioSubset = entityManager.GetSubset(); for (auto entity : audioSubset) { const auto& [audioComponent, transformComponent] = audioSubset.Get(entity); diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 4fc24ab2d..14032a376 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -157,27 +157,23 @@ namespace Atlas::Scene { } - void SceneRenderState::UpdateMeshBindlessData() { + void SceneRenderState::UpdateBlasBindlessData() { - auto bindlessMeshBuffersUpdate = [&](JobData&) { - JobSystem::Wait(bindlessMeshMapUpdateJob); + auto bindlessBlasBuffersUpdate = [&](JobData&) { + JobSystem::Wait(bindlessBlasMapUpdateJob); - if (blasBuffers.size() != meshIdToBindlessIdx.size()) { - blasBuffers.resize(meshIdToBindlessIdx.size()); - triangleBuffers.resize(meshIdToBindlessIdx.size()); - bvhTriangleBuffers.resize(meshIdToBindlessIdx.size()); - triangleOffsetBuffers.resize(meshIdToBindlessIdx.size()); + if (blasBuffers.size() != blasToBindlessIdx.size()) { + blasBuffers.resize(blasToBindlessIdx.size()); + triangleBuffers.resize(blasToBindlessIdx.size()); + bvhTriangleBuffers.resize(blasToBindlessIdx.size()); + triangleOffsetBuffers.resize(blasToBindlessIdx.size()); } - for (const auto& [meshId, idx] : meshIdToBindlessIdx) { - if (!scene->registeredMeshes.contains(meshId)) continue; - - const auto& mesh = scene->registeredMeshes[meshId].resource; - - auto blasBuffer = mesh->blasNodeBuffer.Get(); - auto triangleBuffer = mesh->triangleBuffer.Get(); - auto bvhTriangleBuffer = mesh->bvhTriangleBuffer.Get(); - auto triangleOffsetBuffer = mesh->triangleOffsetBuffer.Get(); + for (const auto& [blas, idx] : blasToBindlessIdx) { + auto blasBuffer = blas->blasNodeBuffer.Get(); + auto triangleBuffer = blas->triangleBuffer.Get(); + auto bvhTriangleBuffer = blas->bvhTriangleBuffer.Get(); + auto triangleOffsetBuffer = blas->triangleOffsetBuffer.Get(); AE_ASSERT(triangleBuffer != nullptr); @@ -188,28 +184,29 @@ namespace Atlas::Scene { } }; - auto bindlessMeshMapUpdate = [&, bindlessMeshBuffersUpdate](JobData&) { + auto bindlessBlasMapUpdate = [&, bindlessBlasBuffersUpdate](JobData&) { auto meshes = scene->GetMeshes(); - meshIdToBindlessIdx.clear(); + blasToBindlessIdx.clear(); uint32_t bufferIdx = 0; for (const auto& mesh : meshes) { if (!mesh.IsLoaded()) continue; // Not all meshes might have a bvh and not all blases will be built in frame, so skip them if they are not ready - if (!mesh->IsBVHBuilt() || mesh->IsBVHBuilt() && mesh->blas && !mesh->blas->isDynamic && !mesh->blas->isBuilt) + if (!mesh->IsBVHBuilt() || mesh->IsBVHBuilt() && mesh->blas->blas && + !mesh->blas->blas->isDynamic && !mesh->blas->blas->isBuilt) continue; - meshIdToBindlessIdx[mesh.GetID()] = bufferIdx++; + blasToBindlessIdx[mesh->blas] = bufferIdx++; } }; - JobSystem::Wait(bindlessMeshMapUpdateJob); - JobSystem::Wait(prepareBindlessMeshesJob); + JobSystem::Wait(bindlessBlasMapUpdateJob); + JobSystem::Wait(prepareBindlessBlasesJob); - JobSystem::Execute(bindlessMeshMapUpdateJob, bindlessMeshMapUpdate); - JobSystem::Execute(prepareBindlessMeshesJob, bindlessMeshBuffersUpdate); + JobSystem::Execute(bindlessBlasMapUpdateJob, bindlessBlasMapUpdate); + JobSystem::Execute(prepareBindlessBlasesJob, bindlessBlasBuffersUpdate); } @@ -569,12 +566,12 @@ namespace Atlas::Scene { // Assume scene work was done mainCameraSignal.Release(); - JobSystem::Wait(bindlessMeshMapUpdateJob); + JobSystem::Wait(bindlessBlasMapUpdateJob); JobSystem::Wait(bindlessTextureMapUpdateJob); JobSystem::Wait(bindlessOtherTextureMapUpdateJob); JobSystem::Wait(materialUpdateJob); JobSystem::Wait(rayTracingWorldUpdateJob); - JobSystem::Wait(prepareBindlessMeshesJob); + JobSystem::Wait(prepareBindlessBlasesJob); JobSystem::Wait(fillRenderListJob); JobSystem::Wait(cullAndSortLightsJob); diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index 44c42b629..fad72f7fb 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -31,7 +31,7 @@ namespace Atlas::Scene { void PrepareMaterials(); - void UpdateMeshBindlessData(); + void UpdateBlasBindlessData(); void UpdateTextureBindlessData(); @@ -64,7 +64,7 @@ namespace Atlas::Scene { std::unordered_map, uint32_t> textureToBindlessIdx; std::unordered_map, uint32_t> textureArrayToBindlessIdx; std::unordered_map, uint32_t> cubemapToBindlessIdx; - std::unordered_map meshIdToBindlessIdx; + std::unordered_map, uint32_t> blasToBindlessIdx; std::vector lightEntities; std::vector lights; @@ -75,10 +75,10 @@ namespace Atlas::Scene { JobGroup materialUpdateJob{ JobPriority::High }; JobGroup rayTracingWorldUpdateJob{ JobPriority::High }; - JobGroup bindlessMeshMapUpdateJob{ JobPriority::High }; + JobGroup bindlessBlasMapUpdateJob{ JobPriority::High }; JobGroup bindlessTextureMapUpdateJob{ JobPriority::High }; JobGroup bindlessOtherTextureMapUpdateJob{ JobPriority::High }; - JobGroup prepareBindlessMeshesJob{ JobPriority::High }; + JobGroup prepareBindlessBlasesJob{ JobPriority::High }; JobGroup fillRenderListJob{ JobPriority::High }; JobGroup cullAndSortLightsJob{ JobPriority::High }; diff --git a/src/engine/terrain/TerrainStorageCell.cpp b/src/engine/terrain/TerrainStorageCell.cpp index b557bce97..8d586506f 100644 --- a/src/engine/terrain/TerrainStorageCell.cpp +++ b/src/engine/terrain/TerrainStorageCell.cpp @@ -23,6 +23,76 @@ namespace Atlas { } + void TerrainStorageCell::BuildBVH() { + + if (!IsLoaded()) return; + + int32_t heightFieldSideLength = int32_t(sqrtf(float(heightData.size()))); + + std::vector vertices(heightData.size()); + for (int32_t y = 0; y < heightFieldSideLength; y++) { + for (int32_t x = 0; x < heightFieldSideLength; x++) { + auto idx = y * heightFieldSideLength + x; + vertices[idx] = vec3(float(x), heightData[idx], float(y)); + } + } + + auto vertexSideCount = heightFieldSideLength - 1; + + std::vector indices(vertexSideCount * vertexSideCount * 6); + for (int32_t y = 0; y < vertexSideCount; y++) { + for (int32_t x = 0; x < vertexSideCount; x++) { + auto idx = y * vertexSideCount + x; + auto baseIdx = (y * vertexSideCount + x) * 6; + + indices[baseIdx + 0] = idx; + indices[baseIdx + 1] = idx + 1; + indices[baseIdx + 2] = idx + heightFieldSideLength; + + indices[baseIdx + 3] = idx + 1; + indices[baseIdx + 4] = idx + heightFieldSideLength + 1; + indices[baseIdx + 5] = idx + heightFieldSideLength; + } + } + + Buffer::IndexBuffer indexBuffer(VK_INDEX_TYPE_UINT32, indices.size(), indices.data()); + Buffer::VertexBuffer vertexBuffer(VK_FORMAT_R32G32B32_SFLOAT, vertices.size(), vertices.data()); + + auto material = ResourceHandle(CreateRef()); + + std::vector triangles(indices.size() / 3); + for (size_t i = 0; i < triangles.size(); i++) { + + RayTracing::BLAS::Triangle triangle; + + triangle.v0 = vertices[indices[i * 3 + 0]]; + triangle.v1 = vertices[indices[i * 3 + 1]]; + triangle.v2 = vertices[indices[i * 3 + 2]]; + + vec3 normal = glm::normalize(glm::cross(triangle.v0 - triangle.v1, triangle.v0 - triangle.v2)); + + triangle.n0 = normal; + triangle.n1 = normal; + triangle.n2 = normal; + + triangle.materialIdx = 0; + + triangles[i] = triangle; + } + + Graphics::ASGeometryRegion geometryRegions[] = {{ + .indexCount = indices.size(), + .indexOffset = 0, + .opaque = false + }}; + + std::vector> materials = { material }; + + blas = CreateRef(); + blas->Build(triangles, materials, vertexBuffer, indexBuffer, geometryRegions); + + } + } } \ No newline at end of file diff --git a/src/engine/terrain/TerrainStorageCell.h b/src/engine/terrain/TerrainStorageCell.h index dbf3f7213..75e08fe18 100644 --- a/src/engine/terrain/TerrainStorageCell.h +++ b/src/engine/terrain/TerrainStorageCell.h @@ -3,6 +3,7 @@ #include "../System.h" #include "../Material.h" #include "../physics/ShapesManager.h" +#include "../raytracing/BLAS.h" #include @@ -23,6 +24,8 @@ namespace Atlas { bool IsLoaded(); + void BuildBVH(); + int32_t x = 0; int32_t y = 0; int32_t LoD = 0; @@ -30,6 +33,7 @@ namespace Atlas { vec2 position; Physics::ShapeRef shape; + Ref blas; std::vector heightData; From 5aafefd5e566aea54fb70131a86c08d31b79584c Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 26 Oct 2024 15:47:02 +0200 Subject: [PATCH 59/66] More chaanges --- src/engine/raytracing/BLAS.cpp | 1 - src/engine/raytracing/RayTracingWorld.cpp | 172 +++++++++++++++------- src/engine/raytracing/RayTracingWorld.h | 17 ++- src/engine/scene/SceneRenderState.cpp | 19 ++- src/engine/scene/SceneRenderState.h | 1 + src/engine/terrain/Terrain.h | 2 +- src/engine/terrain/TerrainStorageCell.cpp | 6 + src/engine/terrain/TerrainStorageCell.h | 4 + 8 files changed, 159 insertions(+), 63 deletions(-) diff --git a/src/engine/raytracing/BLAS.cpp b/src/engine/raytracing/BLAS.cpp index c0cb6f196..13fa173ca 100644 --- a/src/engine/raytracing/BLAS.cpp +++ b/src/engine/raytracing/BLAS.cpp @@ -21,7 +21,6 @@ namespace Atlas::RayTracing { BuildBuffers(triangles, materials); - if (hardwareRayTracing) { Graphics::ASBuilder asBuilder; diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index deb93fa00..4621078cb 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -41,63 +41,85 @@ namespace Atlas { auto renderState = &scene->renderState; blases.clear(); + buildBlases.clear(); auto meshes = scene->GetMeshes(); int32_t meshCount = 0; JobSystem::Wait(renderState->bindlessBlasMapUpdateJob); - std::swap(prevMeshInfos, meshInfos); - meshInfos.clear(); + std::swap(prevBlasInfos, blasInfos); + blasInfos.clear(); for (auto& mesh : meshes) { // Only need to check for this, since that means that the BVH was built and the mesh is loaded if (!renderState->blasToBindlessIdx.contains(mesh->blas)) continue; - if (!prevMeshInfos.contains(mesh.GetID())) { - meshInfos[mesh.GetID()] = {}; + if (!prevBlasInfos.contains(mesh->blas)) { + blasInfos[mesh->blas] = {}; BuildTriangleLightsForMesh(mesh); } else { - meshInfos[mesh.GetID()] = prevMeshInfos[mesh.GetID()]; + blasInfos[mesh->blas] = prevBlasInfos[mesh->blas]; } - auto &meshInfo = meshInfos[mesh.GetID()]; - meshInfo.offset = int32_t(renderState->blasToBindlessIdx[mesh->blas]); - meshInfo.cullingDistanceSqr = mesh->rayTraceDistanceCulling * mesh->rayTraceDistanceCulling; + auto &blasInfo = blasInfos[mesh->blas]; + blasInfo.offset = int32_t(renderState->blasToBindlessIdx[mesh->blas]); + blasInfo.cullingDistanceSqr = mesh->rayTraceDistanceCulling * mesh->rayTraceDistanceCulling; + + blases.push_back(mesh->blas); // Some extra path for hardware raytracing, don't want to do work twice if (hardwareRayTracing) { if (mesh->blas->needsBvhRefresh && mesh->blas->blas->isDynamic) { - blases.push_back(mesh->blas->blas); + buildBlases.push_back(mesh->blas->blas); mesh->blas->needsBvhRefresh = false; } - meshInfo.blas = mesh->blas->blas; - meshInfo.idx = meshCount++; + blasInfo.idx = meshCount++; + } + } + + for (const auto node : renderState->terrainLeafNodes) { + + if (!node->cell || !node->cell->IsLoaded() || !renderState->blasToBindlessIdx.contains(node->cell->blas)) + continue; + + if (!prevBlasInfos.contains(node->cell->blas)) { + blasInfos[node->cell->blas] = {}; + + } + else { + blasInfos[node->cell->blas] = prevBlasInfos[node->cell->blas]; } + + auto &blasInfo = blasInfos[node->cell->blas]; + blasInfo.offset = int32_t(renderState->blasToBindlessIdx[node->cell->blas]); + blasInfo.cullingDistanceSqr = 100000000000.0f; + + blases.push_back(node->cell->blas); } if (hardwareRayTracing) { Graphics::ASBuilder asBuilder; - if (!blases.empty()) { + if (!buildBlases.empty()) { auto commandList = device->GetCommandList(); commandList->BeginCommands(); - asBuilder.BuildBLAS(blases, commandList); + asBuilder.BuildBLAS(buildBlases, commandList); commandList->EndCommands(); device->SubmitCommandList(commandList); } } - for (auto& [_, meshInfo] : meshInfos) { - meshInfo.instanceIndices.clear(); - meshInfo.matrices.clear(); + for (auto& [_, blasInfo] : blasInfos) { + blasInfo.instanceIndices.clear(); + blasInfo.matrices.clear(); } hardwareInstances.clear(); gpuBvhInstances.clear(); - actorAABBs.clear(); + instanceAABBs.clear(); lastMatrices.clear(); JobSystem::Wait(renderState->bindlessTextureMapUpdateJob); @@ -119,16 +141,16 @@ namespace Atlas { if (!renderState->blasToBindlessIdx.contains(meshComponent.mesh->blas)) continue; - auto &meshInfo = meshInfos[meshComponent.mesh.GetID()]; + auto &blasInfo = blasInfos[meshComponent.mesh->blas]; auto distSqd = glm::distance2( vec3(transformComponent.globalMatrix[3]), cameraLocation); - if (hasCamera && distSqd > meshInfo.cullingDistanceSqr) + if (hasCamera && distSqd > blasInfo.cullingDistanceSqr) continue; if (hardwareRayTracing && !meshComponent.mesh->blas->blas->isBuilt || meshComponent.mesh->blas->needsBvhRefresh) continue; - actorAABBs.push_back(meshComponent.aabb); + instanceAABBs.push_back(meshComponent.aabb); auto inverseMatrix = mat3x4(glm::transpose(transformComponent.inverseGlobalMatrix)); uint32_t mask = InstanceCullMasks::MaskAll; @@ -136,13 +158,13 @@ namespace Atlas { GPUBVHInstance gpuBvhInstance = { .inverseMatrix = inverseMatrix, - .meshOffset = meshInfo.offset, - .materialOffset = meshInfo.materialOffset, + .meshOffset = blasInfo.offset, + .materialOffset = blasInfo.materialOffset, .mask = mask }; - meshInfo.matrices.emplace_back(transformComponent.globalMatrix); - meshInfo.instanceIndices.push_back(uint32_t(gpuBvhInstances.size())); + blasInfo.matrices.emplace_back(transformComponent.globalMatrix); + blasInfo.instanceIndices.push_back(uint32_t(gpuBvhInstances.size())); gpuBvhInstances.push_back(gpuBvhInstance); if (includeObjectHistory) @@ -157,7 +179,7 @@ namespace Atlas { std::memcpy(&transform, &transposed, sizeof(VkTransformMatrixKHR)); inst.transform = transform; - inst.instanceCustomIndex = meshInfo.offset; + inst.instanceCustomIndex = blasInfo.offset; inst.accelerationStructureReference = meshComponent.mesh->blas->blas->bufferDeviceAddress; inst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; inst.mask = mask; @@ -166,11 +188,58 @@ namespace Atlas { } } - if (scene->terrain) { - for (auto node : scene->terrain->renderList) { + for (const auto node : renderState->terrainLeafNodes) { + if (!node->cell || !node->cell->IsLoaded() || !renderState->blasToBindlessIdx.contains(node->cell->blas)) + continue; + + auto &blasInfo = blasInfos[node->cell->blas]; + if (hardwareRayTracing && !node->cell->blas->blas->isBuilt || node->cell->blas->needsBvhRefresh) + continue; + + float nodeStretch = node->sideLength; + float hideStretch = scene->terrain->heightScale; + + vec3 nodeScale = vec3(nodeStretch / 64.0f, hideStretch, nodeStretch / 64.0f); + + auto nodePosition = vec3(node->location.x, 0.0f, node->location.y); + mat4 globalMatrix = glm::translate(glm::scale(nodeScale), nodePosition); + mat4 inverseGlobalMatrix = glm::inverse(globalMatrix); + + instanceAABBs.push_back(node->cell->aabb.Transform(globalMatrix)); + auto inverseMatrix = mat3x4(glm::transpose(inverseGlobalMatrix)); + + uint32_t mask = InstanceCullMasks::MaskAll; + mask |= InstanceCullMasks::MaskShadow; + + GPUBVHInstance gpuBvhInstance = { + .inverseMatrix = inverseMatrix, + .meshOffset = blasInfo.offset, + .materialOffset = blasInfo.materialOffset, + .mask = mask + }; + + blasInfo.matrices.emplace_back(globalMatrix); + blasInfo.instanceIndices.push_back(uint32_t(gpuBvhInstances.size())); + gpuBvhInstances.push_back(gpuBvhInstance); + + if (includeObjectHistory) + lastMatrices.emplace_back(glm::transpose(globalMatrix)); + // Some extra path for hardware raytracing, don't want to do work twice + if (hardwareRayTracing) { + VkAccelerationStructureInstanceKHR inst = {}; + VkTransformMatrixKHR transform; + auto transposed = glm::transpose(globalMatrix); + std::memcpy(&transform, &transposed, sizeof(VkTransformMatrixKHR)); + inst.transform = transform; + inst.instanceCustomIndex = blasInfo.offset; + inst.accelerationStructureReference = node->cell->blas->blas->bufferDeviceAddress; + inst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + inst.mask = mask; + inst.instanceShaderBindingTableRecordOffset = 0; + hardwareInstances.push_back(inst); } } @@ -184,7 +253,7 @@ namespace Atlas { UpdateForHardwareRayTracing(subset, gpuBvhInstances.size()); } else { - UpdateForSoftwareRayTracing(gpuBvhInstances, lastMatrices, actorAABBs); + UpdateForSoftwareRayTracing(gpuBvhInstances, lastMatrices, instanceAABBs); } if (updateTriangleLights) @@ -219,25 +288,24 @@ namespace Atlas { auto meshes = scene->GetMeshes(); materials.clear(); - for (auto& mesh : meshes) { - if (!meshInfos.contains(mesh.GetID()) || !mesh.IsLoaded()) - continue; - - auto& meshInfo = meshInfos[mesh.GetID()]; - meshInfo.materialOffset = int32_t(materials.size()); + for (auto& [blas, blasInfo] : blasInfos) { + blasInfo.materialOffset = int32_t(materials.size()); int32_t meshMaterialID = 0; - for (auto& material : mesh->data.materials) { + for (auto& material : blas->materials) { GPUMaterial gpuMaterial; - size_t hash = mesh.GetID(); + size_t hash = 0; + HashCombine(hash, blas.get()); HashCombine(hash, meshMaterialID++); // Only is persistent when no materials are reorderd in mesh gpuMaterial.ID = int32_t(hash % 65535); if (material.IsLoaded()) { + auto& mesh = blasInfo.mesh; + gpuMaterial.baseColor = Common::ColorConverter::ConvertSRGBToLinear(material->baseColor); gpuMaterial.emissiveColor = Common::ColorConverter::ConvertSRGBToLinear(material->emissiveColor) * material->emissiveIntensity; @@ -254,9 +322,9 @@ namespace Atlas { gpuMaterial.tiling = material->tiling; - gpuMaterial.invertUVs = mesh->invertUVs ? 1 : 0; + gpuMaterial.invertUVs = mesh.IsLoaded() ? (mesh->invertUVs ? 1 : 0) : 0; gpuMaterial.twoSided = material->twoSided ? 1 : 0; - gpuMaterial.cullBackFaces = mesh->cullBackFaces ? 1 : 0; + gpuMaterial.cullBackFaces = mesh.IsLoaded() ? (mesh->cullBackFaces ? 1 : 0) : 0; gpuMaterial.useVertexColors = material->vertexColors ? 1 : 0; if (material->HasBaseColorMap()) { @@ -292,6 +360,10 @@ namespace Atlas { } } + for (const auto node : sceneState->terrainLeafNodes) { + + } + if (materials.empty()) return; @@ -306,7 +378,7 @@ namespace Atlas { void RayTracingWorld::Clear() { - meshInfos.clear(); + blasInfos.clear(); } @@ -314,14 +386,14 @@ namespace Atlas { auto device = Graphics::GraphicsDevice::DefaultDevice; - return materialBuffer.GetSize() > 0 && device->support.bindless && !meshInfos.empty(); + return materialBuffer.GetSize() > 0 && device->support.bindless && !blasInfos.empty(); } void RayTracingWorld::UpdateForSoftwareRayTracing(std::vector& gpuBvhInstances, - std::vector& lastMatrices, std::vector& actorAABBs) { + std::vector& lastMatrices, std::vector& instanceAABBs) { - auto bvh = Volume::BVH(actorAABBs); + auto bvh = Volume::BVH(instanceAABBs); auto& nodes = bvh.GetTree(); auto gpuBvhNodes = std::vector(nodes.size()); @@ -378,8 +450,8 @@ namespace Atlas { auto& gpuTriangles = mesh->blas->gpuTriangles; auto& materials = mesh->blas->materials; - auto& meshInfo = meshInfos[mesh.GetID()]; - meshInfo.triangleLights.clear(); + auto& blasInfo = blasInfos[mesh->blas]; + blasInfo.triangleLights.clear(); // Triangle lights for (size_t i = 0; i < gpuTriangles.size(); i++) { @@ -423,7 +495,7 @@ namespace Atlas { light.color = vec4(Common::ColorConverter::ConvertSRGBToLinear(radiance) * material->emissiveIntensity, 0.0f); light.data = vec4(cd, weight, 0.0, 0.0f); - meshInfo.triangleLights.push_back(light); + blasInfo.triangleLights.push_back(light); } } @@ -433,14 +505,14 @@ namespace Atlas { triangleLights.clear(); - for (auto& [meshIdx, meshInfo] : meshInfos) { + for (auto& [meshIdx, blasInfo] : blasInfos) { - for (auto& light : meshInfo.triangleLights) { + for (auto& light : blasInfo.triangleLights) { - for (size_t i = 0; i < meshInfo.instanceIndices.size(); i++) { + for (size_t i = 0; i < blasInfo.instanceIndices.size(); i++) { - auto instanceIdx = meshInfo.instanceIndices[i]; - auto& matrix = meshInfo.matrices[i]; + auto instanceIdx = blasInfo.instanceIndices[i]; + auto& matrix = blasInfo.matrices[i]; vec3 P = matrix * vec4(vec3(light.P), 1.0f); vec3 N = matrix * vec4(vec3(light.N), 0.0f); diff --git a/src/engine/raytracing/RayTracingWorld.h b/src/engine/raytracing/RayTracingWorld.h index 18810abcf..689b7aca4 100644 --- a/src/engine/raytracing/RayTracingWorld.h +++ b/src/engine/raytracing/RayTracingWorld.h @@ -3,6 +3,7 @@ #include "System.h" #include "RTStructures.h" +#include "BLAS.h" #include "scene/Subset.h" #include "scene/components/MeshComponent.h" @@ -47,8 +48,8 @@ namespace Atlas { bool includeObjectHistory = false; private: - struct MeshInfo { - Ref blas = nullptr; + struct BlasInfo { + ResourceHandle mesh; int32_t offset = 0; int32_t materialOffset = 0; @@ -65,7 +66,7 @@ namespace Atlas { void UpdateMaterials(std::vector& materials); void UpdateForSoftwareRayTracing(std::vector& gpuBvhInstances, - std::vector& lastMatrices, std::vector& actorAABBs); + std::vector& lastMatrices, std::vector& instanceAABBs); void UpdateForHardwareRayTracing(Scene::Subset& entitySubset, size_t instanceCount); @@ -77,7 +78,9 @@ namespace Atlas { Scene::Scene* scene; Ref tlas; - std::vector> blases; + + std::vector> blases; + std::vector> buildBlases; Buffer::Buffer materialBuffer; Buffer::Buffer bvhInstanceBuffer; @@ -86,13 +89,13 @@ namespace Atlas { std::vector hardwareInstances; std::vector gpuBvhInstances; - std::vector actorAABBs; + std::vector instanceAABBs; std::vector lastMatrices; std::vector triangleLights; - std::unordered_map meshInfos; - std::unordered_map prevMeshInfos; + std::unordered_map, BlasInfo> blasInfos; + std::unordered_map, BlasInfo> prevBlasInfos; std::vector materials; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 14032a376..58197240c 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -159,6 +159,13 @@ namespace Atlas::Scene { void SceneRenderState::UpdateBlasBindlessData() { + terrainLeafNodes.clear(); + if (scene->terrain) { + auto& leafNodes = scene->terrain->leafList; + terrainLeafNodes.reserve(leafNodes.size()); + std::copy(leafNodes.begin(), leafNodes.end(), std::back_inserter(terrainLeafNodes)); + } + auto bindlessBlasBuffersUpdate = [&](JobData&) { JobSystem::Wait(bindlessBlasMapUpdateJob); @@ -200,6 +207,14 @@ namespace Atlas::Scene { blasToBindlessIdx[mesh->blas] = bufferIdx++; } + + for (const auto leafNode : terrainLeafNodes) { + auto leafCell = leafNode->cell; + if (!leafCell || !leafCell->IsLoaded() || !leafCell->blas || !leafCell->blas->IsBuilt()) + continue; + + blasToBindlessIdx[leafCell->blas] = bufferIdx++; + } }; JobSystem::Wait(bindlessBlasMapUpdateJob); @@ -462,10 +477,6 @@ namespace Atlas::Scene { auto matrix = cascade->projectionMatrix * cascade->viewMatrix * camera.invViewMatrix; shadowUniform.cascades[i].cascadeSpace = glm::transpose(matrix); - - mat4 reTransposed = mat4(glm::transpose(shadowUniform.cascades[i].cascadeSpace)); - - AE_ASSERT(reTransposed == matrix); } shadowUniform.cascades[i].texelSize = texelSize; } diff --git a/src/engine/scene/SceneRenderState.h b/src/engine/scene/SceneRenderState.h index fad72f7fb..c44fd3ba0 100644 --- a/src/engine/scene/SceneRenderState.h +++ b/src/engine/scene/SceneRenderState.h @@ -59,6 +59,7 @@ namespace Atlas::Scene { std::vector> bvhTriangleBuffers; std::vector> triangleOffsetBuffers; + std::vector terrainLeafNodes; std::vector materials; std::unordered_map materialMap; std::unordered_map, uint32_t> textureToBindlessIdx; diff --git a/src/engine/terrain/Terrain.h b/src/engine/terrain/Terrain.h index a355af912..b9d56e8f7 100644 --- a/src/engine/terrain/Terrain.h +++ b/src/engine/terrain/Terrain.h @@ -171,6 +171,7 @@ namespace Atlas { Buffer::VertexArray vertexArray; Buffer::VertexArray distanceVertexArray; std::vector renderList; + std::vector leafList; Common::Image LoDImage; @@ -194,7 +195,6 @@ namespace Atlas { std::vector LoDDistances; std::vector rootNodes; - std::vector leafList; }; diff --git a/src/engine/terrain/TerrainStorageCell.cpp b/src/engine/terrain/TerrainStorageCell.cpp index 8d586506f..50a07d3bc 100644 --- a/src/engine/terrain/TerrainStorageCell.cpp +++ b/src/engine/terrain/TerrainStorageCell.cpp @@ -29,11 +29,17 @@ namespace Atlas { int32_t heightFieldSideLength = int32_t(sqrtf(float(heightData.size()))); + aabb.min = glm::vec3(std::numeric_limits::max()); + aabb.max = glm::vec3(-std::numeric_limits::max()); + std::vector vertices(heightData.size()); for (int32_t y = 0; y < heightFieldSideLength; y++) { for (int32_t x = 0; x < heightFieldSideLength; x++) { auto idx = y * heightFieldSideLength + x; vertices[idx] = vec3(float(x), heightData[idx], float(y)); + + aabb.min = glm::min(aabb.min, vertices[idx]); + aabb.max = glm::max(aabb.max, vertices[idx]); } } diff --git a/src/engine/terrain/TerrainStorageCell.h b/src/engine/terrain/TerrainStorageCell.h index 75e08fe18..bdb524cca 100644 --- a/src/engine/terrain/TerrainStorageCell.h +++ b/src/engine/terrain/TerrainStorageCell.h @@ -4,6 +4,7 @@ #include "../Material.h" #include "../physics/ShapesManager.h" #include "../raytracing/BLAS.h" +#include "../volume/AABB.h" #include @@ -32,6 +33,9 @@ namespace Atlas { vec2 position; + Volume::AABB aabb; + mat3x4 inverseMatrix; + Physics::ShapeRef shape; Ref blas; From 33760ea146304934a1bdf3873c7af5ee2f7ebbef Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 26 Oct 2024 19:29:34 +0200 Subject: [PATCH 60/66] More changes --- src/engine/loader/TerrainLoader.cpp | 1 + src/engine/raytracing/RayTracingWorld.cpp | 21 ++++++------ src/engine/scene/Scene.cpp | 6 ++-- src/engine/scene/SceneRenderState.cpp | 10 ++++++ src/engine/terrain/TerrainStorage.h | 6 ++-- src/engine/terrain/TerrainStorageCell.cpp | 40 ++++++++++++++++++----- src/engine/terrain/TerrainStorageCell.h | 5 ++- 7 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/engine/loader/TerrainLoader.cpp b/src/engine/loader/TerrainLoader.cpp index a456f03d3..b0866df23 100644 --- a/src/engine/loader/TerrainLoader.cpp +++ b/src/engine/loader/TerrainLoader.cpp @@ -272,6 +272,7 @@ namespace Atlas { cell->splatMap = Texture::Texture2D(tileResolution, tileResolution, VK_FORMAT_R8_UINT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); cell->splatMap.SetData(splatMapData); + cell->materialIdxData = splatMapData; if (initWithHeightData) { cell->heightData.resize(tileResolution * tileResolution); diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index 4621078cb..a54d1add2 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -87,8 +87,7 @@ namespace Atlas { continue; if (!prevBlasInfos.contains(node->cell->blas)) { - blasInfos[node->cell->blas] = {}; - + blasInfos[node->cell->blas] = {}; } else { blasInfos[node->cell->blas] = prevBlasInfos[node->cell->blas]; @@ -196,16 +195,21 @@ namespace Atlas { if (hardwareRayTracing && !node->cell->blas->blas->isBuilt || node->cell->blas->needsBvhRefresh) continue; - float nodeStretch = node->sideLength; + float nodeStretch = scene->terrain->resolution * powf(2.0f, + (float)(scene->terrain->LoDCount - node->cell->LoD) - 1.0f); float hideStretch = scene->terrain->heightScale; - vec3 nodeScale = vec3(nodeStretch / 64.0f, hideStretch, nodeStretch / 64.0f); + vec3 nodeScale = vec3(nodeStretch, hideStretch, nodeStretch); auto nodePosition = vec3(node->location.x, 0.0f, node->location.y); - mat4 globalMatrix = glm::translate(glm::scale(nodeScale), nodePosition); + mat4 globalMatrix = glm::scale(glm::translate(nodePosition), nodeScale); mat4 inverseGlobalMatrix = glm::inverse(globalMatrix); - instanceAABBs.push_back(node->cell->aabb.Transform(globalMatrix)); + auto aabb = node->cell->aabb.Scale(nodeScale); + vec3 halfSize = aabb.GetSize() * 0.5f; + + Volume::AABB testaabb(vec3( - 2000.0f), vec3(2000.0f)); + instanceAABBs.push_back(testaabb); auto inverseMatrix = mat3x4(glm::transpose(inverseGlobalMatrix)); uint32_t mask = InstanceCullMasks::MaskAll; @@ -285,7 +289,6 @@ namespace Atlas { auto sceneState = &scene->renderState; - auto meshes = scene->GetMeshes(); materials.clear(); for (auto& [blas, blasInfo] : blasInfos) { @@ -360,10 +363,6 @@ namespace Atlas { } } - for (const auto node : sceneState->terrainLeafNodes) { - - } - if (materials.empty()) return; diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index fbd3fd9fa..272648b45 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -408,10 +408,6 @@ namespace Atlas { auto& mainCamera = mainCameraEntity.GetComponent(); - if (terrain) { - terrain->Update(mainCamera); - } - auto audioSubset = entityManager.GetSubset(); for (auto entity : audioSubset) { const auto& [audioComponent, transformComponent] = audioSubset.Get(entity); @@ -437,6 +433,8 @@ namespace Atlas { renderState.FillRenderList(); renderState.CullAndSortLights(); + JobSystem::WaitSpin(renderState.rayTracingWorldUpdateJob); + if (terrain) { terrain->Update(mainCamera); } diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 58197240c..ef6dd2faf 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -244,6 +244,16 @@ namespace Atlas::Scene { materialSet.insert(material.Get()); } + for (const auto leafNode : terrainLeafNodes) { + auto leafCell = leafNode->cell; + if (!leafCell || !leafCell->IsLoaded() || !leafCell->blas || !leafCell->blas->IsBuilt()) + continue; + + for (auto& material : leafCell->blas->materials) + if (material.IsLoaded()) + materialSet.insert(material.Get()); + } + for (const auto& material : materialSet) { if (material->HasBaseColorMap()) textureSet.insert(material->baseColorMap.Get()); diff --git a/src/engine/terrain/TerrainStorage.h b/src/engine/terrain/TerrainStorage.h index 28ea4b52e..d57870254 100644 --- a/src/engine/terrain/TerrainStorage.h +++ b/src/engine/terrain/TerrainStorage.h @@ -95,6 +95,8 @@ namespace Atlas { Texture::Texture2DArray normalMaps; Texture::Texture2DArray displacementMaps; + std::vector> materials; + private: void BlitImageToImageArray(Ref& srcImage, Ref& dstImage, int32_t slot); @@ -105,9 +107,7 @@ namespace Atlas { int32_t materialResolution; int32_t materialCount; - int32_t* LoDSideLengths; - - std::vector> materials; + int32_t* LoDSideLengths; std::vector> cells; diff --git a/src/engine/terrain/TerrainStorageCell.cpp b/src/engine/terrain/TerrainStorageCell.cpp index 50a07d3bc..55540460f 100644 --- a/src/engine/terrain/TerrainStorageCell.cpp +++ b/src/engine/terrain/TerrainStorageCell.cpp @@ -48,7 +48,7 @@ namespace Atlas { std::vector indices(vertexSideCount * vertexSideCount * 6); for (int32_t y = 0; y < vertexSideCount; y++) { for (int32_t x = 0; x < vertexSideCount; x++) { - auto idx = y * vertexSideCount + x; + auto idx = y * heightFieldSideLength + x; auto baseIdx = (y * vertexSideCount + x) * 6; indices[baseIdx + 0] = idx; @@ -64,39 +64,63 @@ namespace Atlas { Buffer::IndexBuffer indexBuffer(VK_INDEX_TYPE_UINT32, indices.size(), indices.data()); Buffer::VertexBuffer vertexBuffer(VK_FORMAT_R32G32B32_SFLOAT, vertices.size(), vertices.data()); - auto material = ResourceHandle(CreateRef()); + std::vector> materials; + for (size_t i = 0; i < storage->materials.size(); i++) { + if (storage->materials[i] != nullptr) { + materials.push_back(ResourceHandle(storage->materials[i])); + materials.back()->twoSided = false; + } + else { + materials.push_back(ResourceHandle()); + } + + + } std::vector triangles(indices.size() / 3); for (size_t i = 0; i < triangles.size(); i++) { RayTracing::BLAS::Triangle triangle; - triangle.v0 = vertices[indices[i * 3 + 0]]; + triangle.v0 = vertices[indices[i * 3 + 2]]; triangle.v1 = vertices[indices[i * 3 + 1]]; - triangle.v2 = vertices[indices[i * 3 + 2]]; + triangle.v2 = vertices[indices[i * 3 + 0]]; - vec3 normal = glm::normalize(glm::cross(triangle.v0 - triangle.v1, triangle.v0 - triangle.v2)); + vec3 normal = -glm::normalize(glm::cross(triangle.v0 - triangle.v1, triangle.v0 - triangle.v2)); triangle.n0 = normal; triangle.n1 = normal; triangle.n2 = normal; - triangle.materialIdx = 0; + triangle.uv0 = vec2(triangle.v2.x, triangle.v2.z); + triangle.uv1 = vec2(triangle.v1.x, triangle.v1.z); + triangle.uv2 = vec2(triangle.v0.x, triangle.v0.z); + + triangle.materialIdx = int32_t(materialIdxData[indices[i * 3]]); triangles[i] = triangle; + } Graphics::ASGeometryRegion geometryRegions[] = {{ .indexCount = indices.size(), .indexOffset = 0, - .opaque = false + .opaque = true }}; - std::vector> materials = { material }; blas = CreateRef(); blas->Build(triangles, materials, vertexBuffer, indexBuffer, geometryRegions); + if (Graphics::GraphicsDevice::DefaultDevice->support.hardwareRayTracing) { + Graphics::ASBuilder asBuilder; + std::vector> blases = { blas->blas }; + asBuilder.BuildBLAS(blases); + + blas->blas = blases.front(); + blas->needsBvhRefresh = false; + } + } } diff --git a/src/engine/terrain/TerrainStorageCell.h b/src/engine/terrain/TerrainStorageCell.h index bdb524cca..2efcd6291 100644 --- a/src/engine/terrain/TerrainStorageCell.h +++ b/src/engine/terrain/TerrainStorageCell.h @@ -40,14 +40,13 @@ namespace Atlas { Ref blas; std::vector heightData; + std::vector materialIdxData; Texture::Texture2D heightField; Texture::Texture2D normalMap; Texture::Texture2D splatMap; - Texture::Texture2D diffuseMap; - private: - TerrainStorage* const storage; + TerrainStorage* storage = nullptr; }; From 7641cc7ab2b51bb5be6076a942d67b099c57cc69 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 26 Oct 2024 22:14:12 +0200 Subject: [PATCH 61/66] Fixed software raytracing issues --- src/engine/loader/TerrainLoader.cpp | 10 +++--- src/engine/loader/TerrainLoader.h | 6 ++-- src/engine/raytracing/BLAS.cpp | 3 +- src/engine/raytracing/BLAS.h | 4 +-- src/engine/raytracing/RayTracingManager.cpp | 35 ++++++++++++++++--- src/engine/raytracing/RayTracingManager.h | 5 ++- src/engine/raytracing/RayTracingWorld.cpp | 14 ++------ src/engine/renderer/OceanRenderer.cpp | 10 +++--- src/engine/renderer/TerrainRenderer.cpp | 8 ++--- src/engine/renderer/TerrainShadowRenderer.cpp | 4 +-- src/engine/scene/Scene.cpp | 4 +-- src/engine/scene/Scene.h | 9 ++--- src/engine/scene/SceneRenderState.cpp | 2 +- src/engine/terrain/TerrainStorage.h | 5 ++- src/engine/terrain/TerrainStorageCell.cpp | 14 ++++---- src/engine/terrain/TerrainStorageCell.h | 2 +- 16 files changed, 76 insertions(+), 59 deletions(-) diff --git a/src/engine/loader/TerrainLoader.cpp b/src/engine/loader/TerrainLoader.cpp index b0866df23..b2aef5e56 100644 --- a/src/engine/loader/TerrainLoader.cpp +++ b/src/engine/loader/TerrainLoader.cpp @@ -9,7 +9,7 @@ namespace Atlas { namespace Loader { - void TerrainLoader::SaveTerrain(Ref terrain, std::string filename) { + void TerrainLoader::SaveTerrain(Ref terrain, const std::string& filename) { auto fileStream = AssetLoader::WriteFile(filename, std::ios::out | std::ios::binary); @@ -111,7 +111,7 @@ namespace Atlas { } - Ref TerrainLoader::LoadTerrain(std::string filename) { + Ref TerrainLoader::LoadTerrain(const std::string& filename) { auto fileStream = AssetLoader::ReadFile(filename, std::ios::in); @@ -196,7 +196,7 @@ namespace Atlas { } void TerrainLoader::LoadStorageCell(Ref terrain, Terrain::TerrainStorageCell* cell, - std::string filename, bool initWithHeightData) { + const std::string& filename, bool initWithHeightData) { auto fileStream = AssetLoader::ReadFile(filename, std::ios::in | std::ios::binary); @@ -252,6 +252,8 @@ namespace Atlas { tileSideCount *= 2; } + cell->storage = &terrain->storage; + fileStream.seekg(currPos, std::ios_base::cur); std::vector heightFieldData(tileResolution * tileResolution); @@ -283,8 +285,6 @@ namespace Atlas { fileStream.close(); - cell->BuildBVH(); - } int32_t TerrainLoader::ReadInt(const char* ptr, std::string line, size_t& offset) { diff --git a/src/engine/loader/TerrainLoader.h b/src/engine/loader/TerrainLoader.h index 943bbe5ab..066fcd773 100644 --- a/src/engine/loader/TerrainLoader.h +++ b/src/engine/loader/TerrainLoader.h @@ -16,7 +16,7 @@ namespace Atlas { * @return * @note This method just loads the terrain information, not the nodes. */ - static Ref LoadTerrain(std::string filename); + static Ref LoadTerrain(const std::string& filename); /** * Stores the terrain in a directory on the hard drive @@ -24,7 +24,7 @@ namespace Atlas { * @param filename * @warning All storage cells of the terrain must be loaded. */ - static void SaveTerrain(Ref terrain, std::string filename); + static void SaveTerrain(Ref terrain, const std::string& filename); /** * @@ -34,7 +34,7 @@ namespace Atlas { * @param initWithHeightData */ static void LoadStorageCell(Ref terrain, Terrain::TerrainStorageCell* cell, - std::string filename, bool initWithHeightData = false); + const std::string& filename, bool initWithHeightData = false); private: static int32_t ReadInt(const char* ptr, std::string line, size_t& offset); diff --git a/src/engine/raytracing/BLAS.cpp b/src/engine/raytracing/BLAS.cpp index 13fa173ca..d4ed01085 100644 --- a/src/engine/raytracing/BLAS.cpp +++ b/src/engine/raytracing/BLAS.cpp @@ -82,7 +82,7 @@ namespace Atlas::RayTracing { Volume::BVH bvh; if (!hardwareRayTracing) { // Generate BVH - bvh = Volume::BVH(aabbs, bvhTriangles); + bvh = Volume::BVH(aabbs, bvhTriangles, false); bvhTriangles.clear(); bvhTriangles.shrink_to_fit(); @@ -100,7 +100,6 @@ namespace Atlas::RayTracing { if (!hardwareRayTracing) gpuBvhTriangles.reserve(triangleCount); - for (auto& bvhTriangle : data) { auto& triangle = triangles[bvhTriangle.idx]; diff --git a/src/engine/raytracing/BLAS.h b/src/engine/raytracing/BLAS.h index 4a61b8190..684ebda8b 100644 --- a/src/engine/raytracing/BLAS.h +++ b/src/engine/raytracing/BLAS.h @@ -33,8 +33,8 @@ namespace Atlas::RayTracing { vec4 color1; vec4 color2; - int32_t materialIdx; - float opacity; + int32_t materialIdx = 0; + float opacity = -1.0f; }; BLAS() = default; diff --git a/src/engine/raytracing/RayTracingManager.cpp b/src/engine/raytracing/RayTracingManager.cpp index a907c778f..b9e8bc69a 100644 --- a/src/engine/raytracing/RayTracingManager.cpp +++ b/src/engine/raytracing/RayTracingManager.cpp @@ -4,6 +4,7 @@ #include "graphics/ASBuilder.h" #include "resource/ResourceManager.h" #include "mesh/Mesh.h" +#include "terrain/Terrain.h" namespace Atlas::RayTracing { @@ -16,10 +17,10 @@ namespace Atlas::RayTracing { // This crashes when we start with path tracing and do the bvh build async // Launch BVH builds asynchronously auto buildRTStructure = [&](JobData) { - auto sceneMeshes = ResourceManager::GetResources(); + auto meshes = ResourceManager::GetResources(); JobGroup bvhBuildGroup; - for (const auto& mesh : sceneMeshes) { + for (const auto& mesh : meshes) { if (!mesh.IsLoaded()) continue; if (mesh->IsBVHBuilt() || !mesh->rayTrace) @@ -33,11 +34,36 @@ namespace Atlas::RayTracing { }); } + auto terrains = ResourceManager::GetResources(); + for (const auto& terrain : terrains) { + if (!terrain.IsLoaded()) + continue; + + auto& storage = terrain->storage; + for (int32_t i = 0; i < storage.cells.size(); i++) { + auto& lodCells = storage.cells[i]; + + for (auto& cell : lodCells) { + if (!cell.IsLoaded()) + continue; + if (cell.blas && cell.blas->IsBuilt()) + continue; + + float nodeStretch = terrain->resolution * powf(2.0f, + (float)(terrain->LoDCount - cell.LoD) - 1.0f); + float heightStretch = terrain->heightScale; + JobSystem::Execute(bvhBuildGroup, [cell = &cell, nodeStretch, heightStretch](JobData&) { + cell->BuildBVH(nodeStretch, heightStretch); + }); + } + } + } + JobSystem::Wait(bvhBuildGroup); auto device = Graphics::GraphicsDevice::DefaultDevice; if (device->support.hardwareRayTracing) - BuildStaticBLAS(sceneMeshes); + BuildStaticBLAS(meshes, terrains); }; if (bvhUpdateGroup.HasFinished()) { @@ -47,7 +73,8 @@ namespace Atlas::RayTracing { } - void RayTracingManager::BuildStaticBLAS(std::vector>& meshes) { + void RayTracingManager::BuildStaticBLAS(std::vector>& meshes, + std::vector>& terrains) { Graphics::ASBuilder asBuilder; diff --git a/src/engine/raytracing/RayTracingManager.h b/src/engine/raytracing/RayTracingManager.h index 337e5814c..77dc3180b 100644 --- a/src/engine/raytracing/RayTracingManager.h +++ b/src/engine/raytracing/RayTracingManager.h @@ -3,6 +3,8 @@ #include "../System.h" #include "jobsystem/JobGroup.h" #include "graphics/BLAS.h" + +#include "terrain/Terrain.h" #include "mesh/Mesh.h" namespace Atlas::RayTracing { @@ -13,7 +15,8 @@ namespace Atlas::RayTracing { static void Update(); private: - static void BuildStaticBLAS(std::vector>& meshes); + static void BuildStaticBLAS(std::vector>& meshes, + std::vector>& terrains); static JobGroup bvhUpdateGroup; static std::vector> blases; diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index a54d1add2..f1d2be8ce 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -195,21 +195,11 @@ namespace Atlas { if (hardwareRayTracing && !node->cell->blas->blas->isBuilt || node->cell->blas->needsBvhRefresh) continue; - float nodeStretch = scene->terrain->resolution * powf(2.0f, - (float)(scene->terrain->LoDCount - node->cell->LoD) - 1.0f); - float hideStretch = scene->terrain->heightScale; - - vec3 nodeScale = vec3(nodeStretch, hideStretch, nodeStretch); - auto nodePosition = vec3(node->location.x, 0.0f, node->location.y); - mat4 globalMatrix = glm::scale(glm::translate(nodePosition), nodeScale); + mat4 globalMatrix = glm::translate(nodePosition), nodeScale; mat4 inverseGlobalMatrix = glm::inverse(globalMatrix); - auto aabb = node->cell->aabb.Scale(nodeScale); - vec3 halfSize = aabb.GetSize() * 0.5f; - - Volume::AABB testaabb(vec3( - 2000.0f), vec3(2000.0f)); - instanceAABBs.push_back(testaabb); + instanceAABBs.push_back(node->cell->aabb.Translate(nodePosition)); auto inverseMatrix = mat3x4(glm::transpose(inverseGlobalMatrix)); uint32_t mask = InstanceCullMasks::MaskAll; diff --git a/src/engine/renderer/OceanRenderer.cpp b/src/engine/renderer/OceanRenderer.cpp index 51236c1fd..c45974dc1 100644 --- a/src/engine/renderer/OceanRenderer.cpp +++ b/src/engine/renderer/OceanRenderer.cpp @@ -211,7 +211,7 @@ namespace Atlas { if (cloudShadowsEnabled) config.AddMacro("CLOUD_SHADOWS"); if (ocean->rippleTexture.IsValid()) config.AddMacro("RIPPLE_TEXTURE"); if (ocean->foamTexture.IsValid()) config.AddMacro("FOAM_TEXTURE"); - if (scene->terrain && scene->terrain->shoreLine.IsValid()) config.AddMacro("TERRAIN"); + if (scene->terrain.IsLoaded() && scene->terrain->shoreLine.IsValid()) config.AddMacro("TERRAIN"); auto pipeline = PipelineManager::GetPipeline(config); @@ -273,7 +273,7 @@ namespace Atlas { depthTexture.Bind(commandList, 3, 5); target->oceanDepthTexture.Bind(commandList, 3, 20); - if (scene->terrain) { + if (scene->terrain.IsLoaded()) { if (scene->terrain->shoreLine.IsValid()) { auto terrain = scene->terrain; @@ -379,7 +379,7 @@ namespace Atlas { groupCount.x += ((res.x % groupSize == 0) ? 0 : 1); groupCount.y += ((res.y % groupSize == 0) ? 0 : 1); - underWaterPipelineConfig.ManageMacro("TERRAIN", scene->terrain && scene->terrain->shoreLine.IsValid()); + underWaterPipelineConfig.ManageMacro("TERRAIN", scene->terrain.IsLoaded() && scene->terrain->shoreLine.IsValid()); auto pipeline = PipelineManager::GetPipeline(underWaterPipelineConfig); commandList->BindPipeline(pipeline); @@ -424,7 +424,7 @@ namespace Atlas { target->oceanDepthOnlyFrameBuffer); auto config = GeneratePipelineConfig(target, true, ocean->wireframe); - if (scene->terrain && scene->terrain->shoreLine.IsValid()) config.AddMacro("TERRAIN"); + if (scene->terrain.IsLoaded() && scene->terrain->shoreLine.IsValid()) config.AddMacro("TERRAIN"); auto pipeline = PipelineManager::GetPipeline(config); @@ -475,7 +475,7 @@ namespace Atlas { refractionTexture.Bind(commandList, 3, 4); depthTexture.Bind(commandList, 3, 5); - if (scene->terrain) { + if (scene->terrain.IsLoaded()) { if (scene->terrain->shoreLine.IsValid()) { auto terrain = scene->terrain; diff --git a/src/engine/renderer/TerrainRenderer.cpp b/src/engine/renderer/TerrainRenderer.cpp index 5a44b0d64..b46c048a8 100644 --- a/src/engine/renderer/TerrainRenderer.cpp +++ b/src/engine/renderer/TerrainRenderer.cpp @@ -15,7 +15,7 @@ namespace Atlas { void TerrainRenderer::Render(Ref target, Ref scene, Graphics::CommandList* commandList, std::unordered_map materialMap) { - if (!scene->terrain) + if (!scene->terrain.IsLoaded()) return; Graphics::Profiler::BeginQuery("Terrain"); @@ -105,17 +105,17 @@ namespace Atlas { PipelineConfig config; switch (i) { - case 0: config = GeneratePipelineConfig(target, terrain, true, true); + case 0: config = GeneratePipelineConfig(target, terrain.Get(), true, true); terrain->vertexArray.Bind(commandList); Graphics::Profiler::BeginQuery("Detail with displacement"); nodes = detailDisplacementNodes; break; - case 1: config = GeneratePipelineConfig(target, terrain, false, true); + case 1: config = GeneratePipelineConfig(target, terrain.Get(), false, true); terrain->distanceVertexArray.Bind(commandList); Graphics::Profiler::BeginQuery("Detail"); nodes = detailNodes; break; - case 2: config = GeneratePipelineConfig(target, terrain, false, false); + case 2: config = GeneratePipelineConfig(target, terrain.Get(), false, false); terrain->distanceVertexArray.Bind(commandList); Graphics::Profiler::BeginQuery("Distance"); nodes = distanceNodes; diff --git a/src/engine/renderer/TerrainShadowRenderer.cpp b/src/engine/renderer/TerrainShadowRenderer.cpp index b30ca57bd..e62b96da1 100644 --- a/src/engine/renderer/TerrainShadowRenderer.cpp +++ b/src/engine/renderer/TerrainShadowRenderer.cpp @@ -13,7 +13,7 @@ namespace Atlas { void TerrainShadowRenderer::Render(Ref target, Ref scene, Graphics::CommandList* commandList) { - if (!scene->terrain) + if (!scene->terrain.IsLoaded()) return; Graphics::Profiler::BeginQuery("Terrain shadows"); @@ -54,7 +54,7 @@ namespace Atlas { commandList->BeginRenderPass(frameBuffer->renderPass, frameBuffer); - auto config = GeneratePipelineConfig(frameBuffer, terrain); + auto config = GeneratePipelineConfig(frameBuffer, terrain.Get()); auto pipeline = PipelineManager::GetPipeline(config); commandList->BindPipeline(pipeline); diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 272648b45..59ec4b579 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -435,7 +435,7 @@ namespace Atlas { JobSystem::WaitSpin(renderState.rayTracingWorldUpdateJob); - if (terrain) { + if (terrain.IsLoaded()) { terrain->Update(mainCamera); } @@ -463,7 +463,7 @@ namespace Atlas { std::vector> materials; - if (terrain) { + if (terrain.IsLoaded()) { auto terrainMaterials = terrain->storage.GetMaterials(); materials.reserve(terrainMaterials.size()); diff --git a/src/engine/scene/Scene.h b/src/engine/scene/Scene.h index 31a0e7479..5e9b6685f 100644 --- a/src/engine/scene/Scene.h +++ b/src/engine/scene/Scene.h @@ -130,12 +130,13 @@ namespace Atlas { static Ref Restore(const std::vector& serialized); std::string name; - - Ref ocean = nullptr; - Ref terrain = nullptr; + Ref clutter = nullptr; Ref physicsWorld = nullptr; - Ref rayTracingWorld = nullptr; + Ref rayTracingWorld = nullptr; + + Ref ocean = nullptr; + ResourceHandle terrain; Wind wind; Lighting::Sky sky; diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index ef6dd2faf..0e546e0fb 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -160,7 +160,7 @@ namespace Atlas::Scene { void SceneRenderState::UpdateBlasBindlessData() { terrainLeafNodes.clear(); - if (scene->terrain) { + if (scene->terrain.IsLoaded()) { auto& leafNodes = scene->terrain->leafList; terrainLeafNodes.reserve(leafNodes.size()); std::copy(leafNodes.begin(), leafNodes.end(), std::back_inserter(terrainLeafNodes)); diff --git a/src/engine/terrain/TerrainStorage.h b/src/engine/terrain/TerrainStorage.h index d57870254..0a8951282 100644 --- a/src/engine/terrain/TerrainStorage.h +++ b/src/engine/terrain/TerrainStorage.h @@ -96,6 +96,7 @@ namespace Atlas { Texture::Texture2DArray displacementMaps; std::vector> materials; + std::vector> cells; private: void BlitImageToImageArray(Ref& srcImage, @@ -107,9 +108,7 @@ namespace Atlas { int32_t materialResolution; int32_t materialCount; - int32_t* LoDSideLengths; - - std::vector> cells; + int32_t* LoDSideLengths; Graphics::CommandList* commandList = nullptr; diff --git a/src/engine/terrain/TerrainStorageCell.cpp b/src/engine/terrain/TerrainStorageCell.cpp index 55540460f..c37ae0053 100644 --- a/src/engine/terrain/TerrainStorageCell.cpp +++ b/src/engine/terrain/TerrainStorageCell.cpp @@ -23,7 +23,7 @@ namespace Atlas { } - void TerrainStorageCell::BuildBVH() { + void TerrainStorageCell::BuildBVH(float stretchFactor, float heightFactor) { if (!IsLoaded()) return; @@ -36,7 +36,7 @@ namespace Atlas { for (int32_t y = 0; y < heightFieldSideLength; y++) { for (int32_t x = 0; x < heightFieldSideLength; x++) { auto idx = y * heightFieldSideLength + x; - vertices[idx] = vec3(float(x), heightData[idx], float(y)); + vertices[idx] = vec3(float(x) * stretchFactor, heightData[idx] * heightFactor, float(y) * stretchFactor); aabb.min = glm::min(aabb.min, vertices[idx]); aabb.max = glm::max(aabb.max, vertices[idx]); @@ -61,8 +61,8 @@ namespace Atlas { } } - Buffer::IndexBuffer indexBuffer(VK_INDEX_TYPE_UINT32, indices.size(), indices.data()); - Buffer::VertexBuffer vertexBuffer(VK_FORMAT_R32G32B32_SFLOAT, vertices.size(), vertices.data()); + Buffer::IndexBuffer indexBuffer(VK_INDEX_TYPE_UINT32, indices.size(), indices.data(), true); + Buffer::VertexBuffer vertexBuffer(VK_FORMAT_R32G32B32_SFLOAT, vertices.size(), vertices.data(), true); std::vector> materials; for (size_t i = 0; i < storage->materials.size(); i++) { @@ -73,8 +73,6 @@ namespace Atlas { else { materials.push_back(ResourceHandle()); } - - } std::vector triangles(indices.size() / 3); @@ -88,6 +86,8 @@ namespace Atlas { vec3 normal = -glm::normalize(glm::cross(triangle.v0 - triangle.v1, triangle.v0 - triangle.v2)); + normal *= normal.y < 0.0f ? -1.0f : 1.0f; + triangle.n0 = normal; triangle.n1 = normal; triangle.n2 = normal; @@ -99,7 +99,6 @@ namespace Atlas { triangle.materialIdx = int32_t(materialIdxData[indices[i * 3]]); triangles[i] = triangle; - } Graphics::ASGeometryRegion geometryRegions[] = {{ @@ -108,7 +107,6 @@ namespace Atlas { .opaque = true }}; - blas = CreateRef(); blas->Build(triangles, materials, vertexBuffer, indexBuffer, geometryRegions); diff --git a/src/engine/terrain/TerrainStorageCell.h b/src/engine/terrain/TerrainStorageCell.h index 2efcd6291..6486abec4 100644 --- a/src/engine/terrain/TerrainStorageCell.h +++ b/src/engine/terrain/TerrainStorageCell.h @@ -25,7 +25,7 @@ namespace Atlas { bool IsLoaded(); - void BuildBVH(); + void BuildBVH(float stretchFactor, float heightFactor); int32_t x = 0; int32_t y = 0; From 8e9a4fc96fb8a3a0136068a92a0e382076e7c6a7 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 27 Oct 2024 14:11:38 +0100 Subject: [PATCH 62/66] Improvements and fixes --- data/shader/globals.hsh | 3 +- data/shader/pathtracer/rayHit.csh | 6 ++- data/shader/raytracer/structures.hsh | 8 ++-- data/shader/raytracer/surface.hsh | 13 ++++-- data/shader/raytracer/texture.hsh | 10 ++++ data/shader/reflection/rtreflection.csh | 4 +- data/shader/reflection/ssr.csh | 4 +- data/shader/reflection/temporal.csh | 4 +- data/shader/terrain/terrain.fsh | 32 ++++++------- data/shader/terrain/terrain.tesh | 10 ++-- src/engine/graphics/ASBuilder.cpp | 21 +++++---- src/engine/graphics/ASBuilder.h | 11 +++-- src/engine/loader/TerrainLoader.cpp | 20 ++++---- src/engine/raytracing/RTStructures.h | 2 + src/engine/raytracing/RayTracingWorld.cpp | 23 +++++----- src/engine/raytracing/RayTracingWorld.h | 5 +- src/engine/renderer/MainRenderer.cpp | 16 ++++++- src/engine/renderer/MainRenderer.h | 1 + src/engine/renderer/ShadowRenderer.cpp | 2 - src/engine/renderer/TerrainRenderer.cpp | 8 ++-- src/engine/renderer/TerrainShadowRenderer.cpp | 2 +- src/engine/scene/Scene.cpp | 22 +++++---- src/engine/scene/SceneRenderState.cpp | 2 + src/engine/terrain/Terrain.cpp | 46 +++++++++---------- src/engine/terrain/TerrainStorageCell.cpp | 12 ++--- src/engine/terrain/TerrainStorageCell.h | 7 +-- src/engine/tools/TerrainTool.cpp | 38 +++++++-------- src/engine/volume/BVH.cpp | 37 ++++++++++++++- 28 files changed, 228 insertions(+), 141 deletions(-) diff --git a/data/shader/globals.hsh b/data/shader/globals.hsh index 167ae2b38..bcfbbcee0 100644 --- a/data/shader/globals.hsh +++ b/data/shader/globals.hsh @@ -44,4 +44,5 @@ layout(set = 0, binding = 5) uniform texture2DArray bindlessTextureArrays[TEXTUR layout(set = 1, binding = 13) uniform sampler2D dfgTexture; layout(set = 1, binding = 14) uniform sampler bindlessSampler; -layout(set = 1, binding = 16) uniform sampler bindlessNearestSampler; \ No newline at end of file +layout(set = 1, binding = 16) uniform sampler bindlessNearestSampler; +layout(set = 1, binding = 17) uniform sampler bindlessClampToEdgeSampler; \ No newline at end of file diff --git a/data/shader/pathtracer/rayHit.csh b/data/shader/pathtracer/rayHit.csh index 5ead8a10b..932828e45 100644 --- a/data/shader/pathtracer/rayHit.csh +++ b/data/shader/pathtracer/rayHit.csh @@ -108,6 +108,7 @@ void main() { vec2 ndcLast = projPositionLast.xy / projPositionLast.w; vec2 velocity = (ndcLast - ndcCurrent) * 0.5; + imageStore(velocityImage, pixel, vec4(velocity, 0.0, 0.0)); imageStore(depthImage, pixel, vec4(ray.hitID >= 0 ? projPositionCurrent.z / projPositionCurrent.w : INF, 0.0, 0.0, 0.0)); @@ -170,11 +171,14 @@ Surface EvaluateBounce(inout Ray ray, inout RayPayload payload) { payload.throughput = vec3(0.0); return surface; } + + int lod = int(ray.hitDistance / 30.0); + lod = 0; // Unpack the compressed triangle and extract surface parameters Instance instance = GetInstance(ray); Triangle tri = GetTriangle(ray, instance); - surface = GetSurfaceParameters(instance, tri, ray, true, 0); + surface = GetSurfaceParameters(instance, tri, ray, true, lod); // If we hit an emissive surface we need to terminate the ray #ifndef REALTIME diff --git a/data/shader/raytracer/structures.hsh b/data/shader/raytracer/structures.hsh index 5a0f40b69..c40ed6e63 100644 --- a/data/shader/raytracer/structures.hsh +++ b/data/shader/raytracer/structures.hsh @@ -124,6 +124,7 @@ struct RaytraceMaterial { float normalScale; float tiling; + float terrainTiling; int invertUVs; int twoSided; @@ -136,11 +137,10 @@ struct RaytraceMaterial { int roughnessTexture; int metalnessTexture; int aoTexture; - int emissiveTexture; + int emissiveTexture; + int terrainNormalTexture; - int padding0; - int padding1; - int padding2; + int padding; }; diff --git a/data/shader/raytracer/surface.hsh b/data/shader/raytracer/surface.hsh index 5d63d9062..dee0d58a8 100644 --- a/data/shader/raytracer/surface.hsh +++ b/data/shader/raytracer/surface.hsh @@ -87,9 +87,6 @@ Surface GetSurfaceParameters(Instance instance, Triangle tri, Ray ray, vec3 normal = normalize(r * tri.n0 + s * tri.n1 + t * tri.n2); vec4 vertexColor = r * tri.color0 + s * tri.color1 + t * tri.color2; - texCoord = rayMat.invertUVs > 0 ? vec2(texCoord.x, 1.0 - texCoord.y) : texCoord; - texCoord *= rayMat.tiling; - // Produces some problems in the bottom left corner of the Sponza scene, // but fixes the cube. Should work in theory. vec3 triangleNormal = normalize(cross(tri.v0 - tri.v1, tri.v0 - tri.v2)); @@ -99,6 +96,16 @@ Surface GetSurfaceParameters(Instance instance, Triangle tri, Ray ray, vec3 geometryNormal = triangleNormal; + if (rayMat.terrainNormalTexture >= 0) { + vec2 terrainTexCoord = texCoord * rayMat.terrainTiling; + terrainTexCoord = rayMat.invertUVs > 0 ? vec2(terrainTexCoord.x, 1.0 - terrainTexCoord.y) : terrainTexCoord; + geometryNormal = normal; + normal = normalize(2.0 * SampleTerrainNormalBilinear(rayMat.terrainNormalTexture, 0.0, terrainTexCoord) - 1.0); + } + + texCoord = rayMat.invertUVs > 0 ? vec2(texCoord.x, 1.0 - texCoord.y) : texCoord; + texCoord *= rayMat.tiling; + int level = textureLevel; //mat.opacity *= vertexColor.a; mat.baseColor *= rayMat.useVertexColors > 0 ? vertexColor.rgb : vec3(1.0); diff --git a/data/shader/raytracer/texture.hsh b/data/shader/raytracer/texture.hsh index d50b828ba..591c858ea 100644 --- a/data/shader/raytracer/texture.hsh +++ b/data/shader/raytracer/texture.hsh @@ -69,6 +69,16 @@ vec3 SampleEmissiveBilinear(int textureId, float mip, vec2 texCoord) { } +vec3 SampleTerrainNormalBilinear(int textureId, float mip, vec2 texCoord) { + + if (textureId < 0) + return vec3(1.0); + + return textureLod(sampler2D(bindlessTextures[nonuniformEXT(textureId)], bindlessClampToEdgeSampler), texCoord, mip).rgb; + +} + + vec4 SampleEnvironmentMap(vec3 v) { return textureLod(environmentMap, v, 0); diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index 06613e990..d46b68918 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -108,7 +108,7 @@ void main() { SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) ); - float alpha = sqr(material.roughness); + float alpha = sqr(max(0.0, material.roughness)); vec3 V = normalize(-viewVec); vec3 N = worldNorm; @@ -121,7 +121,7 @@ void main() { float pdf = 1.0; BRDFSample brdfSample; - if (material.roughness > 0.01) { + if (material.roughness >= 0.0) { ImportanceSampleGGXVNDF(blueNoiseVec, N, V, alpha, ray.direction, pdf); } diff --git a/data/shader/reflection/ssr.csh b/data/shader/reflection/ssr.csh index cc38a80d4..c181f66ac 100644 --- a/data/shader/reflection/ssr.csh +++ b/data/shader/reflection/ssr.csh @@ -109,7 +109,7 @@ void main() { SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) ); - float alpha = sqr(material.roughness); + float alpha = sqr(max(0.0, material.roughness)); vec3 V = normalize(-viewVec); vec3 N = worldNorm; @@ -122,7 +122,7 @@ void main() { float pdf = 1.0; BRDFSample brdfSample; - if (material.roughness > 0.01) { + if (material.roughness >= 0.0) { ImportanceSampleGGXVNDF(blueNoiseVec.xy, N, V, alpha, ray.direction, pdf); } diff --git a/data/shader/reflection/temporal.csh b/data/shader/reflection/temporal.csh index c2cf4dbc2..e55d5d449 100644 --- a/data/shader/reflection/temporal.csh +++ b/data/shader/reflection/temporal.csh @@ -409,7 +409,7 @@ void main() { roughness *= material.roughnessMap ? texelFetch(roughnessMetallicAoTexture, pixel, 0).r : 1.0; float temporalWeight = mix(pushConstants.temporalWeight, 0.5, adjClipBlend); - float factor = clamp(32.0 * log(roughness + 1.0), 0.75, temporalWeight); + float factor = clamp(32.0 * log(roughness + 1.0), 0.5, temporalWeight); factor = (uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0 || uv.y > 1.0) ? 0.0 : factor; @@ -432,7 +432,7 @@ void main() { float variance = max(0.0, momentsResolve.g - momentsResolve.r * momentsResolve.r); variance *= varianceBoost; - variance = roughness <= 0.1 ? 0.0 : variance; + variance = roughness <= 0.1 ? variance * 0.05 : variance; imageStore(momentsImage, pixel, vec4(momentsResolve, historyLength + 1.0, 0.0)); imageStore(resolveImage, pixel, vec4(resolve, variance)); diff --git a/data/shader/terrain/terrain.fsh b/data/shader/terrain/terrain.fsh index 556b01c96..2614dd39a 100644 --- a/data/shader/terrain/terrain.fsh +++ b/data/shader/terrain/terrain.fsh @@ -57,10 +57,10 @@ layout(location=3) in vec3 ndcLast; vec3 SampleBaseColor(vec2 off, uvec4 indices, vec4 tiling) { - vec3 q00 = nonuniformEXT(texture(baseColorMaps, vec3(materialTexCoords / 4.0 * tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).rgb); - vec3 q10 = nonuniformEXT(indices.y != indices.x ? texture(baseColorMaps, vec3(materialTexCoords / 4.0 * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).rgb : q00); - vec3 q01 = nonuniformEXT(indices.z != indices.x ? texture(baseColorMaps, vec3(materialTexCoords / 4.0 * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).rgb : q00); - vec3 q11 = nonuniformEXT(indices.w != indices.x ? texture(baseColorMaps, vec3(materialTexCoords / 4.0 * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).rgb : q00); + vec3 q00 = nonuniformEXT(texture(baseColorMaps, vec3(materialTexCoords * tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).rgb); + vec3 q10 = nonuniformEXT(indices.y != indices.x ? texture(baseColorMaps, vec3(materialTexCoords * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).rgb : q00); + vec3 q01 = nonuniformEXT(indices.z != indices.x ? texture(baseColorMaps, vec3(materialTexCoords * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).rgb : q00); + vec3 q11 = nonuniformEXT(indices.w != indices.x ? texture(baseColorMaps, vec3(materialTexCoords * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).rgb : q00); // Interpolate samples horizontally vec3 h0 = mix(q00, q10, off.x); @@ -73,10 +73,10 @@ vec3 SampleBaseColor(vec2 off, uvec4 indices, vec4 tiling) { float SampleRoughness(vec2 off, uvec4 indices, vec4 tiling) { - float q00 = nonuniformEXT(texture(roughnessMaps, vec3(materialTexCoords / 4.0 * tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).r); - float q10 = nonuniformEXT(indices.y != indices.x ? texture(roughnessMaps, vec3(materialTexCoords / 4.0 * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).r : q00); - float q01 = nonuniformEXT(indices.z != indices.x ? texture(roughnessMaps, vec3(materialTexCoords / 4.0 * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).r : q00); - float q11 = nonuniformEXT(indices.w != indices.x ? texture(roughnessMaps, vec3(materialTexCoords / 4.0 * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).r : q00); + float q00 = nonuniformEXT(texture(roughnessMaps, vec3(materialTexCoords* tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).r); + float q10 = nonuniformEXT(indices.y != indices.x ? texture(roughnessMaps, vec3(materialTexCoords * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).r : q00); + float q01 = nonuniformEXT(indices.z != indices.x ? texture(roughnessMaps, vec3(materialTexCoords * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).r : q00); + float q11 = nonuniformEXT(indices.w != indices.x ? texture(roughnessMaps, vec3(materialTexCoords * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).r : q00); // Interpolate samples horizontally float h0 = mix(q00, q10, off.x); @@ -89,10 +89,10 @@ float SampleRoughness(vec2 off, uvec4 indices, vec4 tiling) { float SampleAo(vec2 off, uvec4 indices, vec4 tiling) { - float q00 = nonuniformEXT(texture(aoMaps, vec3(materialTexCoords / 4.0 * tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).r); - float q10 = nonuniformEXT(indices.y != indices.x ? texture(aoMaps, vec3(materialTexCoords / 4.0 * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).r : q00); - float q01 = nonuniformEXT(indices.z != indices.x ? texture(aoMaps, vec3(materialTexCoords / 4.0 * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).r : q00); - float q11 = nonuniformEXT(indices.w != indices.x ? texture(aoMaps, vec3(materialTexCoords / 4.0 * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).r : q00); + float q00 = nonuniformEXT(texture(aoMaps, vec3(materialTexCoords * tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).r); + float q10 = nonuniformEXT(indices.y != indices.x ? texture(aoMaps, vec3(materialTexCoords * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).r : q00); + float q01 = nonuniformEXT(indices.z != indices.x ? texture(aoMaps, vec3(materialTexCoords * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).r : q00); + float q11 = nonuniformEXT(indices.w != indices.x ? texture(aoMaps, vec3(materialTexCoords * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).r : q00); // Interpolate samples horizontally float h0 = mix(q00, q10, off.x); @@ -105,10 +105,10 @@ float SampleAo(vec2 off, uvec4 indices, vec4 tiling) { vec3 SampleNormal(vec2 off, uvec4 indices, vec4 tiling) { - vec3 q00 = nonuniformEXT(texture(normalMaps, vec3(materialTexCoords / 4.0 * tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).rgb); - vec3 q10 = nonuniformEXT(indices.y != indices.x ? texture(normalMaps, vec3(materialTexCoords / 4.0 * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).rgb : q00); - vec3 q01 = nonuniformEXT(indices.z != indices.x ? texture(normalMaps, vec3(materialTexCoords / 4.0 * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).rgb : q00); - vec3 q11 = nonuniformEXT(indices.w != indices.x ? texture(normalMaps, vec3(materialTexCoords / 4.0 * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).rgb : q00); + vec3 q00 = nonuniformEXT(texture(normalMaps, vec3(materialTexCoords * tiling.x, nonuniformEXT(float(indices.x))), globalData.mipLodBias).rgb); + vec3 q10 = nonuniformEXT(indices.y != indices.x ? texture(normalMaps, vec3(materialTexCoords * tiling.y, nonuniformEXT(float(indices.y))), globalData.mipLodBias).rgb : q00); + vec3 q01 = nonuniformEXT(indices.z != indices.x ? texture(normalMaps, vec3(materialTexCoords * tiling.z, nonuniformEXT(float(indices.z))), globalData.mipLodBias).rgb : q00); + vec3 q11 = nonuniformEXT(indices.w != indices.x ? texture(normalMaps, vec3(materialTexCoords * tiling.w, nonuniformEXT(float(indices.w))), globalData.mipLodBias).rgb : q00); // Interpolate samples horizontally vec3 h0 = mix(q00, q10, off.x); diff --git a/data/shader/terrain/terrain.tesh b/data/shader/terrain/terrain.tesh index ab38d7500..d19e112d7 100644 --- a/data/shader/terrain/terrain.tesh +++ b/data/shader/terrain/terrain.tesh @@ -51,12 +51,12 @@ float SampleDisplacement(vec2 off, uvec4 indices) { if (indices.x == indices.y && indices.x == indices.z && indices.x == indices.w) - return texture(displacementMaps, vec3(materialTexCoords / 4.0, float(indices.x))).r; + return texture(displacementMaps, vec3(materialTexCoords, float(indices.x))).r; - float q00 = texture(displacementMaps, vec3(materialTexCoords / 4.0, float(indices.x))).r; - float q10 = texture(displacementMaps, vec3(materialTexCoords / 4.0, float(indices.y))).r; - float q01 = texture(displacementMaps, vec3(materialTexCoords / 4.0, float(indices.z))).r; - float q11 = texture(displacementMaps, vec3(materialTexCoords / 4.0, float(indices.w))).r; + float q00 = texture(displacementMaps, vec3(materialTexCoords, float(indices.x))).r; + float q10 = texture(displacementMaps, vec3(materialTexCoords, float(indices.y))).r; + float q01 = texture(displacementMaps, vec3(materialTexCoords, float(indices.z))).r; + float q11 = texture(displacementMaps, vec3(materialTexCoords, float(indices.w))).r; // Interpolate samples horizontally float h0 = mix(q00, q10, off.x); diff --git a/src/engine/graphics/ASBuilder.cpp b/src/engine/graphics/ASBuilder.cpp index 32b24d760..4a76388c6 100644 --- a/src/engine/graphics/ASBuilder.cpp +++ b/src/engine/graphics/ASBuilder.cpp @@ -49,7 +49,7 @@ namespace Atlas { } - int32_t ASBuilder::BuildBLAS(std::vector> &blases, CommandList* commandList) { + int32_t ASBuilder::BuildBLAS(std::span> blases, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; @@ -123,8 +123,8 @@ namespace Atlas { } - Ref ASBuilder::BuildTLAS(Ref& tlas, - std::vector& instances, CommandList* commandList) { + Buffer* ASBuilder::BuildTLAS(Ref& tlas, + std::span instances, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; @@ -142,9 +142,12 @@ namespace Atlas { .data = instances.data(), .size = sizeof(VkAccelerationStructureInstanceKHR) * instances.size(), }; - auto instanceBuffer = device->CreateBuffer(desc); + if (!instanceBuffer || instanceBuffer->size < desc.size) + instanceBuffer = device->CreateMultiBuffer(desc); + else + instanceBuffer->SetData(instances.data(), 0, desc.size); - tlas->Allocate(instanceBuffer->GetDeviceAddress(), uint32_t(instances.size()), false); + tlas->Allocate(instanceBuffer->GetCurrent()->GetDeviceAddress(), uint32_t(instances.size()), false); commandList->MemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); @@ -170,11 +173,11 @@ namespace Atlas { device->SubmitCommandList(commandList); } - return instanceBuffer; + return instanceBuffer->GetCurrent(); } - void ASBuilder::BuildBLASBatch(const std::vector &batchIndices, std::vector> &blases, + void ASBuilder::BuildBLASBatch(const std::span &batchIndices, std::span> &blases, Ref& scratchBuffer, Ref& queryPool, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; @@ -220,8 +223,8 @@ namespace Atlas { } - void ASBuilder::CompactBLASBatch(const std::vector& batchIndices, - std::vector>& blases, Ref& queryPool, CommandList* commandList) { + void ASBuilder::CompactBLASBatch(const std::span& batchIndices, + std::span>& blases, Ref& queryPool, CommandList* commandList) { auto device = GraphicsDevice::DefaultDevice; diff --git a/src/engine/graphics/ASBuilder.h b/src/engine/graphics/ASBuilder.h index 3fc5b129d..1287288f0 100644 --- a/src/engine/graphics/ASBuilder.h +++ b/src/engine/graphics/ASBuilder.h @@ -28,18 +28,19 @@ namespace Atlas { BLASDesc GetBLASDescForTriangleGeometry(Ref vertexBuffer, Ref indexBuffer, size_t vertexCount, size_t vertexSize, size_t indexSize, std::span regions); - int32_t BuildBLAS(std::vector>& blases, CommandList* commandList = nullptr); + int32_t BuildBLAS(std::span> blases, CommandList* commandList = nullptr); - Ref BuildTLAS(Ref& tlas, std::vector& instances, CommandList* commandList = nullptr); + Buffer* BuildTLAS(Ref& tlas, std::span instances, CommandList* commandList = nullptr); private: - void BuildBLASBatch(const std::vector& batchIndices, std::vector>& blases, + void BuildBLASBatch(const std::span& batchIndices, std::span>& blases, Ref& scratchBuffer, Ref& queryPool, CommandList* commandList); - void CompactBLASBatch(const std::vector& batchIndices, - std::vector>& blases, Ref& queryPool, CommandList* commandList); + void CompactBLASBatch(const std::span& batchIndices, + std::span>& blases, Ref& queryPool, CommandList* commandList); Ref scratchBuffer = nullptr; + Ref instanceBuffer = nullptr; }; diff --git a/src/engine/loader/TerrainLoader.cpp b/src/engine/loader/TerrainLoader.cpp index b2aef5e56..35a233f15 100644 --- a/src/engine/loader/TerrainLoader.cpp +++ b/src/engine/loader/TerrainLoader.cpp @@ -90,15 +90,15 @@ namespace Atlas { } // Here we assume that all cells are present - auto heightData = cell->heightField.GetData(); + auto heightData = cell->heightField->GetData(); fileStream.write(reinterpret_cast(heightData.data()), heightData.size() * 2); - auto data = cell->normalMap.GetData(); + auto data = cell->normalMap->GetData(); fileStream.write(reinterpret_cast(data.data()), data.size()); - data = cell->splatMap.GetData(); + data = cell->splatMap->GetData(); fileStream.write(reinterpret_cast(data.data()), data.size()); @@ -258,22 +258,24 @@ namespace Atlas { std::vector heightFieldData(tileResolution * tileResolution); fileStream.read(reinterpret_cast(heightFieldData.data()), heightFieldData.size() * 2); - cell->heightField = Texture::Texture2D(tileResolution, tileResolution, + cell->heightField = CreateRef(tileResolution, tileResolution, VK_FORMAT_R16_UINT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); - cell->heightField.SetData(heightFieldData); + cell->heightField->SetData(heightFieldData); Common::Image image(normalDataResolution, normalDataResolution, 3); fileStream.read(reinterpret_cast(image.GetData().data()), image.GetData().size()); + cell->normalData = image.GetData(); + image.ExpandToChannelCount(4, 255); - cell->normalMap = Texture::Texture2D(normalDataResolution, normalDataResolution, + cell->normalMap = CreateRef(normalDataResolution, normalDataResolution, VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - cell->normalMap.SetData(image.GetData()); + cell->normalMap->SetData(image.GetData()); std::vector splatMapData(heightFieldData.size()); fileStream.read(reinterpret_cast(splatMapData.data()), splatMapData.size()); - cell->splatMap = Texture::Texture2D(tileResolution, tileResolution, + cell->splatMap = CreateRef(tileResolution, tileResolution, VK_FORMAT_R8_UINT, Texture::Wrapping::ClampToEdge, Texture::Filtering::Nearest); - cell->splatMap.SetData(splatMapData); + cell->splatMap->SetData(splatMapData); cell->materialIdxData = splatMapData; if (initWithHeightData) { diff --git a/src/engine/raytracing/RTStructures.h b/src/engine/raytracing/RTStructures.h index 46b069110..c37915772 100644 --- a/src/engine/raytracing/RTStructures.h +++ b/src/engine/raytracing/RTStructures.h @@ -65,6 +65,7 @@ namespace Atlas { float normalScale = 1.0f; float tiling = 1.0f; + float terrainTiling = 1.0f; int32_t invertUVs = 0; int32_t twoSided = 0; @@ -78,6 +79,7 @@ namespace Atlas { int32_t metalnessTexture = -1; int32_t aoTexture = -1; int32_t emissiveTexture = -1; + int32_t terrainNormalTexture = -1; }; struct GPUAABB { diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index f1d2be8ce..107589bcb 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -40,7 +40,6 @@ namespace Atlas { auto renderState = &scene->renderState; - blases.clear(); buildBlases.clear(); auto meshes = scene->GetMeshes(); @@ -61,15 +60,13 @@ namespace Atlas { BuildTriangleLightsForMesh(mesh); } else { - blasInfos[mesh->blas] = prevBlasInfos[mesh->blas]; + std::swap(blasInfos[mesh->blas], prevBlasInfos[mesh->blas]); } auto &blasInfo = blasInfos[mesh->blas]; blasInfo.offset = int32_t(renderState->blasToBindlessIdx[mesh->blas]); blasInfo.cullingDistanceSqr = mesh->rayTraceDistanceCulling * mesh->rayTraceDistanceCulling; - blases.push_back(mesh->blas); - // Some extra path for hardware raytracing, don't want to do work twice if (hardwareRayTracing) { if (mesh->blas->needsBvhRefresh && mesh->blas->blas->isDynamic) { @@ -90,14 +87,14 @@ namespace Atlas { blasInfos[node->cell->blas] = {}; } else { - blasInfos[node->cell->blas] = prevBlasInfos[node->cell->blas]; + std::swap(blasInfos[node->cell->blas], prevBlasInfos[node->cell->blas]); } auto &blasInfo = blasInfos[node->cell->blas]; + + blasInfo.node = node; blasInfo.offset = int32_t(renderState->blasToBindlessIdx[node->cell->blas]); blasInfo.cullingDistanceSqr = 100000000000.0f; - - blases.push_back(node->cell->blas); } if (hardwareRayTracing) { @@ -164,7 +161,7 @@ namespace Atlas { blasInfo.matrices.emplace_back(transformComponent.globalMatrix); blasInfo.instanceIndices.push_back(uint32_t(gpuBvhInstances.size())); - gpuBvhInstances.push_back(gpuBvhInstance); + gpuBvhInstances.emplace_back(gpuBvhInstance); if (includeObjectHistory) lastMatrices.emplace_back(glm::transpose(transformComponent.lastGlobalMatrix)); @@ -314,6 +311,7 @@ namespace Atlas { gpuMaterial.normalScale = material->normalScale; gpuMaterial.tiling = material->tiling; + gpuMaterial.terrainTiling = blasInfo.node ? 1.0f / blasInfo.node->sideLength : 1.0f; gpuMaterial.invertUVs = mesh.IsLoaded() ? (mesh->invertUVs ? 1 : 0) : 0; gpuMaterial.twoSided = material->twoSided ? 1 : 0; @@ -347,6 +345,10 @@ namespace Atlas { if (material->HasEmissiveMap()) { gpuMaterial.emissiveTexture = sceneState->textureToBindlessIdx[material->emissiveMap.Get()]; } + + if (blasInfo.node) { + gpuMaterial.terrainNormalTexture = sceneState->textureToBindlessIdx[blasInfo.node->cell->normalMap]; + } } materials.push_back(gpuMaterial); @@ -425,12 +427,11 @@ namespace Atlas { TransformComponent>& entitySubset, size_t instanceCount) { auto device = Graphics::GraphicsDevice::DefaultDevice; - - Graphics::ASBuilder asBuilder; +; auto tlasDesc = Graphics::TLASDesc(); tlas = device->CreateTLAS(tlasDesc); - asBuilder.BuildTLAS(tlas, hardwareInstances); + tlasBuilder.BuildTLAS(tlas, hardwareInstances); } diff --git a/src/engine/raytracing/RayTracingWorld.h b/src/engine/raytracing/RayTracingWorld.h index 689b7aca4..f3f87b407 100644 --- a/src/engine/raytracing/RayTracingWorld.h +++ b/src/engine/raytracing/RayTracingWorld.h @@ -6,6 +6,8 @@ #include "BLAS.h" #include "scene/Subset.h" + +#include "terrain/TerrainNode.h" #include "scene/components/MeshComponent.h" #include "scene/components/TransformComponent.h" @@ -50,6 +52,7 @@ namespace Atlas { private: struct BlasInfo { ResourceHandle mesh; + Terrain::TerrainNode* node = nullptr; int32_t offset = 0; int32_t materialOffset = 0; @@ -77,9 +80,9 @@ namespace Atlas { Scene::Scene* scene; + Graphics::ASBuilder tlasBuilder; Ref tlas; - std::vector> blases; std::vector> buildBlases; Buffer::Buffer materialBuffer; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index b4ed8f75a..320794449 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -109,6 +109,7 @@ namespace Atlas { commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); commandList->BindSampler(globalSampler, 1, 14); commandList->BindSampler(globalNearestSampler, 1, 16); + commandList->BindSampler(globalClampToEdgeSampler, 1, 17); if (scene->clutter) vegetationRenderer.helper.PrepareInstanceBuffer(*scene->clutter, camera, commandList); @@ -183,6 +184,7 @@ namespace Atlas { continue; auto shadow = light.shadow; + shadow->update = false; shadowImageBarriers.push_back({ shadow->useCubemap ? shadow->cubemap->image : shadow->maps->image, layout, access }); } @@ -473,6 +475,7 @@ namespace Atlas { commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); commandList->BindSampler(globalSampler, 1, 14); commandList->BindSampler(globalNearestSampler, 1, 16); + commandList->BindSampler(globalClampToEdgeSampler, 1, 17); commandList->BindBuffers(renderState->triangleBuffers, 0, 1); if (renderState->textures.size()) commandList->BindSampledImages(renderState->textures, 0, 3); @@ -498,7 +501,7 @@ namespace Atlas { if (scene->postProcessing.fsr2) { fsr2Renderer.Render(target, scene, commandList); } - else { + else if (scene->postProcessing.taa.enable) { taaRenderer.Render(target, scene, commandList); } @@ -929,6 +932,15 @@ namespace Atlas { }; globalSampler = device->CreateSampler(samplerDesc); + samplerDesc = Graphics::SamplerDesc{ + .filter = VK_FILTER_LINEAR, + .mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .maxLod = 12, + .anisotropicFiltering = true + }; + globalClampToEdgeSampler = device->CreateSampler(samplerDesc); + samplerDesc = Graphics::SamplerDesc{ .filter = VK_FILTER_NEAREST, .mode = VK_SAMPLER_ADDRESS_MODE_REPEAT, @@ -938,6 +950,8 @@ namespace Atlas { }; globalNearestSampler = device->CreateSampler(samplerDesc); + + auto layoutDesc = Graphics::DescriptorSetLayoutDesc{ .bindings = { { diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index a89d02db5..e64cbf287 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -86,6 +86,7 @@ namespace Atlas { Ref lightUniformBuffer; Ref globalDescriptorSetLayout; Ref globalSampler; + Ref globalClampToEdgeSampler; Ref globalNearestSampler; Buffer::VertexArray vertexArray; diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index 7ef57a7c4..51de7b391 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -45,8 +45,6 @@ namespace Atlas { // Need to also keep track of non processed layer (e.g. long range layers) for (auto& [lightEntity, frameBuffer] : lightMap) { const auto& light = lightEntity.GetComponent(); - // Will be activated automatically by movable lights - light.shadow->update = false; if (light.type == LightType::DirectionalLight && light.shadow->longRange) { // Need to go through render passes to make sure images have transitioned diff --git a/src/engine/renderer/TerrainRenderer.cpp b/src/engine/renderer/TerrainRenderer.cpp index b46c048a8..87c631508 100644 --- a/src/engine/renderer/TerrainRenderer.cpp +++ b/src/engine/renderer/TerrainRenderer.cpp @@ -128,9 +128,9 @@ namespace Atlas { for (auto node : nodes) { - node->cell->heightField.Bind(commandList, 3, 0); - node->cell->normalMap.Bind(commandList, 3, 1); - node->cell->splatMap.Bind(commandList, 3, 2); + node->cell->heightField->Bind(commandList, 3, 0); + node->cell->normalMap->Bind(commandList, 3, 1); + node->cell->splatMap->Bind(commandList, 3, 2); auto tileScale = terrain->resolution * powf(2.0f, (float)(terrain->LoDCount - node->cell->LoD) - 1.0f); @@ -139,7 +139,7 @@ namespace Atlas { .nodeSideLength = node->sideLength, .tileScale = tileScale, .patchSize = float(terrain->patchSizeFactor), - .normalTexelSize = 1.0f / float(node->cell->normalMap.width), + .normalTexelSize = 1.0f / float(node->cell->normalMap->width), .leftLoD = node->leftLoDStitch, .topLoD = node->topLoDStitch, diff --git a/src/engine/renderer/TerrainShadowRenderer.cpp b/src/engine/renderer/TerrainShadowRenderer.cpp index e62b96da1..c964c65e1 100644 --- a/src/engine/renderer/TerrainShadowRenderer.cpp +++ b/src/engine/renderer/TerrainShadowRenderer.cpp @@ -72,7 +72,7 @@ namespace Atlas { for (auto node : terrain->renderList) { - node->cell->heightField.Bind(commandList, 3, 0); + node->cell->heightField->Bind(commandList, 3, 0); auto tileScale = terrain->resolution * powf(2.0f, (float)(terrain->LoDCount - node->cell->LoD) - 1.0f); diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 59ec4b579..6d46b7bd5 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -110,6 +110,18 @@ namespace Atlas { } } + // Do these updates before anything else (doesn't have newest camera position, but that doesn't matter too much + if (mainCameraEntity.IsValid()) { + auto& mainCamera = mainCameraEntity.GetComponent(); + + if (terrain.IsLoaded()) + terrain->Update(mainCamera); + + if (ocean) { + ocean->Update(mainCamera, deltaTime); + } + } + // Can only update after scripts were run #ifdef AE_BINDLESS renderState.UpdateBlasBindlessData(); @@ -433,16 +445,6 @@ namespace Atlas { renderState.FillRenderList(); renderState.CullAndSortLights(); - JobSystem::WaitSpin(renderState.rayTracingWorldUpdateJob); - - if (terrain.IsLoaded()) { - terrain->Update(mainCamera); - } - - if (ocean) { - ocean->Update(mainCamera, deltaTime); - } - } std::vector> Scene::GetMeshes() { diff --git a/src/engine/scene/SceneRenderState.cpp b/src/engine/scene/SceneRenderState.cpp index 0e546e0fb..9e3a16721 100644 --- a/src/engine/scene/SceneRenderState.cpp +++ b/src/engine/scene/SceneRenderState.cpp @@ -249,6 +249,8 @@ namespace Atlas::Scene { if (!leafCell || !leafCell->IsLoaded() || !leafCell->blas || !leafCell->blas->IsBuilt()) continue; + textureSet.insert(leafCell->normalMap); + for (auto& material : leafCell->blas->materials) if (material.IsLoaded()) materialSet.insert(material.Get()); diff --git a/src/engine/terrain/Terrain.cpp b/src/engine/terrain/Terrain.cpp index 033ee0d7e..ff0f738f4 100644 --- a/src/engine/terrain/Terrain.cpp +++ b/src/engine/terrain/Terrain.cpp @@ -157,8 +157,8 @@ namespace Atlas { z -= zPosition; // Cells have overlapping edges (last pixels are on next cell) - x *= float(cell->heightField.width - 1); - z *= float(cell->heightField.height - 1); + x *= float(cell->heightField->width - 1); + z *= float(cell->heightField->height - 1); xPosition = floorf(x); zPosition = floorf(z); @@ -182,14 +182,14 @@ namespace Atlas { topLeft is in x direction bottomRight is in z direction */ - float heightBottomLeft = cell->heightData[xIndex + cell->heightField.width * zIndex]; + float heightBottomLeft = cell->heightData[xIndex + cell->heightField->width * zIndex]; float heightBottomRight = 0.0f; float heightTopRight = 0.0f; float heightTopLeft = 0.0f; // Check if we must sample from a neighbour node (allows for errors while retrieving the height information at the edge of the terrain) - if (zIndex + 1 == cell->heightField.height && - xIndex + 1 == cell->heightField.width) { + if (zIndex + 1 == cell->heightField->height && + xIndex + 1 == cell->heightField->width) { auto neighbourCell = storage.GetCell(xIndex + 1, zIndex + 1, LoDCount - 1); if (!neighbourCell) { @@ -199,13 +199,13 @@ namespace Atlas { } else { heightTopLeft = neighbourCell->heightData[1]; - heightBottomRight = neighbourCell->heightData[neighbourCell->heightField.width]; - heightTopRight = neighbourCell->heightData[neighbourCell->heightField.width + 1]; + heightBottomRight = neighbourCell->heightData[neighbourCell->heightField->width]; + heightTopRight = neighbourCell->heightData[neighbourCell->heightField->width + 1]; } } - else if (zIndex + 1 == cell->heightField.height) { + else if (zIndex + 1 == cell->heightField->height) { - heightTopLeft = cell->heightData[xIndex + 1 + cell->heightField.width * zIndex]; + heightTopLeft = cell->heightData[xIndex + 1 + cell->heightField->width * zIndex]; auto neighbourCell = storage.GetCell(xIndex, zIndex + 1, LoDCount - 1); @@ -219,9 +219,9 @@ namespace Atlas { } } - else if (xIndex + 1 == cell->heightField.width) { + else if (xIndex + 1 == cell->heightField->width) { - heightBottomRight = cell->heightData[xIndex + cell->heightField.width * (zIndex + 1)]; + heightBottomRight = cell->heightData[xIndex + cell->heightField->width * (zIndex + 1)]; auto neighbourCell = storage.GetCell(xIndex + 1, zIndex, LoDCount - 1); @@ -230,16 +230,16 @@ namespace Atlas { heightTopRight = heightBottomRight; } else { - heightTopLeft = neighbourCell->heightData[zIndex * neighbourCell->heightField.width]; + heightTopLeft = neighbourCell->heightData[zIndex * neighbourCell->heightField->width]; heightTopRight = neighbourCell->heightData[(zIndex + 1) * - neighbourCell->heightField.width]; + neighbourCell->heightField->width]; } } else { - heightTopLeft = cell->heightData[xIndex + 1 + cell->heightField.width * zIndex]; - heightBottomRight = cell->heightData[xIndex + cell->heightField.width * (zIndex + 1)]; - heightTopRight = cell->heightData[xIndex + 1 + cell->heightField.width * (zIndex + 1)]; + heightTopLeft = cell->heightData[xIndex + 1 + cell->heightField->width * zIndex]; + heightBottomRight = cell->heightData[xIndex + cell->heightField->width * (zIndex + 1)]; + heightTopRight = cell->heightData[xIndex + 1 + cell->heightField->width * (zIndex + 1)]; } heightBottomLeft *= heightScale; @@ -313,7 +313,7 @@ namespace Atlas { AE_ASSERT(cell->IsLoaded() && "All cells in a given LoD must \ be loaded to be converted into height field"); - width += cell->heightField.width - 1; + width += cell->heightField->width - 1; } for (int32_t y = 0; y < lodCount; y++) { @@ -322,7 +322,7 @@ namespace Atlas { AE_ASSERT(cell->IsLoaded() && "All cells in a given LoD must \ be loaded to be converted into height field"); - height += cell->heightField.height - 1; + height += cell->heightField->height - 1; } Common::Image heightImage(width, height, 1); @@ -336,19 +336,19 @@ namespace Atlas { AE_ASSERT(cell->IsLoaded() && "All cells in a given LoD must \ be loaded to be converted into height field"); - for (int32_t y = 0; y < cell->heightField.height - 1; y++) { - for (int32_t x = 0; x < cell->heightField.width - 1; x++) { - auto idx = y * cell->heightField.width + x; + for (int32_t y = 0; y < cell->heightField->height - 1; y++) { + for (int32_t x = 0; x < cell->heightField->width - 1; x++) { + auto idx = y * cell->heightField->width + x; heightImage.SetData(width + x, height + y, 0, cell->heightData[idx]); } } - width += cell->heightField.width - 1; + width += cell->heightField->width - 1; } auto cell = storage.GetCell(0, cellY, LoD); - height += cell->heightField.height - 1; + height += cell->heightField->height - 1; } return heightImage; diff --git a/src/engine/terrain/TerrainStorageCell.cpp b/src/engine/terrain/TerrainStorageCell.cpp index c37ae0053..736bfcf88 100644 --- a/src/engine/terrain/TerrainStorageCell.cpp +++ b/src/engine/terrain/TerrainStorageCell.cpp @@ -13,10 +13,10 @@ namespace Atlas { bool TerrainStorageCell::IsLoaded() { - if (!heightField.IsValid()) + if (!heightField || !heightField->IsValid()) return false; - if (!normalMap.IsValid()) + if (!normalMap || !normalMap->IsValid()) return false; return true; @@ -80,9 +80,9 @@ namespace Atlas { RayTracing::BLAS::Triangle triangle; - triangle.v0 = vertices[indices[i * 3 + 2]]; + triangle.v0 = vertices[indices[i * 3 + 0]]; triangle.v1 = vertices[indices[i * 3 + 1]]; - triangle.v2 = vertices[indices[i * 3 + 0]]; + triangle.v2 = vertices[indices[i * 3 + 2]]; vec3 normal = -glm::normalize(glm::cross(triangle.v0 - triangle.v1, triangle.v0 - triangle.v2)); @@ -92,9 +92,9 @@ namespace Atlas { triangle.n1 = normal; triangle.n2 = normal; - triangle.uv0 = vec2(triangle.v2.x, triangle.v2.z); + triangle.uv0 = vec2(triangle.v0.x, triangle.v0.z); triangle.uv1 = vec2(triangle.v1.x, triangle.v1.z); - triangle.uv2 = vec2(triangle.v0.x, triangle.v0.z); + triangle.uv2 = vec2(triangle.v2.x, triangle.v2.z); triangle.materialIdx = int32_t(materialIdxData[indices[i * 3]]); diff --git a/src/engine/terrain/TerrainStorageCell.h b/src/engine/terrain/TerrainStorageCell.h index 6486abec4..55501a260 100644 --- a/src/engine/terrain/TerrainStorageCell.h +++ b/src/engine/terrain/TerrainStorageCell.h @@ -41,10 +41,11 @@ namespace Atlas { std::vector heightData; std::vector materialIdxData; + std::vector normalData; - Texture::Texture2D heightField; - Texture::Texture2D normalMap; - Texture::Texture2D splatMap; + Ref heightField = nullptr; + Ref normalMap = nullptr; + Ref splatMap = nullptr; TerrainStorage* storage = nullptr; diff --git a/src/engine/tools/TerrainTool.cpp b/src/engine/tools/TerrainTool.cpp index fb97d33f3..71fcc1912 100644 --- a/src/engine/tools/TerrainTool.cpp +++ b/src/engine/tools/TerrainTool.cpp @@ -89,8 +89,8 @@ namespace Atlas { } } - cell->heightField.SetData(cellHeightData); - cell->splatMap.SetData(cellSplatData); + cell->heightField->SetData(cellHeightData); + cell->splatMap->SetData(cellSplatData); } } @@ -185,8 +185,8 @@ namespace Atlas { } } - cell->heightField.SetData(cellHeightData); - cell->splatMap.SetData(cellSplatData); + cell->heightField->SetData(cellHeightData); + cell->splatMap->SetData(cellSplatData); } } @@ -216,7 +216,7 @@ namespace Atlas { for (int32_t i = 0; i < tileSideCount; i++) { for (int32_t j = 0; j < tileSideCount; j++) { auto cell = terrain->storage.GetCell(i, j, terrain->LoDCount - 1); - auto cellSplatData = cell->splatMap.GetData(); + auto cellSplatData = cell->splatMap->GetData(); // Now copy a tile of the original image // We make sure that every tile has the same size @@ -379,9 +379,9 @@ namespace Atlas { } */ - cell->normalMap.SetData(tileNormalData); - cell->heightField.SetData(tileHeightData); - cell->splatMap.SetData(tileSplatData); + cell->normalMap->SetData(tileNormalData); + cell->heightField->SetData(tileHeightData); + cell->splatMap->SetData(tileSplatData); } } @@ -417,8 +417,8 @@ namespace Atlas { bottomLeft, bottomMiddle, bottomRight}; // Now bring all height data into one array (we assume that all tiles have the same size) - int32_t width = middleMiddle->heightField.width - 1; - int32_t height = middleMiddle->heightField.height - 1; + int32_t width = middleMiddle->heightField->width - 1; + int32_t height = middleMiddle->heightField->height - 1; std::vector heights(width * height * 9); @@ -512,7 +512,7 @@ namespace Atlas { cellHeightData[k] = (uint16_t)(cell->heightData[k] * 65535.0f); } - cell->heightField.SetData(cellHeightData); + cell->heightField->SetData(cellHeightData); } @@ -545,8 +545,8 @@ namespace Atlas { bottomLeft, bottomMiddle, bottomRight}; // Now bring all height data into one array (we assume that all tiles have the same size) - int32_t width = middleMiddle->heightField.width - 1; - int32_t height = middleMiddle->heightField.height - 1; + int32_t width = middleMiddle->heightField->width - 1; + int32_t height = middleMiddle->heightField->height - 1; std::vector heights(width * height * 9); @@ -661,7 +661,7 @@ namespace Atlas { cellHeightData[k] = (uint16_t)(cell->heightData[k] * 65535.0f); } - cell->heightField.SetData(cellHeightData); + cell->heightField->SetData(cellHeightData); } } @@ -694,8 +694,8 @@ namespace Atlas { std::vector cellDatas[9]; // Now bring all height data into one array (we assume that all tiles have the same size) - int32_t width = middleMiddle->splatMap.width - 1; - int32_t height = middleMiddle->splatMap.height - 1; + int32_t width = middleMiddle->splatMap->width - 1; + int32_t height = middleMiddle->splatMap->height - 1; std::vector combinedSplatMap(width * height * 9); @@ -709,7 +709,7 @@ namespace Atlas { if (cell == nullptr) continue; - cellDatas[i * 3 + j] = cell->splatMap.GetData(); + cellDatas[i * 3 + j] = cell->splatMap->GetData(); auto& splatData = cellDatas[i * 3 + j]; for (int32_t k = 0; k < height + 1; k++) { @@ -788,7 +788,7 @@ namespace Atlas { } } - cell->splatMap.SetData(splatData); + cell->splatMap->SetData(splatData); } @@ -813,7 +813,7 @@ namespace Atlas { for (int32_t i = 0; i < tileSideCount; i++) { for (int32_t j = 0; j < tileSideCount; j++) { auto cell = terrain->storage.GetCell(i, j, terrain->LoDCount - 1); - auto cellSplatData = cell->splatMap.GetData(); + auto cellSplatData = cell->splatMap->GetData(); // Now copy a tile of the original image // We make sure that every tile has the same size diff --git a/src/engine/volume/BVH.cpp b/src/engine/volume/BVH.cpp index 4c6c2746a..8dc5c8895 100644 --- a/src/engine/volume/BVH.cpp +++ b/src/engine/volume/BVH.cpp @@ -55,7 +55,7 @@ namespace Atlas { } - BVH::BVH(const std::vector& aabbs, bool parallelBuild) { + BVH::BVH(const std::vector& aabbs, bool parallelBuild) { refs.resize(aabbs.size()); for (size_t i = 0; i < refs.size(); i++) { @@ -63,6 +63,41 @@ namespace Atlas { refs[i].aabb = aabbs[i]; } + /* + // This can be faster when it is purely used for terrain BLASES + for (size_t j = 0; j < 0; j++) { + float avgLongestAxis = 0.0f; + + for (size_t i = 0; i < refs.size(); i++) { + auto size = refs[i].aabb.GetSize(); + auto maxAxis = size.x > size.y ? + (size.x > size.z ? 0 : 2) : + (size.y > size.z ? 1 : 2); + + avgLongestAxis += size[maxAxis]; + } + + auto refCount = refs.size(); + avgLongestAxis /= float(refCount); + + for (size_t i = 0; i < refs.size(); i++) { + auto size = refs[i].aabb.GetSize(); + auto maxAxis = size.x > size.y ? + (size.x > size.z ? 0 : 2) : + (size.y > size.z ? 1 : 2); + + if (size[maxAxis] * 0.01f > avgLongestAxis) { + auto ref = refs[i]; + + refs[i].aabb.max[maxAxis] = refs[i].aabb.min[maxAxis] + size[maxAxis] * 0.5f; + ref.aabb.min[maxAxis] = refs[i].aabb.max[maxAxis]; + + refs.push_back(ref); + } + } + } + */ + // Calculate initial aabb of root AABB aabb(glm::vec3(std::numeric_limits::max()), glm::vec3(-std::numeric_limits::max())); From 33011c2527049e65e3431f0604a0444b60d62af2 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Tue, 29 Oct 2024 18:39:58 +0100 Subject: [PATCH 63/66] Added different SSGI option --- .gitignore | 3 ++ data/shader/bloom/bloomDownsample.csh | 2 +- data/shader/common/traceScreenSpace.hsh | 55 +++++++++++-------- data/shader/deferred/direct.csh | 5 +- data/shader/deferred/indirect.csh | 5 ++ data/shader/reflection/ssr.csh | 5 +- data/shader/ssgi/ssgi.csh | 71 +++++++++++++++++++------ data/shader/ssgi/temporal.csh | 2 +- src/engine/renderer/SSGIRenderer.cpp | 1 - 9 files changed, 106 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 6c1d4816b..91cc42453 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,6 @@ data/meadow .vscode data/elven data/dungeon +data/namaqualand +data/quarry +data/hiddenalley diff --git a/data/shader/bloom/bloomDownsample.csh b/data/shader/bloom/bloomDownsample.csh index 254c9dc15..5fe5e9b93 100644 --- a/data/shader/bloom/bloomDownsample.csh +++ b/data/shader/bloom/bloomDownsample.csh @@ -3,7 +3,7 @@ layout (local_size_x = 16, local_size_y = 16) in; #include <../common/utility.hsh> #include <../common/flatten.hsh> -//#define NO_SHARED +#define NO_SHARED layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; layout (set = 3, binding = 1) uniform sampler2D textureIn; diff --git a/data/shader/common/traceScreenSpace.hsh b/data/shader/common/traceScreenSpace.hsh index 1804ef724..c47cd667b 100644 --- a/data/shader/common/traceScreenSpace.hsh +++ b/data/shader/common/traceScreenSpace.hsh @@ -20,11 +20,17 @@ bool intersectsDepthBuffer(float z, float minZ, float maxZ, float thickness, flo * artifacts. Driving this value up too high can cause * artifacts of its own. */ - float depthScale = min(1.0f, z * strideCutoff); - //thickness *= mix(0.0f, 2.0f, depthScale); + float depthScale = min(1.0, -z * strideCutoff); + thickness *= mix(0.0, 4.0, depthScale); return (maxZ >= z - thickness) && (minZ < z); } +bool validPixel(vec2 hitPixel, vec2 resolution) { + + return hitPixel.x >= 0 && hitPixel.y >= 0 && hitPixel.x < resolution.x && hitPixel.y < resolution.y; + +} + // Returns true if the ray hit something bool traceScreenSpace( // Camera-space ray origin, which must be within the view volume @@ -62,6 +68,8 @@ bool traceScreenSpace( out point3 minPoint, out point3 maxPoint) { + + mat4 ipMatrix = globalData.ipMatrix; // Clip to the near plane float rayLength = ((csOrig.z + csDir.z * maxDistance) > -globalData.cameraNearPlane) ? @@ -132,12 +140,12 @@ bool traceScreenSpace( float k = k0, stepCount = 0.0, prevZMaxEstimate = csOrig.z; float rayZMin = prevZMaxEstimate, rayZMax = prevZMaxEstimate; - float sceneZMax = rayZMax + 100; + float sceneZMax = rayZMax + maxDistance; point2 P = P0; for (; ((P.x * stepDir) <= end) && (stepCount < maxSteps) && !intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax, zThickness, 0.01) && - (sceneZMax != 0); + (sceneZMax != 0); P += dP, Q.z += dQ.z, k += dk, ++stepCount) { rayZMin = prevZMaxEstimate; @@ -150,7 +158,7 @@ bool traceScreenSpace( hitPixel = permute ? P.yx : P; // You may need hitPixel.y = csZBufferSize.y - hitPixel.y; here if your vertical axis // is different than ours in screen space - sceneZMax = ConvertDepthToViewSpaceDepth(texelFetch(csZBuffer, ivec2(hitPixel), 0).r); + sceneZMax = ConvertDepthToViewSpaceDepth(texelFetch(csZBuffer, ivec2(hitPixel), 0).r, ipMatrix); } minPoint = Q0 + dQ * (stepCount - 2.0); @@ -163,7 +171,8 @@ bool traceScreenSpace( Q.xy += dQ.xy * stepCount; hitPoint = Q * (1.0 / k); - return intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax, zThickness, 0.01); + return intersectsDepthBuffer(sceneZMax, rayZMin, rayZMax, zThickness, 0.01) + && validPixel(hitPixel, csZBufferSize); } bool traceScreenSpace( @@ -231,33 +240,37 @@ bool traceScreenSpaceAdvanced( // Maximum camera-space distance to trace before returning a miss float maxDistance, + bool allowFallback, + // Pixel coordinates of the first intersection with the scene out point2 hitPixel, // Camera space location of the ray hit out point3 hitPoint) { + bool hit = false; + point3 minPoint, maxPoint; if(traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, hitPixel, hitPoint, minPoint, maxPoint)) { - + hit = allowFallback; } maxSteps /= 2.0; - csOrig = minPoint; - csDir = normalize(maxPoint - minPoint); - stride = max(1.0, stride / maxSteps);; - zThickness /= maxSteps; - maxDistance = 20.0 * distance(maxPoint, minPoint); - - vec2 newHitPixel; - vec3 newHitPoint; - if (traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, newHitPixel, newHitPoint, minPoint, maxPoint)) { - hitPixel = newHitPixel; - hitPoint = newHitPoint; - return true; - } + csOrig = minPoint; + csDir = normalize(maxPoint - minPoint); + stride = max(1.0, 2.0 * stride / maxSteps);; + //zThickness /= (2.0 * maxSteps); + //maxDistance = min(maxDistance, 20.0 * distance(maxPoint, minPoint)); + + vec2 newHitPixel; + vec3 newHitPoint; + if (traceScreenSpace(csOrig, csDir, csZBuffer, zThickness, stride, jitter, maxSteps, maxDistance, newHitPixel, newHitPoint, minPoint, maxPoint)) { + hitPixel = newHitPixel; + hitPoint = newHitPoint; + hit = true; + } - return false; + return hit; } \ No newline at end of file diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index a2bf87864..68903e69c 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -95,6 +95,7 @@ void main() { // Get most significant bit index uint bucketBitCount = findMSB(lightBucket) + 1u; + uint offsetIdx = i * 32u; for (uint j = 0u; j < bucketBitCount; j++) { @@ -103,10 +104,10 @@ void main() { lightCount++; - Light light = lights[i * 32u + j]; + Light light = lights[offsetIdx + j]; #ifndef AE_BINDLESS - light.shadow.mapIdx = int(i * 32u + j); + light.shadow.mapIdx = int(offsetIdx + j); #endif bool isMain = i + j == 0u ? true : false; direct += EvaluateLight(light, surface, geometryNormal, isMain); diff --git a/data/shader/deferred/indirect.csh b/data/shader/deferred/indirect.csh index b1a1b5ffe..ad1f3d7b2 100644 --- a/data/shader/deferred/indirect.csh +++ b/data/shader/deferred/indirect.csh @@ -270,7 +270,12 @@ void main() { #endif indirectSpecular *= EvaluateIndirectSpecularBRDF(surface); +#if !defined(SSGI) || defined(RTGI) indirect = (indirectDiffuse + indirectSpecular) * surface.material.ao; +#else + // This is just there if the new SSGI is enabled + indirect = (indirectSpecular) * surface.material.ao; +#endif #ifdef SSGI vec4 ssgi = Uniforms.giDownsampled2x > 0 ? upsampleResult.gi : textureLod(giTexture, texCoord, 0.0); diff --git a/data/shader/reflection/ssr.csh b/data/shader/reflection/ssr.csh index c181f66ac..a24a4c974 100644 --- a/data/shader/reflection/ssr.csh +++ b/data/shader/reflection/ssr.csh @@ -137,7 +137,7 @@ void main() { if (isRayValid) { // Scale offset by depth since the depth buffer inaccuracies increase at a distance and might not match the ray traced geometry anymore - float viewOffset = max(1.0, length(viewPos)); + float viewOffset = max(1.0, 1.0 * length(viewPos)); ray.origin = worldPos + ray.direction * EPSILON * viewOffset + worldNorm * EPSILON * viewOffset; ray.hitID = -1; @@ -146,11 +146,12 @@ void main() { vec3 radiance = vec3(0.0); if (material.roughness <= uniforms.roughnessCutoff) { vec3 viewRayOrigin = viewPos + 10.0 * viewNormal * EPSILON * viewOffset + viewDir * EPSILON * viewOffset; + float rayLength = globalData.cameraFarPlane; vec2 hitPixel; vec3 hitPoint; float jitter = GetInterleavedGradientNoise(vec2(pixel), 4u) / float(sampleCount) + i / float(sampleCount); - if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 1.0, 16.0, jitter, 32.0, 2000.0, hitPixel, hitPoint)) { + if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 32.0, 1.0, 0.0, 64.0, rayLength, false, hitPixel, hitPoint)) { vec2 hitTexCoord = vec2(hitPixel + 0.5) / vec2(textureSize(depthTexture, 0)); radiance = textureLod(lightingTexture, hitTexCoord, 1).rgb; hits += 1.0; diff --git a/data/shader/ssgi/ssgi.csh b/data/shader/ssgi/ssgi.csh index 9b54d7149..a8931101b 100644 --- a/data/shader/ssgi/ssgi.csh +++ b/data/shader/ssgi/ssgi.csh @@ -1,3 +1,6 @@ +#define DDGI +#define DDGI_VISIBILITY + #include <../globals.hsh> #include <../raytracer/lights.hsh> #include <../raytracer/tracing.hsh> @@ -10,6 +13,7 @@ #include <../common/normalencode.hsh> #include <../common/PI.hsh> #include <../common/bluenoise.hsh> +#include <../common/traceScreenSpace.hsh> #include <../brdf/brdfEval.hsh> #include <../brdf/brdfSample.hsh> @@ -33,6 +37,8 @@ layout(set = 3, binding = 6) uniform sampler2D directLightTexture; layout(set = 3, binding = 7) uniform sampler2D scramblingRankingTexture; layout(set = 3, binding = 8) uniform sampler2D sobolSequenceTexture; +layout(set = 1, binding = 12) uniform samplerCube diffuseProbe; + const ivec2 offsets[4] = ivec2[4]( ivec2(0, 0), ivec2(1, 0), @@ -78,9 +84,19 @@ void main() { vec3 viewVec = vec3(globalData.ivMatrix * vec4(viewPos, 0.0)); vec3 viewNorm = normalize(DecodeNormal(textureLod(normalTexture, texCoord, 0).rg)); vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(viewNorm, 0.0))); + vec3 worldView = normalize(vec3(globalData.ivMatrix * vec4(viewVec, 0.0))); uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; Material material = UnpackMaterial(materialIdx); + + vec3 globalProbeFallback = textureLod(diffuseProbe, worldNorm, 0).rgb; +#ifdef DDGI + //rayIrradiance = GetLocalIrradianceInterpolated(worldPos, -V, N, N, globalProbeFallback).rgb * ddgiData.volumeStrength; + vec3 probeIrradiance = GetLocalIrradiance(worldPos, -worldView, worldNorm).rgb * ddgiData.volumeStrength; + probeIrradiance = IsInsideVolume(worldPos) ? probeIrradiance : globalProbeFallback; +#else + probeIrradiance = globalProbeFallback; +#endif vec3 irradiance = vec3(0.0); float hits = 0.0; @@ -117,9 +133,46 @@ void main() { float stepSize = rayLength / float(uniforms.sampleCount); ray.origin = worldPos + surface.N * 0.1 + ray.direction * blueNoiseVec.z * stepSize; - + vec3 rayIrradiance = vec3(0.0); + + vec3 viewDir = normalize(vec3(globalData.vMatrix * vec4(ray.direction, 0.0))); + float viewOffset = max(1.0, length(viewPos)); + vec3 viewRayOrigin = viewPos + viewNorm * EPSILON * viewOffset + viewDir * EPSILON * viewOffset; + vec2 hitPixel; + vec3 hitPoint; + float hit = 0.0; + float jitter = GetInterleavedGradientNoise(vec2(pixel)) / float(uniforms.rayCount) + j / float(uniforms.rayCount); + if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 16.0, 1.0, jitter, 64.0, 0.5 * viewOffset, false, hitPixel, hitPoint)) { + vec2 hitTexCoord = vec2(hitPixel + 0.5) / vec2(textureSize(depthTexture, 0)); + vec3 stepViewNorm = normalize(DecodeNormal(texelFetch(normalTexture, ivec2(hitPixel), 0).rg)); + float depth = texelFetch(depthTexture, ivec2(hitPixel), 0).r; + hitPoint = ConvertDepthToViewSpace(depth, hitTexCoord); + + vec3 worldHitNorm = normalize(vec3(globalData.ivMatrix * vec4(stepViewNorm, 0.0))); + vec3 worldHitPoint = vec3(globalData.ivMatrix * vec4(hitPoint, 1.0)); + + float NdotV = saturate(dot(-viewDir, stepViewNorm)); + NdotL = saturate(dot(viewNorm, hitPoint)); + if (NdotV > 0.0) { + // rayIrradiance = mix(probeIrradiance, textureLod(directLightTexture, hitTexCoord, 0).rgb, 1.0); + rayIrradiance = textureLod(directLightTexture, hitTexCoord, 0).rgb * NdotV; + + vec3 bounceRayIrradiance = GetLocalIrradiance(worldHitPoint, -ray.direction, worldHitNorm).rgb * ddgiData.volumeStrength; + bounceRayIrradiance = IsInsideVolume(worldHitPoint) ? bounceRayIrradiance : vec3(0.0); + + rayIrradiance += bounceRayIrradiance * NdotV; + } + hit = 1.0; + } + else { + rayIrradiance = probeIrradiance; + } + + //rayIrradiance = probeIrradiance; + + /* float hit = 0.0; for (uint i = 0; i < uniforms.sampleCount; i++) { @@ -145,19 +198,6 @@ void main() { vec3 rayDir = normalize(stepPos - viewPos); - /* - if (rayDepth < stepLinearDepth) { - float NdotV = dot(stepViewNorm, -rayDir); - float NdotL = dot(-worldNorm, surface.N); - if (NdotV > 0.0) { - ivec2 lightPixel = uniforms.downsampled2x > 0 ? stepPixel * 2 + pixelOffset : stepPixel; - vec3 hitRadiance = texelFetch(directLightTexture, lightPixel, 0).rgb; - rayIrradiance += hitRadiance * max(dot(viewNorm, rayDir), 0.0) / pdf / PI; - totalCount += 1; - } - } - */ - // Check if we are now behind the depth buffer, use that hit as the source of radiance if (rayDepth >= stepLinearDepth) { float NdotV = dot(stepViewNorm, -rayDir); @@ -178,6 +218,7 @@ void main() { } } + */ irradiance += (rayIrradiance / max(1.0, float(totalCount))); @@ -193,7 +234,7 @@ void main() { float ao = max(1.0 - (hits / float(uniforms.rayCount)), 0.0); - imageStore(giImage, pixel, vec4(irradiance, ao)); + imageStore(giImage, pixel, vec4(vec3(irradiance), ao)); } } \ No newline at end of file diff --git a/data/shader/ssgi/temporal.csh b/data/shader/ssgi/temporal.csh index 0749adaad..7179c836f 100644 --- a/data/shader/ssgi/temporal.csh +++ b/data/shader/ssgi/temporal.csh @@ -31,7 +31,7 @@ layout(push_constant) uniform constants { vec2 invResolution = 1.0 / vec2(imageSize(resolveImage)); vec2 resolution = vec2(imageSize(resolveImage)); -const int kernelRadius = 3; +const int kernelRadius = 5; const uint sharedDataSize = (gl_WorkGroupSize.x + 2 * kernelRadius) * (gl_WorkGroupSize.y + 2 * kernelRadius); const ivec2 unflattenedSharedDataSize = ivec2(gl_WorkGroupSize) + 2 * kernelRadius; diff --git a/src/engine/renderer/SSGIRenderer.cpp b/src/engine/renderer/SSGIRenderer.cpp index d189f980c..b0aba7a3d 100644 --- a/src/engine/renderer/SSGIRenderer.cpp +++ b/src/engine/renderer/SSGIRenderer.cpp @@ -143,7 +143,6 @@ namespace Atlas { VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); } - { Graphics::Profiler::EndAndBeginQuery("Temporal filter"); From 6e97b51236df0bb004e6391941f9333ba76b887a Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Fri, 1 Nov 2024 13:50:40 +0100 Subject: [PATCH 64/66] Some more improvements --- data/shader/clouds/shadow.hsh | 15 ++++++++- data/shader/common/traceScreenSpace.hsh | 2 +- data/shader/ddgi/rayHit.csh | 23 +++++++++++--- data/shader/deferred/direct.csh | 6 +--- data/shader/gbuffer/downsampleGBuffer2x.csh | 6 ++-- data/shader/ocean/ocean.fsh | 2 +- data/shader/ocean/sharedUniforms.hsh | 4 --- data/shader/reflection/rtreflection.csh | 20 ++++++++++-- data/shader/reflection/ssr.csh | 6 ++-- data/shader/reflection/temporal.csh | 33 +++++++++++--------- data/shader/reflection/upsample.csh | 13 ++++++++ data/shader/rtgi/rtgi.csh | 16 +++++++++- data/shader/ssgi/ssgi.csh | 10 +++--- data/shader/structures.hsh | 12 +------ data/shader/vegetation/vegetation.fsh | 4 +-- data/shader/vegetation/vegetation.vsh | 9 ++++-- data/shader/volumetric/volumetricResolve.csh | 18 ++++++++++- src/engine/lighting/VolumetricClouds.cpp | 5 ++- src/engine/pipeline/PipelineConfig.cpp | 6 ++-- src/engine/pipeline/PipelineConfig.h | 4 +-- src/engine/raytracing/RayTracingWorld.cpp | 6 ++-- src/engine/renderer/DDGIRenderer.cpp | 20 ++++++++---- src/engine/renderer/DirectLightRenderer.cpp | 19 ++--------- src/engine/renderer/DirectLightRenderer.h | 1 - src/engine/renderer/MainRenderer.cpp | 25 +++++++++++++-- src/engine/renderer/MainRenderer.h | 1 + src/engine/renderer/OceanRenderer.cpp | 19 +---------- src/engine/renderer/OceanRenderer.h | 1 - src/engine/renderer/RTGIRenderer.cpp | 16 +++++++--- src/engine/renderer/RTReflectionRenderer.cpp | 17 ++++++++-- src/engine/renderer/VolumetricRenderer.cpp | 13 ++++++++ src/engine/renderer/VolumetricRenderer.h | 2 ++ src/engine/scene/Scene.cpp | 15 +++++++++ src/engine/scene/Scene.h | 5 +++ 34 files changed, 252 insertions(+), 122 deletions(-) diff --git a/data/shader/clouds/shadow.hsh b/data/shader/clouds/shadow.hsh index a1f54db09..a29adf922 100644 --- a/data/shader/clouds/shadow.hsh +++ b/data/shader/clouds/shadow.hsh @@ -1,7 +1,20 @@ -#include <../structures.hsh> #include <../globals.hsh> #include <../common/convert.hsh> +struct CloudShadow { + + mat4 vMatrix; + mat4 pMatrix; + + mat4 ivMatrix; + mat4 ipMatrix; + +}; + +layout(std140, set = 1, binding = 19) uniform CloudShadowUniformBuffer { + CloudShadow cloudShadow; +} cloudShadowUniforms; + float CalculateCloudShadow(vec3 P, CloudShadow cloudShadow, sampler2D shadowMap) { vec4 cloudShadowViewCoords = cloudShadow.vMatrix * vec4(P, 1.0); diff --git a/data/shader/common/traceScreenSpace.hsh b/data/shader/common/traceScreenSpace.hsh index c47cd667b..29bc8b027 100644 --- a/data/shader/common/traceScreenSpace.hsh +++ b/data/shader/common/traceScreenSpace.hsh @@ -255,7 +255,7 @@ bool traceScreenSpaceAdvanced( hit = allowFallback; } - maxSteps /= 2.0; + // maxSteps /= 2.0; csOrig = minPoint; csDir = normalize(maxPoint - minPoint); diff --git a/data/shader/ddgi/rayHit.csh b/data/shader/ddgi/rayHit.csh index 9bfa24ea7..511eda0fa 100644 --- a/data/shader/ddgi/rayHit.csh +++ b/data/shader/ddgi/rayHit.csh @@ -21,19 +21,23 @@ #include <../brdf/surface.hsh> #include <../shadow.hsh> - +#include <../clouds/shadow.hsh> #include layout (local_size_x = 32) in; layout(set = 3, binding = 0) uniform sampler2DArrayShadow cascadeMaps; +#ifdef CLOUD_SHADOWS +layout(set = 3, binding = 1) uniform sampler2D cloudMap; +#endif + // Instead of write ray array use hits array -layout(std430, set = 3, binding = 1) buffer RayHits { +layout(std430, set = 3, binding = 2) buffer RayHits { PackedRayHit hits[]; }; -layout(std140, set = 3, binding = 2) uniform UniformBuffer { +layout(std140, set = 3, binding = 3) uniform UniformBuffer { float seed; Shadow shadow; } Uniforms; @@ -126,11 +130,20 @@ vec3 EvaluateDirectLight(inout Surface surface) { surface.geometryNormal, saturate(dot(surface.L, surface.geometryNormal))); radiance *= shadowFactor; #else - radiance *= CheckVisibility(surface, lightDistance) ? 1.0 : 0.0; + if (light.castShadow) + radiance *= CheckVisibility(surface, lightDistance) ? 1.0 : 0.0; + +#ifdef CLOUD_SHADOWS + vec3 P = vec3(globalData.vMatrix * vec4(surface.P, 1.0)); + float cloudShadowFactor = CalculateCloudShadow(P, cloudShadowUniforms.cloudShadow, cloudMap); + + radiance *= cloudShadowFactor; +#endif #endif } else { - radiance *= CheckVisibility(surface, lightDistance) ? 1.0 : 0.0; + if (light.castShadow) + radiance *= CheckVisibility(surface, lightDistance) ? 1.0 : 0.0; } return reflectance * radiance * surface.NdotL / lightPdf; diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 68903e69c..60e30265f 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -29,10 +29,6 @@ layout(set = 3, binding = 2) uniform sampler2D cloudMap; layout(set = 3, binding = 4) uniform sampler shadowSampler; -layout(std140, set = 3, binding = 5) uniform CloudShadowUniformBuffer { - CloudShadow cloudShadow; -} cloudShadowUniforms; - layout(std430, set = 3, binding = 6) buffer LightBucketsBuffer { int lightBuckets[]; }; @@ -246,7 +242,7 @@ float GetShadowFactor(Light light, Surface surface, uint lightType, vec3 geometr #ifdef CLOUD_SHADOWS float cloudShadowFactor = CalculateCloudShadow(surface.P, cloudShadowUniforms.cloudShadow, cloudMap); - shadowFactor = min(shadowFactor, cloudShadowFactor); + shadowFactor *= cloudShadowFactor; #endif float shadowFactorTransmissive = shadowFactor; #ifdef SCREEN_SPACE_SHADOWS diff --git a/data/shader/gbuffer/downsampleGBuffer2x.csh b/data/shader/gbuffer/downsampleGBuffer2x.csh index 3e15a4e92..eb40adc51 100644 --- a/data/shader/gbuffer/downsampleGBuffer2x.csh +++ b/data/shader/gbuffer/downsampleGBuffer2x.csh @@ -64,7 +64,7 @@ int MaxDepth(vec4 depthVec, out float maxDepth) { int CheckerboardDepth(vec4 depthVec, ivec2 coord, out float depth) { - float minmax = 0.0; + float minmax = Checkerboard(coord); float maxDepth; int maxIdx = MaxDepth(depthVec, maxDepth); @@ -90,8 +90,8 @@ void main() { float depth11 = texelFetch(depthIn, coord * 2 + ivec2(1, 1), 0).r; vec4 depthVec = vec4(depth00, depth10, depth01, depth11); - int depthIdx = CheckerboardDepth(depthVec, coord, depthVec.x); - //depthIdx = 0; + int depthIdx = (CheckerboardDepth(depthVec, coord, depthVec.x) + int(globalData.frameCount)) % 4; + //depthIdx = int(globalData.frameCount) % 4; float depth = depthVec[depthIdx]; imageStore(depthOut, coord, vec4(depth, 0.0, 0.0, 1.0)); diff --git a/data/shader/ocean/ocean.fsh b/data/shader/ocean/ocean.fsh index 8aff85811..3986fae49 100644 --- a/data/shader/ocean/ocean.fsh +++ b/data/shader/ocean/ocean.fsh @@ -101,7 +101,7 @@ void main() { #ifdef CLOUD_SHADOWS float cloudShadowFactor = CalculateCloudShadow(fPosition, cloudShadowUniforms.cloudShadow, cloudShadowMap); - shadowFactor = min(shadowFactor, cloudShadowFactor); + shadowFactor *= cloudShadowFactor; #endif shadowFactor = max(shadowFactor, 0.01); diff --git a/data/shader/ocean/sharedUniforms.hsh b/data/shader/ocean/sharedUniforms.hsh index 57006bb81..f70ffedec 100644 --- a/data/shader/ocean/sharedUniforms.hsh +++ b/data/shader/ocean/sharedUniforms.hsh @@ -43,10 +43,6 @@ layout (set = 3, binding = 12, std140) uniform LightUniformBuffer { Light light; } LightUniforms; -layout (set = 3, binding = 14, std140) uniform CloudShadowUniformBuffer { - CloudShadow cloudShadow; -} cloudShadowUniforms; - layout(push_constant) uniform constants { float nodeSideLength; float tileScale; diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index d46b68918..c1e607301 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -20,6 +20,7 @@ #include <../ddgi/ddgi.hsh> #include <../shadow.hsh> +#include <../clouds/shadow.hsh> layout (local_size_x = 8, local_size_y = 4) in; @@ -35,6 +36,10 @@ layout(set = 3, binding = 6) uniform sampler2DArrayShadow cascadeMaps; layout(set = 3, binding = 7) uniform sampler2D scramblingRankingTexture; layout(set = 3, binding = 8) uniform sampler2D sobolSequenceTexture; +#ifdef CLOUD_SHADOWS +layout(set = 3, binding = 9) uniform sampler2D cloudMap; +#endif + const ivec2 offsets[4] = ivec2[4]( ivec2(0, 0), ivec2(1, 0), @@ -42,7 +47,7 @@ const ivec2 offsets[4] = ivec2[4]( ivec2(1, 1) ); -layout(std140, set = 3, binding = 9) uniform UniformBuffer { +layout(std140, set = 3, binding = 10) uniform UniformBuffer { float radianceLimit; uint frameSeed; float bias; @@ -166,9 +171,11 @@ void main() { reflection.rgb /= float(sampleCount); + //reflection.rgb = vec3(0.0); + } - imageStore(rtrImage, pixel, reflection); + imageStore(rtrImage, pixel, vec4(reflection.rgb, 0.0)); } } @@ -243,6 +250,15 @@ vec3 EvaluateDirectLight(inout Surface surface, inout float seed) { if (light.castShadow) radiance *= CheckVisibility(surface, lightDistance); #endif + +#ifdef CLOUD_SHADOWS + if (light.type == uint(DIRECTIONAL_LIGHT)) { + vec3 P = vec3(globalData.vMatrix * vec4(surface.P, 1.0)); + float cloudShadowFactor = CalculateCloudShadow(P, cloudShadowUniforms.cloudShadow, cloudMap); + + radiance *= cloudShadowFactor; + } +#endif return reflectance * radiance * surface.NdotL / lightPdf; diff --git a/data/shader/reflection/ssr.csh b/data/shader/reflection/ssr.csh index a24a4c974..14a4c70f0 100644 --- a/data/shader/reflection/ssr.csh +++ b/data/shader/reflection/ssr.csh @@ -86,7 +86,7 @@ void main() { vec3 viewPos = ConvertDepthToViewSpace(depth, recontructTexCoord); vec3 worldPos = vec3(globalData.ivMatrix * vec4(viewPos, 1.0)); vec3 viewVec = vec3(globalData.ivMatrix * vec4(viewPos, 0.0)); - vec3 viewNormal = DecodeNormal(textureLod(normalTexture, texCoord, 0).rg); + vec3 viewNormal = normalize(DecodeNormal(textureLod(normalTexture, texCoord, 0).rg)); vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(viewNormal, 0.0))); uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; @@ -122,7 +122,7 @@ void main() { float pdf = 1.0; BRDFSample brdfSample; - if (material.roughness >= 0.0) { + if (material.roughness >= 0.05) { ImportanceSampleGGXVNDF(blueNoiseVec.xy, N, V, alpha, ray.direction, pdf); } @@ -151,7 +151,7 @@ void main() { vec2 hitPixel; vec3 hitPoint; float jitter = GetInterleavedGradientNoise(vec2(pixel), 4u) / float(sampleCount) + i / float(sampleCount); - if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 32.0, 1.0, 0.0, 64.0, rayLength, false, hitPixel, hitPoint)) { + if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 0.1, 16.0, 0.5, 64.0, rayLength, false, hitPixel, hitPoint)) { vec2 hitTexCoord = vec2(hitPixel + 0.5) / vec2(textureSize(depthTexture, 0)); radiance = textureLod(lightingTexture, hitTexCoord, 1).rgb; hits += 1.0; diff --git a/data/shader/reflection/temporal.csh b/data/shader/reflection/temporal.csh index e55d5d449..eebce87e5 100644 --- a/data/shader/reflection/temporal.csh +++ b/data/shader/reflection/temporal.csh @@ -310,14 +310,14 @@ bool SampleCatmullRom(ivec2 pixel, vec2 uv, out vec4 history) { return false; } -void ComputeVarianceMinMax(out vec3 mean, out vec3 std) { +void ComputeVarianceMinMax(float roughness, out vec3 mean, out vec3 std) { vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); // This could be varied using the temporal variance estimation // By using a wide neighborhood for variance estimation (8x8) we introduce block artifacts // These are similiar to video compression artifacts, the spatial filter mostly clears them up - const int radius = kernelRadius; + const int radius = int(mix(1.0, float(kernelRadius), min(1.0, roughness * 2.0))); ivec2 pixel = ivec2(gl_GlobalInvocationID); float depth = texelFetch(depthTexture, pixel, 0).r; @@ -357,8 +357,14 @@ void main() { pixel.y > imageSize(resolveImage).y) return; + uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; + Material material = UnpackMaterial(materialIdx); + + float roughness = material.roughness; + roughness *= material.roughnessMap ? texelFetch(roughnessMetallicAoTexture, pixel, 0).r : 1.0; + vec3 mean, std; - ComputeVarianceMinMax(mean, std); + ComputeVarianceMinMax(roughness, mean, std); ivec2 velocityPixel = pixel; vec2 velocity = texelFetch(velocityTexture, velocityPixel, 0).rg; @@ -380,6 +386,7 @@ void main() { vec3 historyColor = RGBToYCoCg(history.rgb); vec3 currentColor = RGBToYCoCg(texelFetch(currentTexture, pixel, 0).rgb); + float validPixel = texelFetch(currentTexture, pixel, 0).a; vec2 currentMoments; currentMoments.r = currentColor.r; @@ -402,16 +409,10 @@ void main() { historyColor = YCoCgToRGB(historyColor); currentColor = YCoCgToRGB(currentColor); - uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; - Material material = UnpackMaterial(materialIdx); - - float roughness = material.roughness; - roughness *= material.roughnessMap ? texelFetch(roughnessMetallicAoTexture, pixel, 0).r : 1.0; - float temporalWeight = mix(pushConstants.temporalWeight, 0.5, adjClipBlend); - float factor = clamp(32.0 * log(roughness + 1.0), 0.5, temporalWeight); - factor = (uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0 - || uv.y > 1.0) ? 0.0 : factor; + float factor = clamp(32.0 * log(roughness + 1.0), 0.875, temporalWeight); + valid = (uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0 + || uv.y > 1.0) ? false : valid; factor = pushConstants.resetHistory > 0 ? 0.0 : factor; @@ -424,6 +425,10 @@ void main() { factor = min(factor, historyLength / (historyLength + 1.0)); +#ifdef UPSCALE + factor = validPixel >= 1.5 ? factor : (valid ? mix(1.0, 0.5, adjClipBlend) : factor); +#endif + vec3 resolve = factor <= 0.0 ? currentColor : mix(currentColor, historyColor, factor); vec2 momentsResolve = factor <= 0.0 ? currentMoments : mix(currentMoments, historyMoments.rg, factor); @@ -432,9 +437,9 @@ void main() { float variance = max(0.0, momentsResolve.g - momentsResolve.r * momentsResolve.r); variance *= varianceBoost; - variance = roughness <= 0.1 ? variance * 0.05 : variance; + variance = roughness <= 0.1 ? variance * 0.0 : variance; imageStore(momentsImage, pixel, vec4(momentsResolve, historyLength + 1.0, 0.0)); - imageStore(resolveImage, pixel, vec4(resolve, variance)); + imageStore(resolveImage, pixel, vec4(vec3(resolve), 0.0)); } \ No newline at end of file diff --git a/data/shader/reflection/upsample.csh b/data/shader/reflection/upsample.csh index c13c7acdc..9516bd9c8 100644 --- a/data/shader/reflection/upsample.csh +++ b/data/shader/reflection/upsample.csh @@ -14,6 +14,7 @@ layout(set = 3, binding = 0, rgba16f) writeonly uniform image2D image; layout(set = 3, binding = 1) uniform sampler2D lowResTexture; layout(set = 3, binding = 2) uniform sampler2D lowResDepthTexture; layout(set = 3, binding = 3) uniform sampler2D lowResNormalTexture; +layout(set = 3, binding = 4) uniform isampler2D offsetTexture; // (localSize / 2 + 2)^2 shared float depths[36]; @@ -115,6 +116,10 @@ void main() { ivec2 resolution = imageSize(image); ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + ivec2 downSamplePixel = pixel / 2; + int offsetIdx = texelFetch(offsetTexture, downSamplePixel, 0).r; + ivec2 offset = pixelOffsets[offsetIdx]; + vec2 texCoord = (vec2(pixel) + 0.5) / vec2(resolution); float depth = texelFetch(depthTexture, pixel, 0).r; @@ -125,6 +130,14 @@ void main() { vec4 upsampleResult = Upsample(depth, surface.N, vec2(pixel)); + upsampleResult.a = downSamplePixel * 2 + offset == pixel ? 2.0 : 0.0; + + //upsampleResult.rgb = vec3(offsetIdx); + if (downSamplePixel * 2 + offset == pixel) { + int sharedMemoryOffset = Flatten2D(downSamplePixel, unflattenedDepthDataSize); + //upsampleResult.rgb = data[sharedMemoryOffset]; + } + imageStore(image, pixel, upsampleResult); } \ No newline at end of file diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index 7f237fdf0..c9979af8f 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -19,6 +19,7 @@ #include <../brdf/surface.hsh> #include <../ddgi/ddgi.hsh> +#include <../clouds/shadow.hsh> #include <../shadow.hsh> layout (local_size_x = 8, local_size_y = 4) in; @@ -35,6 +36,10 @@ layout(set = 3, binding = 6) uniform sampler2DArrayShadow cascadeMaps; layout(set = 3, binding = 7) uniform sampler2D scramblingRankingTexture; layout(set = 3, binding = 8) uniform sampler2D sobolSequenceTexture; +#ifdef CLOUD_SHADOWS +layout(set = 3, binding = 9) uniform sampler2D cloudMap; +#endif + const ivec2 offsets[4] = ivec2[4]( ivec2(0, 0), ivec2(1, 0), @@ -42,7 +47,7 @@ const ivec2 offsets[4] = ivec2[4]( ivec2(1, 1) ); -layout(std140, set = 3, binding = 9) uniform UniformBuffer { +layout(std140, set = 3, binding = 10) uniform UniformBuffer { float radianceLimit; uint frameSeed; float bias; @@ -229,6 +234,15 @@ vec3 EvaluateDirectLight(inout Surface surface, inout float seed) { if (light.castShadow) radiance *= CheckVisibility(surface, lightDistance); #endif + +#ifdef CLOUD_SHADOWS + if (light.type == uint(DIRECTIONAL_LIGHT)) { + vec3 P = vec3(globalData.vMatrix * vec4(surface.P, 1.0)); + float cloudShadowFactor = CalculateCloudShadow(P, cloudShadowUniforms.cloudShadow, cloudMap); + + radiance *= cloudShadowFactor; + } +#endif return reflectance * radiance * surface.NdotL / lightPdf; diff --git a/data/shader/ssgi/ssgi.csh b/data/shader/ssgi/ssgi.csh index a8931101b..64f05e880 100644 --- a/data/shader/ssgi/ssgi.csh +++ b/data/shader/ssgi/ssgi.csh @@ -95,7 +95,7 @@ void main() { vec3 probeIrradiance = GetLocalIrradiance(worldPos, -worldView, worldNorm).rgb * ddgiData.volumeStrength; probeIrradiance = IsInsideVolume(worldPos) ? probeIrradiance : globalProbeFallback; #else - probeIrradiance = globalProbeFallback; + vec3 probeIrradiance = globalProbeFallback; #endif vec3 irradiance = vec3(0.0); @@ -144,7 +144,7 @@ void main() { vec3 hitPoint; float hit = 0.0; float jitter = GetInterleavedGradientNoise(vec2(pixel)) / float(uniforms.rayCount) + j / float(uniforms.rayCount); - if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 16.0, 1.0, jitter, 64.0, 0.5 * viewOffset, false, hitPixel, hitPoint)) { + if (traceScreenSpaceAdvanced(viewRayOrigin, viewDir, depthTexture, 0.5, 16.0, jitter, 64.0, viewOffset, false, hitPixel, hitPoint)) { vec2 hitTexCoord = vec2(hitPixel + 0.5) / vec2(textureSize(depthTexture, 0)); vec3 stepViewNorm = normalize(DecodeNormal(texelFetch(normalTexture, ivec2(hitPixel), 0).rg)); float depth = texelFetch(depthTexture, ivec2(hitPixel), 0).r; @@ -157,12 +157,14 @@ void main() { NdotL = saturate(dot(viewNorm, hitPoint)); if (NdotV > 0.0) { // rayIrradiance = mix(probeIrradiance, textureLod(directLightTexture, hitTexCoord, 0).rgb, 1.0); - rayIrradiance = textureLod(directLightTexture, hitTexCoord, 0).rgb * NdotV; + rayIrradiance = textureLod(directLightTexture, hitTexCoord, 0).rgb; +#ifdef DDGI vec3 bounceRayIrradiance = GetLocalIrradiance(worldHitPoint, -ray.direction, worldHitNorm).rgb * ddgiData.volumeStrength; bounceRayIrradiance = IsInsideVolume(worldHitPoint) ? bounceRayIrradiance : vec3(0.0); - rayIrradiance += bounceRayIrradiance * NdotV; + rayIrradiance += bounceRayIrradiance; +#endif } hit = 1.0; } diff --git a/data/shader/structures.hsh b/data/shader/structures.hsh index e2e55cdfa..684fa49ce 100644 --- a/data/shader/structures.hsh +++ b/data/shader/structures.hsh @@ -35,16 +35,6 @@ struct VolumetricLight { int shadowIdx; }; -struct CloudShadow { - - mat4 vMatrix; - mat4 pMatrix; - - mat4 ivMatrix; - mat4 ipMatrix; - -}; - -layout (std430, set = 1, binding = 17) buffer Lights { +layout (std430, set = 1, binding = 18) buffer Lights { Light lights[]; }; \ No newline at end of file diff --git a/data/shader/vegetation/vegetation.fsh b/data/shader/vegetation/vegetation.fsh index a4997a72e..94a033287 100644 --- a/data/shader/vegetation/vegetation.fsh +++ b/data/shader/vegetation/vegetation.fsh @@ -48,7 +48,7 @@ layout(location=5) in vec4 vertexColorsVS; #endif #if defined(NORMAL_MAP) || defined(HEIGHT_MAP) -layout(location=6) in mat3 TBN; +layout(location=7) in mat3 TBN; #endif layout(push_constant) uniform constants { @@ -85,7 +85,7 @@ void main() { baseColorFS *= textureColor.rgb; #endif #ifdef VERTEX_COLORS - baseColorFS.rgb *= vertexColorsVS.rgb; + //baseColorFS.rgb *= vertexColorsVS.rgb; #endif vec3 geometryNormal = normalize(normalVS); diff --git a/data/shader/vegetation/vegetation.vsh b/data/shader/vegetation/vegetation.vsh index e8d33ab75..3b96165db 100644 --- a/data/shader/vegetation/vegetation.vsh +++ b/data/shader/vegetation/vegetation.vsh @@ -18,7 +18,7 @@ layout(location=4) in vec4 vVertexColors; #endif // Vertex out parameters -#ifdef NORMAl_MAP +#ifdef NORMAL_MAP layout(location=0) out vec3 positionVS; #endif layout(location=1) out vec3 normalVS; @@ -32,6 +32,11 @@ layout(location=4) out vec3 ndcLastVS; layout(location=5) out vec4 vertexColorsVS; #endif +#if defined(NORMAL_MAP) || defined(HEIGHT_MAP) +layout(location=7) out mat3 TBN; +#endif + + layout(set = 3, binding = 7) uniform sampler2D windNoiseMap; layout(std430, set = 3, binding = 8) readonly buffer InstanceData { @@ -84,7 +89,7 @@ void main() { #if defined(NORMAL_MAP) || defined(HEIGHT_MAP) vec3 normal = normalize(normalVS); - float correctionFactor = vTangent.w * (PushConstants.invertUVs > 0 ? -1.0 : 1.0); + float correctionFactor = vTangent.w * (pushConstants.invertUVs > 0 ? -1.0 : 1.0); vec3 tangent = normalize(mat3(mvMatrix) * vTangent.xyz); vec3 bitangent = normalize(correctionFactor * diff --git a/data/shader/volumetric/volumetricResolve.csh b/data/shader/volumetric/volumetricResolve.csh index 2ad542985..e1ee9079f 100644 --- a/data/shader/volumetric/volumetricResolve.csh +++ b/data/shader/volumetric/volumetricResolve.csh @@ -20,6 +20,8 @@ layout(set = 3, binding = 3) uniform sampler2D lowResVolumetricCloudsTexture; layout(set = 3, binding = 5) uniform UniformBuffer { Fog fog; vec4 planetCenter; + vec4 mainLightColor; + vec4 mainLightDirection; int downsampled2x; int cloudsEnabled; int fogEnabled; @@ -187,10 +189,24 @@ void main() { vec3 resolve = imageLoad(resolveImage, pixel).rgb; #ifndef RAYMARCHED_FOG + float LdotV = dot(worldDirection, normalize(uniforms.mainLightDirection.xyz)); + float phaseFunction = ComputeScattering(uniforms.fog.scatteringAnisotropy, LdotV); + vec3 worldPosition = vec3(globalData.ivMatrix * vec4(viewPosition, 1.0)); volumetricFog.a = ComputeVolumetricFog(uniforms.fog, globalData.cameraLocation.xyz, worldPosition); - volumetricFog.rgb = uniforms.fog.extinctionCoefficients.rgb * clamp(1.0 - volumetricFog.a, 0.0, 1.0); + vec3 lightPosition = worldPosition - 10000.0 * normalize(uniforms.mainLightDirection.xyz); + lightPosition = vec3(globalData.ivMatrix * vec4(lightPosition, 1.0)); + float extinctionToLight = ComputeVolumetricFog(uniforms.fog, worldPosition, lightPosition); + + vec3 scatteringCoefficient = uniforms.fog.scatteringFactor * + uniforms.fog.extinctionCoefficients.rgb; + + vec3 lightScattering = phaseFunction * uniforms.mainLightColor.rgb; + + vec3 scattering = scatteringCoefficient * (lightScattering + vec3(uniforms.fog.ambientFactor)); + + volumetricFog.rgb = scattering * clamp(1.0 - volumetricFog.a, 0.0, 1.0); #endif resolve = ApplyVolumetrics(uniforms.fog, resolve, volumetricFog, volumetricClouds, diff --git a/src/engine/lighting/VolumetricClouds.cpp b/src/engine/lighting/VolumetricClouds.cpp index f517695a7..44f210b21 100644 --- a/src/engine/lighting/VolumetricClouds.cpp +++ b/src/engine/lighting/VolumetricClouds.cpp @@ -31,8 +31,7 @@ namespace Atlas { auto cameraLocation = camera.GetLocation(); - auto cascadeCenter = cameraLocation + camera.direction * - (camera.nearPlane + camera.farPlane * 0.5f); + auto cascadeCenter = cameraLocation; // A near enough up vector. This is because if the light location is // (0.0f, 1.0f, 0.0f) the shadows wouldn't render correctly due to the @@ -40,7 +39,7 @@ namespace Atlas { vec3 up = glm::vec3(0.0000000000000001f, 1.0f, 0.0000000000000001f); viewMatrix = lookAt(cascadeCenter, cascadeCenter + lightDirection, up); - auto corners = camera.GetFrustumCorners(camera.nearPlane, camera.farPlane); + auto corners = camera.GetFrustumCorners(-camera.farPlane, camera.farPlane); vec3 maxProj = vec3(viewMatrix * vec4(corners.at(0), 1.0f)); vec3 minProj = maxProj; diff --git a/src/engine/pipeline/PipelineConfig.cpp b/src/engine/pipeline/PipelineConfig.cpp index c8bd7f939..55dc05967 100644 --- a/src/engine/pipeline/PipelineConfig.cpp +++ b/src/engine/pipeline/PipelineConfig.cpp @@ -67,14 +67,14 @@ namespace Atlas { } - bool PipelineConfig::HasMacro(const std::string& macro) { + bool PipelineConfig::HasMacro(const char* macro) { return std::any_of(macros.begin(), macros.end(), - [macro](const auto& value) { return value == macro; }); + [macro](const auto& value) { return std::strcmp(value.c_str(), macro) == 0; }); } - bool PipelineConfig::ManageMacro(const std::string& macro, bool enable) { + bool PipelineConfig::ManageMacro(const char* macro, bool enable) { bool hasMacro = HasMacro(macro); if (enable && !hasMacro) { diff --git a/src/engine/pipeline/PipelineConfig.h b/src/engine/pipeline/PipelineConfig.h index e26a7a5c6..b5b6d58dd 100644 --- a/src/engine/pipeline/PipelineConfig.h +++ b/src/engine/pipeline/PipelineConfig.h @@ -33,9 +33,9 @@ namespace Atlas { void RemoveMacro(const std::string& macro); - bool HasMacro(const std::string& macro); + bool HasMacro(const char* macro); - bool ManageMacro(const std::string& macro, bool enable); + bool ManageMacro(const char* macro, bool enable); bool IsValid() const; diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index 107589bcb..d90726cba 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -52,11 +52,13 @@ namespace Atlas { for (auto& mesh : meshes) { // Only need to check for this, since that means that the BVH was built and the mesh is loaded - if (!renderState->blasToBindlessIdx.contains(mesh->blas)) + if (!mesh.IsLoaded() || !renderState->blasToBindlessIdx.contains(mesh->blas)) continue; if (!prevBlasInfos.contains(mesh->blas)) { - blasInfos[mesh->blas] = {}; + blasInfos[mesh->blas] = BlasInfo{ + .mesh = mesh, + }; BuildTriangleLightsForMesh(mesh); } else { diff --git a/src/engine/renderer/DDGIRenderer.cpp b/src/engine/renderer/DDGIRenderer.cpp index 1b8dda19c..c04bcb01a 100644 --- a/src/engine/renderer/DDGIRenderer.cpp +++ b/src/engine/renderer/DDGIRenderer.cpp @@ -45,10 +45,13 @@ namespace Atlas { Graphics::Profiler::BeginQuery("DDGI"); Ref shadow = nullptr; - auto mainLightEntity = GetMainLightEntity(scene); - if (mainLightEntity.IsValid()) - shadow = mainLightEntity.GetComponent().shadow; - + if (scene->HasMainLight()) + shadow = scene->GetMainLight().shadow; + + auto clouds = scene->sky.clouds; + auto cloudShadowEnabled = clouds && clouds->enable && clouds->castShadow; + + rayHitPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowEnabled && scene->HasMainLight()); rayHitPipelineConfig.ManageMacro("DDGI_VISIBILITY", volume->visibility); rayHitPipelineConfig.ManageMacro("USE_SHADOW_MAP", shadow && volume->useShadowMap); @@ -159,11 +162,16 @@ namespace Atlas { } } } + + if (cloudShadowEnabled && scene->HasMainLight()) { + clouds->shadowTexture.Bind(commandList, 3, 1); + } + rayHitUniformBuffer.SetData(&uniforms, 0); // Use this buffer instead of the default writeRays buffer of the helper - commandList->BindBuffer(rayHitBuffer.Get(), 3, 1); - commandList->BindBuffer(rayHitUniformBuffer.Get(), 3, 2); + commandList->BindBuffer(rayHitBuffer.Get(), 3, 2); + commandList->BindBuffer(rayHitUniformBuffer.Get(), 3, 3); } ); diff --git a/src/engine/renderer/DirectLightRenderer.cpp b/src/engine/renderer/DirectLightRenderer.cpp index 21b6e2ac2..990fbae8c 100644 --- a/src/engine/renderer/DirectLightRenderer.cpp +++ b/src/engine/renderer/DirectLightRenderer.cpp @@ -9,7 +9,6 @@ namespace Atlas { this->device = device; lightCullingBuffer = Buffer::Buffer(Buffer::BufferUsageBits::StorageBufferBit, sizeof(uint32_t)); - cloudShadowUniformBuffer = Buffer::UniformBuffer(sizeof(CloudShadow)); pipelineConfig = PipelineConfig("deferred/direct.csh"); @@ -30,9 +29,7 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Direct lighting"); - auto mainLightEntity = GetMainLightEntity(scene); auto& camera = scene->GetMainCamera(); - auto& light = mainLightEntity.GetComponent(); auto sss = scene->sss; auto clouds = scene->sky.clouds; @@ -100,7 +97,7 @@ namespace Atlas { #endif pipelineConfig.ManageMacro("SCREEN_SPACE_SHADOWS", sss && sss->enable); - pipelineConfig.ManageMacro("CLOUD_SHADOWS", clouds && clouds->enable && clouds->castShadow); + pipelineConfig.ManageMacro("CLOUD_SHADOWS", clouds && clouds->enable && clouds->castShadow && scene->HasMainLight()); pipeline = PipelineManager::GetPipeline(pipelineConfig); commandList->BindPipeline(pipeline); @@ -112,22 +109,10 @@ namespace Atlas { commandList->BindSampler(shadowSampler, 3, 4); - CloudShadow cloudShadowUniform; - if (clouds && clouds->enable && clouds->castShadow) { + if (clouds && clouds->enable && clouds->castShadow && scene->HasMainLight()) { clouds->shadowTexture.Bind(commandList, 3, 2); - - clouds->GetShadowMatrices(camera, glm::normalize(light.transformedProperties.directional.direction), - cloudShadowUniform.vMatrix, cloudShadowUniform.pMatrix); - - cloudShadowUniform.ivMatrix = glm::inverse(cloudShadowUniform.vMatrix); - cloudShadowUniform.ipMatrix = glm::inverse(cloudShadowUniform.pMatrix); - - cloudShadowUniform.vMatrix = cloudShadowUniform.vMatrix * camera.invViewMatrix; } - cloudShadowUniformBuffer.SetData(&cloudShadowUniform, 0); - cloudShadowUniformBuffer.Bind(commandList, 3, 5); - commandList->PushConstants("constants", &pushConstants); commandList->Dispatch(groupCount.x, groupCount.y, 1); diff --git a/src/engine/renderer/DirectLightRenderer.h b/src/engine/renderer/DirectLightRenderer.h index d5dde85c0..2537958b5 100644 --- a/src/engine/renderer/DirectLightRenderer.h +++ b/src/engine/renderer/DirectLightRenderer.h @@ -31,7 +31,6 @@ namespace Atlas { PipelineConfig pipelineConfig; Buffer::Buffer lightCullingBuffer; - Buffer::UniformBuffer cloudShadowUniformBuffer; Ref shadowSampler; }; diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index 320794449..c1959b600 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -31,10 +31,14 @@ namespace Atlas { }; globalUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); pathTraceGlobalUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); + uniformBufferDesc.size = sizeof(DDGIUniforms); ddgiUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); + uniformBufferDesc.size = sizeof(CloudShadow); + cloudShadowUniformBuffer = device->CreateMultiBuffer(uniformBufferDesc); + opaqueRenderer.Init(device); impostorRenderer.Init(device); terrainRenderer.Init(device); @@ -109,7 +113,7 @@ namespace Atlas { commandList->BindImage(dfgPreintegrationTexture.image, dfgPreintegrationTexture.sampler, 1, 13); commandList->BindSampler(globalSampler, 1, 14); commandList->BindSampler(globalNearestSampler, 1, 16); - commandList->BindSampler(globalClampToEdgeSampler, 1, 17); + commandList->BindSampler(globalClampToEdgeSampler, 1, 18); if (scene->clutter) vegetationRenderer.helper.PrepareInstanceBuffer(*scene->clutter, camera, commandList); @@ -195,7 +199,8 @@ namespace Atlas { JobSystem::WaitSpin(scene->renderState.rayTracingWorldUpdateJob); JobSystem::WaitSpin(renderState->cullAndSortLightsJob); - renderState->lightBuffer.Bind(commandList, 1, 17); + renderState->lightBuffer.Bind(commandList, 1, 18); + commandList->BindBuffer(cloudShadowUniformBuffer, 1, 19); ddgiRenderer.TraceAndUpdateProbes(scene, commandList); @@ -1071,6 +1076,22 @@ namespace Atlas { ddgiUniformBuffer->SetData(&ddgiUniforms, 0, sizeof(DDGIUniforms)); } + auto clouds = scene->sky.clouds; + if (clouds && clouds->enable && clouds->castShadow && scene->HasMainLight()) { + const auto& light = scene->GetMainLight(); + + CloudShadow cloudShadowUniform; + clouds->GetShadowMatrices(camera, glm::normalize(light.transformedProperties.directional.direction), + cloudShadowUniform.vMatrix, cloudShadowUniform.pMatrix); + + cloudShadowUniform.ivMatrix = glm::inverse(cloudShadowUniform.vMatrix); + cloudShadowUniform.ipMatrix = glm::inverse(cloudShadowUniform.pMatrix); + + cloudShadowUniform.vMatrix = cloudShadowUniform.vMatrix * camera.invViewMatrix; + + cloudShadowUniformBuffer->SetData(&cloudShadowUniform, 0, sizeof(CloudShadow)); + } + auto meshes = scene->GetMeshes(); for (auto& mesh : meshes) { if (!mesh.IsLoaded() || !mesh->impostor) continue; diff --git a/src/engine/renderer/MainRenderer.h b/src/engine/renderer/MainRenderer.h index e64cbf287..18c59720a 100644 --- a/src/engine/renderer/MainRenderer.h +++ b/src/engine/renderer/MainRenderer.h @@ -84,6 +84,7 @@ namespace Atlas { Ref pathTraceGlobalUniformBuffer; Ref ddgiUniformBuffer; Ref lightUniformBuffer; + Ref cloudShadowUniformBuffer; Ref globalDescriptorSetLayout; Ref globalSampler; Ref globalClampToEdgeSampler; diff --git a/src/engine/renderer/OceanRenderer.cpp b/src/engine/renderer/OceanRenderer.cpp index c45974dc1..ebf4534a5 100644 --- a/src/engine/renderer/OceanRenderer.cpp +++ b/src/engine/renderer/OceanRenderer.cpp @@ -19,7 +19,6 @@ namespace Atlas { uniformBuffer = Buffer::UniformBuffer(sizeof(Uniforms)); depthUniformBuffer = Buffer::UniformBuffer(sizeof(Uniforms)); lightUniformBuffer = Buffer::UniformBuffer(sizeof(Light)); - cloudShadowUniformBuffer = Buffer::UniformBuffer(sizeof(CloudShadow)); auto samplerDesc = Graphics::SamplerDesc{ .filter = VK_FILTER_NEAREST, @@ -111,26 +110,10 @@ namespace Atlas { bool fogEnabled = fog && fog->enable; bool cloudsEnabled = clouds && clouds->enable; - bool cloudShadowsEnabled = clouds && clouds->enable && clouds->castShadow; - - CloudShadow cloudShadowUniform; - - if (cloudShadowsEnabled) { + if (cloudShadowsEnabled) clouds->shadowTexture.Bind(commandList, 3, 15); - clouds->GetShadowMatrices(camera, glm::normalize(light.transformedProperties.directional.direction), - cloudShadowUniform.vMatrix, cloudShadowUniform.pMatrix); - - cloudShadowUniform.vMatrix = cloudShadowUniform.vMatrix * camera.invViewMatrix; - - cloudShadowUniform.ivMatrix = glm::inverse(cloudShadowUniform.vMatrix); - cloudShadowUniform.ipMatrix = glm::inverse(cloudShadowUniform.pMatrix); - } - - cloudShadowUniformBuffer.SetData(&cloudShadowUniform, 0); - cloudShadowUniformBuffer.Bind(commandList, 3, 14); - { Graphics::Profiler::BeginQuery("Caustics"); diff --git a/src/engine/renderer/OceanRenderer.h b/src/engine/renderer/OceanRenderer.h index d408b39df..c9250d198 100644 --- a/src/engine/renderer/OceanRenderer.h +++ b/src/engine/renderer/OceanRenderer.h @@ -86,7 +86,6 @@ namespace Atlas { Buffer::UniformBuffer uniformBuffer; Buffer::UniformBuffer depthUniformBuffer; Buffer::UniformBuffer lightUniformBuffer; - Buffer::UniformBuffer cloudShadowUniformBuffer; Ref nearestSampler; Ref shadowSampler; diff --git a/src/engine/renderer/RTGIRenderer.cpp b/src/engine/renderer/RTGIRenderer.cpp index 294fd2c05..a5b1e72d3 100644 --- a/src/engine/renderer/RTGIRenderer.cpp +++ b/src/engine/renderer/RTGIRenderer.cpp @@ -72,9 +72,8 @@ namespace Atlas { // Try to get a shadow map Ref shadow = nullptr; - auto mainLightEntity = GetMainLightEntity(scene); - if (mainLightEntity.IsValid()) - shadow = mainLightEntity.GetComponent().shadow; + if (scene->HasMainLight()) + shadow = scene->GetMainLight().shadow; auto mainCamera = scene->GetMainCamera(); @@ -113,13 +112,17 @@ namespace Atlas { groupCount.x += ((groupCount.x * 8 == res.x) ? 0 : 1); groupCount.y += ((groupCount.y * 4 == res.y) ? 0 : 1); + auto clouds = scene->sky.clouds; + auto ddgiEnabled = scene->irradianceVolume && scene->irradianceVolume->enable; auto ddgiVisibility = ddgiEnabled && scene->irradianceVolume->visibility; + auto cloudShadowEnabled = clouds && clouds->enable && clouds->castShadow; rtPipelineConfig.ManageMacro("USE_SHADOW_MAP", rtgi->useShadowMap && shadow); rtPipelineConfig.ManageMacro("DDGI", rtgi->ddgi && ddgiEnabled); rtPipelineConfig.ManageMacro("DDGI_VISIBILITY", rtgi->ddgi && ddgiVisibility); rtPipelineConfig.ManageMacro("OPACITY_CHECK", rtgi->opacityCheck); + rtPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowEnabled && scene->HasMainLight()); auto pipeline = PipelineManager::GetPipeline(rtPipelineConfig); @@ -170,8 +173,13 @@ namespace Atlas { } } } + + if (cloudShadowEnabled && scene->HasMainLight()) { + clouds->shadowTexture.Bind(commandList, 3, 9); + } + rtUniformBuffer.SetData(&uniforms, 0); - commandList->BindBuffer(rtUniformBuffer.Get(), 3, 9); + commandList->BindBuffer(rtUniformBuffer.Get(), 3, 10); }); diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index 7c2450559..0e8c2e624 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -185,13 +185,17 @@ namespace Atlas { groupCount.x += ((groupCount.x * 8 == rayRes.x) ? 0 : 1); groupCount.y += ((groupCount.y * 4 == rayRes.y) ? 0 : 1); + auto clouds = scene->sky.clouds; + auto ddgiEnabled = scene->irradianceVolume && scene->irradianceVolume->enable; auto ddgiVisibility = ddgiEnabled && scene->irradianceVolume->visibility; + auto cloudShadowEnabled = clouds && clouds->enable && clouds->castShadow; rtrPipelineConfig.ManageMacro("USE_SHADOW_MAP", reflection->useShadowMap && shadow); rtrPipelineConfig.ManageMacro("DDGI", reflection->ddgi && ddgiEnabled); rtrPipelineConfig.ManageMacro("DDGI_VISIBILITY", reflection->ddgi && ddgiVisibility); - rtrPipelineConfig.ManageMacro("OPACITY_CHECK", reflection->opacityCheck); + rtrPipelineConfig.ManageMacro("OPACITY_CHECK", reflection->opacityCheck); + rtrPipelineConfig.ManageMacro("CLOUD_SHADOWS", cloudShadowEnabled && scene->HasMainLight()); auto pipeline = PipelineManager::GetPipeline(rtrPipelineConfig); @@ -201,14 +205,19 @@ namespace Atlas { helper.DispatchAndHit(scene, commandList, pipeline, ivec3(groupCount, 1), [=]() { commandList->BindImage(reflectionTexture->image, 3, 0); - commandList->BindBuffer(rtrUniformBuffer.Get(), 3, 9); + + if (cloudShadowEnabled && scene->HasMainLight()) { + clouds->shadowTexture.Bind(commandList, 3, 9); + } + + commandList->BindBuffer(rtrUniformBuffer.Get(), 3, 10); }); commandList->ImageMemoryBarrier(reflectionTexture->image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT); } - if (reflection->upsampleBeforeFiltering) { + if (reflection->upsampleBeforeFiltering && reflection->halfResolution) { Graphics::Profiler::EndAndBeginQuery("Upscaling"); ivec2 groupCount = ivec2(res.x / 8, res.y / 8); @@ -260,6 +269,8 @@ namespace Atlas { groupCount.x += ((groupCount.x * 16 == res.x) ? 0 : 1); groupCount.y += ((groupCount.y * 16 == res.y) ? 0 : 1); + temporalPipelineConfig.ManageMacro("UPSCALE", reflection->upsampleBeforeFiltering && reflection->halfResolution); + auto pipeline = PipelineManager::GetPipeline(temporalPipelineConfig); commandList->BindPipeline(pipeline); diff --git a/src/engine/renderer/VolumetricRenderer.cpp b/src/engine/renderer/VolumetricRenderer.cpp index 497915b0a..1496062dc 100644 --- a/src/engine/renderer/VolumetricRenderer.cpp +++ b/src/engine/renderer/VolumetricRenderer.cpp @@ -312,6 +312,19 @@ namespace Atlas { commandList->BindImage(depthTexture->image, depthTexture->sampler, 3, 4); ResolveUniforms uniforms; + + if (scene->HasMainLight()) { + auto& mainLight = scene->GetMainLight(); + auto& lightDirection = mainLight.transformedProperties.directional.direction; + auto lightColor = Common::ColorConverter::ConvertSRGBToLinear(mainLight.color); + + uniforms.mainLightColor = vec4(lightColor * mainLight.intensity, 0.0f); + uniforms.mainLightDirection = vec4(lightDirection, 0.0f); + } + else { + uniforms.mainLightColor = vec4(0.0f); + } + uniforms.cloudsEnabled = cloudsEnabled ? 1 : 0; uniforms.fogEnabled = fogEnabled ? 1 : 0; uniforms.downsampled2x = target->GetVolumetricResolution() == RenderResolution::HALF_RES ? 1 : 0; diff --git a/src/engine/renderer/VolumetricRenderer.h b/src/engine/renderer/VolumetricRenderer.h index 9ed64f197..67375bc27 100644 --- a/src/engine/renderer/VolumetricRenderer.h +++ b/src/engine/renderer/VolumetricRenderer.h @@ -43,6 +43,8 @@ namespace Atlas { struct alignas(16) ResolveUniforms { Fog fog; vec4 planetCenter; + vec4 mainLightColor; + vec4 mainLightDirection; int downsampled2x; int cloudsEnabled; int fogEnabled; diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 6d46b7bd5..ae2744ed1 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -340,6 +340,9 @@ namespace Atlas { for (auto entity : lightSubset) { auto& lightComponent = lightSubset.Get(entity); + if (lightComponent.isMain && lightComponent.type == LightType::DirectionalLight) + mainLightEntity = Entity(entity, &entityManager); + auto transformComponent = entityManager.TryGet(entity); lightComponent.Update(transformComponent); @@ -513,6 +516,18 @@ namespace Atlas { } + LightComponent& Scene::GetMainLight() { + + return mainLightEntity.GetComponent(); + + } + + bool Scene::HasMainLight() const { + + return mainLightEntity.IsValid() && mainLightEntity.HasComponent(); + + } + Volume::RayResult Scene::CastRay(Volume::Ray& ray, SceneQueryComponents queryComponents) { Volume::RayResult result; diff --git a/src/engine/scene/Scene.h b/src/engine/scene/Scene.h index 5e9b6685f..9a5cc0868 100644 --- a/src/engine/scene/Scene.h +++ b/src/engine/scene/Scene.h @@ -104,6 +104,10 @@ namespace Atlas { bool HasMainCamera() const; + LightComponent& GetMainLight(); + + bool HasMainLight() const; + Volume::RayResult CastRay(Volume::Ray& ray, SceneQueryComponents queryComponents = SceneQueryComponentBits::AllComponentsBit); @@ -176,6 +180,7 @@ namespace Atlas { std::map> registeredAudios; Entity mainCameraEntity; + Entity mainLightEntity; float deltaTime = 1.0f; bool firstTimestep = true; From a61a1bcd6f29b143c682bd2905d3f0963f968675 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sat, 2 Nov 2024 22:42:32 +0100 Subject: [PATCH 65/66] Performance improvements and fixes --- data/shader/bloom/bloomDownsample.csh | 114 +++++------------- data/shader/bloom/bloomUpsample.csh | 34 +++--- data/shader/common/types.hsh | 48 ++++++++ data/shader/common/utility.hsh | 25 ++++ data/shader/common/ycocg.hsh | 18 +++ data/shader/ddgi/ddgi.hsh | 18 +++ data/shader/deferred/direct.csh | 9 +- data/shader/deferred/lightCulling.hsh | 4 +- data/shader/gbuffer/downsampleGBuffer2x.csh | 15 ++- data/shader/gbuffer/generateReactiveMask.csh | 5 + ...tchGBufferNormals.csh => patchGBuffer.csh} | 12 +- data/shader/raytracer/surface.hsh | 3 +- data/shader/reflection/atrous.csh | 29 ++--- data/shader/reflection/rtreflection.csh | 30 +++-- data/shader/reflection/temporal.csh | 20 ++- data/shader/reflection/upsample.csh | 12 +- data/shader/rtgi/rtgi.csh | 67 +++++----- data/shader/rtgi/temporal.csh | 4 +- .../ImguiExtension/panels/ReflectionPanel.cpp | 2 + src/engine/graphics/Shader.cpp | 4 + src/engine/raytracing/RayTracingWorld.cpp | 2 +- src/engine/renderer/GBufferRenderer.cpp | 17 ++- src/engine/renderer/GBufferRenderer.h | 2 +- src/engine/renderer/MainRenderer.cpp | 4 +- src/engine/renderer/RTReflectionRenderer.cpp | 7 +- 25 files changed, 305 insertions(+), 200 deletions(-) create mode 100644 data/shader/common/types.hsh rename data/shader/gbuffer/{patchGBufferNormals.csh => patchGBuffer.csh} (50%) diff --git a/data/shader/bloom/bloomDownsample.csh b/data/shader/bloom/bloomDownsample.csh index 5fe5e9b93..eb6b0a988 100644 --- a/data/shader/bloom/bloomDownsample.csh +++ b/data/shader/bloom/bloomDownsample.csh @@ -1,10 +1,9 @@ layout (local_size_x = 16, local_size_y = 16) in; #include <../common/utility.hsh> +#include <../common/types.hsh> #include <../common/flatten.hsh> -#define NO_SHARED - layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; layout (set = 3, binding = 1) uniform sampler2D textureIn; @@ -26,83 +25,36 @@ const ivec2 pixelOffsets[4] = ivec2[4]( ivec2(1, 1) ); -float Luma(vec3 color) { +AeF16 Luma(AeF16x3 color) { - const vec3 luma = vec3(0.299, 0.587, 0.114); + const AeF16x3 luma = AeF16x3(0.299, 0.587, 0.114); return dot(color, luma); } -vec3 Prefilter(vec3 color) { +AeF16x3 Prefilter(AeF16x3 color) { - float brightness = Luma(color); - float contribution = max(0.0, brightness - pushConstants.threshold); - contribution /= max(brightness, 0.00001); + AeF16 brightness = Luma(color); + AeF16 contribution = max(AeF16(0.0), brightness - AeF16(pushConstants.threshold)); + contribution /= max(brightness, AeF16(0.001)); return color * contribution; } -void LoadGroupSharedData() { - - ivec2 resolution = textureSize(textureIn, pushConstants.mipLevel); - ivec2 workGroupOffset = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize); - - uint workGroupSize = gl_WorkGroupSize.x * gl_WorkGroupSize.y; - for(uint i = gl_LocalInvocationIndex; i < sharedDataSize; i += workGroupSize) { - ivec2 localOffset = Unflatten2D(int(i), unflattenedSharedDataSize); - ivec2 texel = localOffset + 2 * workGroupOffset - ivec2(supportSize); - - texel = clamp(texel, ivec2(0), ivec2(resolution) - ivec2(1)); - - vec3 color = texelFetch(textureIn, texel, pushConstants.mipLevel).rgb; - if (pushConstants.mipLevel == 0) { - color = Prefilter(color); - } - - sharedMemory[i] = color; - } - barrier(); +AeF16x3 Sample(vec2 texCoord) { -} - -vec3 Sample(vec2 texCoord) { - -#ifdef NO_SHARED if (pushConstants.mipLevel == 0) { - return Prefilter(textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb); + return Prefilter(AeF16x3(textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb)); } else { - return textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb; - } -#else - const ivec2 groupOffset = 2 * (ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize)) - ivec2(supportSize); - - vec2 pixel = texCoord * textureSize(textureIn, pushConstants.mipLevel); - pixel -= 0.5; - - float x = fract(pixel.x); - float y = fract(pixel.y); - - float weights[4] = { (1 - x) * (1 - y), x * (1 - y), (1 - x) * y, x * y }; - - vec3 color = vec3(0.0); - for (int i = 0; i < 4; i++) { - ivec2 offsetPixel = ivec2(pixel) + pixelOffsets[i]; - offsetPixel -= groupOffset; - offsetPixel = clamp(offsetPixel, ivec2(0), unflattenedSharedDataSize - ivec2(1)); - int sharedMemoryIdx = Flatten2D(offsetPixel, unflattenedSharedDataSize); - color += weights[i] * sharedMemory[sharedMemoryIdx]; + return AeF16x3(textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb); } - return color; -#endif } void main() { - LoadGroupSharedData(); - ivec2 size = imageSize(textureOut); ivec2 coord = ivec2(gl_GlobalInvocationID); @@ -114,35 +66,35 @@ void main() { vec2 texelSize = 1.0 / vec2(textureSize(textureIn, pushConstants.mipLevel)); // We always sample at pixel border, not centers - vec3 outer00 = Sample(texCoord + vec2(-2.0 * texelSize.x, -2.0 * texelSize.y)); - vec3 outer10 = Sample(texCoord + vec2(0.0, -2.0 * texelSize.y)); - vec3 outer20 = Sample(texCoord + vec2(2.0 * texelSize.x, -2.0 * texelSize.y)); + AeF16x3 outer00 = Sample(texCoord + vec2(-2.0 * texelSize.x, -2.0 * texelSize.y)); + AeF16x3 outer10 = Sample(texCoord + vec2(0.0, -2.0 * texelSize.y)); + AeF16x3 outer20 = Sample(texCoord + vec2(2.0 * texelSize.x, -2.0 * texelSize.y)); - vec3 outer01 = Sample(texCoord + vec2(-2.0 * texelSize.x, 0.0)); - vec3 outer11 = Sample(texCoord + vec2(0.0, 0.0)); - vec3 outer21 = Sample(texCoord + vec2(2.0 * texelSize.x, 0.0)); + AeF16x3 outer01 = Sample(texCoord + vec2(-2.0 * texelSize.x, 0.0)); + AeF16x3 outer11 = Sample(texCoord + vec2(0.0, 0.0)); + AeF16x3 outer21 = Sample(texCoord + vec2(2.0 * texelSize.x, 0.0)); - vec3 outer02 = Sample(texCoord + vec2(-2.0 * texelSize.x, 2.0 * texelSize.y)); - vec3 outer12 = Sample(texCoord + vec2(0.0, 2.0 * texelSize.y)); - vec3 outer22 = Sample(texCoord + vec2(2.0 * texelSize.x, 2.0 * texelSize.y)); + AeF16x3 outer02 = Sample(texCoord + vec2(-2.0 * texelSize.x, 2.0 * texelSize.y)); + AeF16x3 outer12 = Sample(texCoord + vec2(0.0, 2.0 * texelSize.y)); + AeF16x3 outer22 = Sample(texCoord + vec2(2.0 * texelSize.x, 2.0 * texelSize.y)); - vec3 inner00 = Sample(texCoord + vec2(-texelSize.x, -texelSize.y)); - vec3 inner10 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); - vec3 inner01 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); - vec3 inner11 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); + AeF16x3 inner00 = Sample(texCoord + vec2(-texelSize.x, -texelSize.y)); + AeF16x3 inner10 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); + AeF16x3 inner01 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); + AeF16x3 inner11 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); - vec3 outerGroup0 = 0.125 * (outer00 + outer10 + outer01 + outer11) * 0.25; - vec3 outerGroup1 = 0.125 * (outer10 + outer20 + outer11 + outer21) * 0.25; - vec3 outerGroup2 = 0.125 * (outer01 + outer11 + outer02 + outer12) * 0.25; - vec3 outerGroup3 = 0.125 * (outer11 + outer21 + outer12 + outer22) * 0.25; - vec3 innerGroup = 0.5 * (inner00 + inner10 + inner01 + inner11) * 0.25; + AeF16x3 outerGroup0 = AeF16(0.125 * 0.25) * (outer00 + outer10 + outer01 + outer11); + AeF16x3 outerGroup1 = AeF16(0.125 * 0.25) * (outer10 + outer20 + outer11 + outer21); + AeF16x3 outerGroup2 = AeF16(0.125 * 0.25) * (outer01 + outer11 + outer02 + outer12); + AeF16x3 outerGroup3 = AeF16(0.125 * 0.25) * (outer11 + outer21 + outer12 + outer22); + AeF16x3 innerGroup = AeF16(0.5 * 0.25) * (inner00 + inner10 + inner01 + inner11); if (pushConstants.mipLevel == 0) { - float outerGroup0Weight = (1.0 / (1.0 + Luma(outerGroup0))); - float outerGroup1Weight = (1.0 / (1.0 + Luma(outerGroup1))); - float outerGroup2Weight = (1.0 / (1.0 + Luma(outerGroup2))); - float outerGroup3Weight = (1.0 / (1.0 + Luma(outerGroup3))); - float innerGroupWeight = (1.0 / (1.0 + Luma(innerGroup))); + AeF16 outerGroup0Weight = (AeF16(1.0) / (AeF16(1.0) + Luma(outerGroup0))); + AeF16 outerGroup1Weight = (AeF16(1.0) / (AeF16(1.0) + Luma(outerGroup1))); + AeF16 outerGroup2Weight = (AeF16(1.0) / (AeF16(1.0) + Luma(outerGroup2))); + AeF16 outerGroup3Weight = (AeF16(1.0) / (AeF16(1.0) + Luma(outerGroup3))); + AeF16 innerGroupWeight = (AeF16(1.0) / (AeF16(1.0) + Luma(innerGroup))); outerGroup0 *= outerGroup0Weight; outerGroup1 *= outerGroup1Weight; diff --git a/data/shader/bloom/bloomUpsample.csh b/data/shader/bloom/bloomUpsample.csh index ee399301d..d533c1d9e 100644 --- a/data/shader/bloom/bloomUpsample.csh +++ b/data/shader/bloom/bloomUpsample.csh @@ -1,3 +1,5 @@ +#include <../common/types.hsh> + layout (local_size_x = 8, local_size_y = 8) in; layout (set = 3, binding = 0, rgba16f) writeonly uniform image2D textureOut; @@ -9,9 +11,9 @@ layout(push_constant) uniform constants { float filterSize; } pushConstants; -vec3 Sample(vec2 texCoord) { +AeF16x3 Sample(vec2 texCoord) { - return textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb; + return AeF16x3(textureLod(textureIn, texCoord, float(pushConstants.mipLevel)).rgb); } @@ -31,24 +33,24 @@ void main() { texelSize = max(filterSize, filterSize); // We always sample at pixel border, not centers - vec3 filter00 = Sample(texCoord + vec2(-texelSize.x, -texelSize.y)); - vec3 filter10 = Sample(texCoord + vec2(0.0, -texelSize.y)); - vec3 filter20 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); + AeF16x3 filter00 = Sample(texCoord + vec2(-texelSize.x, -texelSize.y)); + AeF16x3 filter10 = Sample(texCoord + vec2(0.0, -texelSize.y)); + AeF16x3 filter20 = Sample(texCoord + vec2(texelSize.x, -texelSize.y)); - vec3 filter01 = Sample(texCoord + vec2(-texelSize.x, 0.0)); - vec3 filter11 = Sample(texCoord + vec2(0.0, 0.0)); - vec3 filter21 = Sample(texCoord + vec2(texelSize.x, 0.0)); + AeF16x3 filter01 = Sample(texCoord + vec2(-texelSize.x, 0.0)); + AeF16x3 filter11 = Sample(texCoord + vec2(0.0, 0.0)); + AeF16x3 filter21 = Sample(texCoord + vec2(texelSize.x, 0.0)); - vec3 filter02 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); - vec3 filter12 = Sample(texCoord + vec2(0.0, texelSize.y)); - vec3 filter22 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); + AeF16x3 filter02 = Sample(texCoord + vec2(-texelSize.x, texelSize.y)); + AeF16x3 filter12 = Sample(texCoord + vec2(0.0, texelSize.y)); + AeF16x3 filter22 = Sample(texCoord + vec2(texelSize.x, texelSize.y)); - vec3 filtered = vec3(0.0); + AeF16x3 filtered = AeF16x3(0.0); - filtered += 4.0 * filter11; - filtered += 2.0 * (filter10 + filter01 + filter21 + filter12); - filtered += 1.0 * (filter00 + filter20 + filter02 + filter22); - filtered /= 16.0; + filtered += AeF16(4.0) * filter11; + filtered += AeF16(2.0) * (filter10 + filter01 + filter21 + filter12); + filtered += AeF16(1.0) * (filter00 + filter20 + filter02 + filter22); + filtered /= AeF16(16.0); if (pushConstants.additive > 0) { imageStore(textureOut, coord, vec4(filtered + filter11, 1.0)); diff --git a/data/shader/common/types.hsh b/data/shader/common/types.hsh new file mode 100644 index 000000000..dd790c8a6 --- /dev/null +++ b/data/shader/common/types.hsh @@ -0,0 +1,48 @@ +#extension GL_EXT_shader_explicit_arithmetic_types : require +#extension GL_EXT_shader_16bit_storage : require + +#define AeBool bool +#define AeF32 float +#define AeF32x2 vec2 +#define AeF32x3 vec3 +#define AeF32x4 vec4 +#define AeUI32 uint +#define AeUI32x2 uvec2 +#define AeUI32x3 uvec3 +#define AeUI32x4 uvec4 +#define AeI32 int +#define AeI32x2 ivec2 +#define AeI32x3 ivec3 +#define AeI32x4 ivec4 + +#ifdef AE_HALF_FLOAT +#define AeF16 float16_t +#define AeF16x2 f16vec2 +#define AeF16x3 f16vec3 +#define AeF16x4 f16vec4 +#define AeUI16 uint16_t +#define AeUI16x2 u16vec2 +#define AeUI16x3 u16vec3 +#define AeUI16x4 u16vec4 +#define AeI16 int16_t +#define AeI16x2 i16vec2 +#define AeI16x3 i16vec3 +#define AeI16x4 i16vec4 +#define AeF16x4x4 f16mat4x4 +#define AeF16x3x3 f16mat3x3 +#else +#define AeF16 float +#define AeF16x2 vec2 +#define AeF16x3 vec3 +#define AeF16x4 vec4 +#define AeUI16 uint +#define AeUI16x2 uvec2 +#define AeUI16x3 uvec3 +#define AeUI16x4 uvec4 +#define AeI16 int +#define AeI16x2 ivec2 +#define AeI16x3 ivec3 +#define AeI16x4 ivec4 +#define AeF16x4x4 mat4 +#define AeF16x3x3 mat3 +#endif \ No newline at end of file diff --git a/data/shader/common/utility.hsh b/data/shader/common/utility.hsh index 0d629b20a..aea15a3d5 100644 --- a/data/shader/common/utility.hsh +++ b/data/shader/common/utility.hsh @@ -1,5 +1,6 @@ // Contains useful functions #include +#include float saturate(float value) { @@ -25,6 +26,30 @@ vec4 saturate(vec4 value) { } +AeF16 saturate(AeF16 value) { + + return clamp(value, AeF16(0.0), AeF16(1.0)); + +} + +AeF16x2 saturate(AeF16x2 value) { + + return clamp(value, AeF16x2(0.0), AeF16x2(1.0)); + +} + +AeF16x3 saturate(AeF16x3 value) { + + return clamp(value, AeF16x3(0.0), AeF16x3(1.0)); + +} + +AeF16x4 saturate(AeF16x4 value) { + + return clamp(value, AeF16x4(0.0), AeF16x4(1.0)); + +} + float sqr(float value) { return value * value; diff --git a/data/shader/common/ycocg.hsh b/data/shader/common/ycocg.hsh index b19cc8990..54bd89715 100644 --- a/data/shader/common/ycocg.hsh +++ b/data/shader/common/ycocg.hsh @@ -1,6 +1,11 @@ +#include + const mat3 RGBToYCoCgMatrix = mat3(0.25, 0.5, -0.25, 0.5, 0.0, 0.5, 0.25, -0.5, -0.25); const mat3 YCoCgToRGBMatrix = mat3(1.0, 1.0, 1.0, 1.0, 0.0, -1.0, -1.0, 1.0, -1.0); +const AeF16x3x3 F16RGBToYCoCgMatrix = AeF16x3x3(0.25, 0.5, -0.25, 0.5, 0.0, 0.5, 0.25, -0.5, -0.25); +const AeF16x3x3 F16YCoCgToRGBMatrix = AeF16x3x3(1.0, 1.0, 1.0, 1.0, 0.0, -1.0, -1.0, 1.0, -1.0); + vec3 RGBToYCoCg(vec3 RGB) { return RGBToYCoCgMatrix * RGB; @@ -12,3 +17,16 @@ vec3 YCoCgToRGB(vec3 YCoCg) { return YCoCgToRGBMatrix * YCoCg; } + +AeF16x3 RGBToYCoCg(AeF16x3 RGB) { + + return F16RGBToYCoCgMatrix * RGB; + +} + +AeF16x3 YCoCgToRGB(AeF16x3 YCoCg) { + + return F16YCoCgToRGBMatrix * YCoCg; + +} + diff --git a/data/shader/ddgi/ddgi.hsh b/data/shader/ddgi/ddgi.hsh index 703860a52..83466ccd5 100644 --- a/data/shader/ddgi/ddgi.hsh +++ b/data/shader/ddgi/ddgi.hsh @@ -145,6 +145,24 @@ bool IsInsideCascade(vec3 position, int cascadeIndex) { } +vec3 GetCellSize(vec3 position) { + + int cascadeIndex = 0; + while (cascadeIndex < ddgiData.cascadeCount) { + + bool isInside = IsInsideCascade(position, cascadeIndex); + if (!isInside) + break; + + cascadeIndex++; + } + + cascadeIndex = max(cascadeIndex - 1, 0); + + return ddgiData.cascades[cascadeIndex].cellSize.xyz; + +} + void GetProbeHistoryInfo(ivec3 probeIndex, int cascadeIndex, out ivec3 historyProbeCoord, out bool reset) { ivec3 cascadeProbeOffset = ivec3(0, cascadeIndex * ddgiData.volumeProbeCount.y, 0); diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh index 60e30265f..dfc3b722b 100644 --- a/data/shader/deferred/direct.csh +++ b/data/shader/deferred/direct.csh @@ -74,7 +74,7 @@ void main() { float depth = texelFetch(depthTexture, pixel, 0).r; int lightCount = 0; - + // Load to get the atmosphere which was rendered before vec3 direct = imageLoad(image, pixel).rgb; if (depth < 1.0) { @@ -82,8 +82,7 @@ void main() { // We don't have any light direction, that's why we use vec3(0.0, -1.0, 0.0) as a placeholder Surface surface = GetSurface(texCoord, depth, vec3(0.0, -1.0, 0.0), geometryNormal); - direct = vec3(0.0); - + direct = vec3(0.0); for (uint i = 0u; i < pushConstants.lightBucketCount; i++) { uint lightBucket = sharedLightBuckets[i]; @@ -162,6 +161,8 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai if (attenuation == 0.0) return vec3(0.0); + float shadowFactor = GetShadowFactor(light, surface, lightType, geometryNormal, isMain); + UpdateSurface(surface); // Direct diffuse + specular BRDF @@ -170,8 +171,6 @@ vec3 EvaluateLight(Light light, Surface surface, vec3 geometryNormal, bool isMai vec3 direct = directDiffuse + directSpecular; - float shadowFactor = GetShadowFactor(light, surface, lightType, geometryNormal, isMain); - vec3 radiance = light.color.rgb * light.intensity * attenuation; direct = direct * radiance * surface.NdotL * shadowFactor; diff --git a/data/shader/deferred/lightCulling.hsh b/data/shader/deferred/lightCulling.hsh index 2edf00474..5b2dfff32 100644 --- a/data/shader/deferred/lightCulling.hsh +++ b/data/shader/deferred/lightCulling.hsh @@ -77,8 +77,8 @@ AABB CalculateAABB(vec3 corners[8]) { } AABB aabb; - aabb.center = (aabbMax + aabbMin) * 0.5; - aabb.extent = aabbMax - aabb.center; + aabb.extent = (aabbMax - aabbMin) * 0.5; + aabb.center = aabbMin + aabb.extent; return aabb; } diff --git a/data/shader/gbuffer/downsampleGBuffer2x.csh b/data/shader/gbuffer/downsampleGBuffer2x.csh index eb40adc51..6ed30fa5f 100644 --- a/data/shader/gbuffer/downsampleGBuffer2x.csh +++ b/data/shader/gbuffer/downsampleGBuffer2x.csh @@ -20,12 +20,18 @@ layout (set = 3, binding = 10, rg16f) writeonly uniform image2D velocityOut; layout (set = 3, binding = 11, r16ui) writeonly uniform uimage2D materialIdxOut; layout (set = 3, binding = 12, r8i) writeonly uniform iimage2D offsetOut; -float Checkerboard(ivec2 coord) { +float Checkerboard2x(ivec2 coord) { return float((coord.x + coord.y % 2) % 2); } +float Checkerboard4x(ivec2 coord) { + + return float((coord.x + coord.y % 4) % 4); + +} + int MinDepth(vec4 depthVec, out float minDepth) { int idx = 0; @@ -64,7 +70,7 @@ int MaxDepth(vec4 depthVec, out float maxDepth) { int CheckerboardDepth(vec4 depthVec, ivec2 coord, out float depth) { - float minmax = Checkerboard(coord); + float minmax = Checkerboard2x(coord); float maxDepth; int maxIdx = MaxDepth(depthVec, maxDepth); @@ -90,8 +96,9 @@ void main() { float depth11 = texelFetch(depthIn, coord * 2 + ivec2(1, 1), 0).r; vec4 depthVec = vec4(depth00, depth10, depth01, depth11); - int depthIdx = (CheckerboardDepth(depthVec, coord, depthVec.x) + int(globalData.frameCount)) % 4; - //depthIdx = int(globalData.frameCount) % 4; + //int depthIdx = (CheckerboardDepth(depthVec, coord, depthVec.x) + int(globalData.frameCount)) % 4; + int depthIdx = int(globalData.frameCount) % 4; + //int depthIdx = (int(Checkerboard4x(coord)) + int(globalData.frameCount)) % 4; float depth = depthVec[depthIdx]; imageStore(depthOut, coord, vec4(depth, 0.0, 0.0, 1.0)); diff --git a/data/shader/gbuffer/generateReactiveMask.csh b/data/shader/gbuffer/generateReactiveMask.csh index f2128fe8c..2c9124dac 100644 --- a/data/shader/gbuffer/generateReactiveMask.csh +++ b/data/shader/gbuffer/generateReactiveMask.csh @@ -4,6 +4,7 @@ layout (local_size_x = 8, local_size_y = 8) in; layout (set = 3, binding = 0, r8) uniform image2D reactiveMaskImage; layout (set = 3, binding = 1) uniform usampler2D stencilTexture; +layout (set = 3, binding = 2) uniform sampler2D roughnessMetalnessAoTexture; void main() { @@ -18,6 +19,10 @@ void main() { StencilFeatures features = DecodeStencilFeatures(texelFetch(stencilTexture, pixel, 0).r); reactivity = features.responsivePixel ? 0.8 : reactivity; + vec3 roughnessMetallicAo = texelFetch(roughnessMetalnessAoTexture, pixel, 0).rgb; + float reflectiveReactivity = min(1.0, 5.0 * roughnessMetallicAo.r); + //reactivity = max(reactivity, mix(1.0, 0.0, reflectiveReactivity)); + imageStore(reactiveMaskImage, pixel, vec4(reactivity, 0.0, 0.0, 0.0)); } diff --git a/data/shader/gbuffer/patchGBufferNormals.csh b/data/shader/gbuffer/patchGBuffer.csh similarity index 50% rename from data/shader/gbuffer/patchGBufferNormals.csh rename to data/shader/gbuffer/patchGBuffer.csh index d92c25f0b..355295dc7 100644 --- a/data/shader/gbuffer/patchGBufferNormals.csh +++ b/data/shader/gbuffer/patchGBuffer.csh @@ -3,8 +3,9 @@ layout (local_size_x = 8, local_size_y = 8) in; layout (set = 3, binding = 0, rg16f) uniform image2D normalImage; -layout (set = 3, binding = 1) uniform sampler2D geometryNormalTexture; -layout (set = 3, binding = 2) uniform usampler2D materialIdxTexture; +layout (set = 3, binding = 1, rgba16f) uniform image2D roughnessMetalnessAoImage; +layout (set = 3, binding = 2) uniform sampler2D geometryNormalTexture; +layout (set = 3, binding = 3) uniform usampler2D materialIdxTexture; void main() { @@ -15,6 +16,8 @@ void main() { coord.y < size.y) { vec2 normal = imageLoad(normalImage, coord).rg; + vec3 roughnessMetalnessAo = imageLoad(roughnessMetalnessAoImage, coord).rgb; + vec2 geometryNormal = texelFetch(geometryNormalTexture, coord, 0).rg; uint materialIdx = texelFetch(materialIdxTexture, coord, 0).r; @@ -22,7 +25,12 @@ void main() { normal = material.normalMap ? normal : geometryNormal; + roughnessMetalnessAo.r = material.roughnessMap ? roughnessMetalnessAo.r * material.roughness : material.roughness; + roughnessMetalnessAo.g = material.metalnessMap ? roughnessMetalnessAo.g * material.metalness : material.metalness; + roughnessMetalnessAo.b = material.aoMap ? roughnessMetalnessAo.b * material.ao : material.ao; + imageStore(normalImage, coord, vec4(normal, 0.0, 0.0)); + imageStore(roughnessMetalnessAoImage, coord, vec4(roughnessMetalnessAo, 0.0)); } diff --git a/data/shader/raytracer/surface.hsh b/data/shader/raytracer/surface.hsh index dee0d58a8..ec95b1772 100644 --- a/data/shader/raytracer/surface.hsh +++ b/data/shader/raytracer/surface.hsh @@ -141,8 +141,7 @@ Surface GetSurfaceParameters(Instance instance, Triangle tri, Ray ray, surface.geometryNormal = geometryNormal; - surface.F0 = mix(vec3(0.04), surface.material.baseColor, - surface.material.metalness); + surface.F0 = mix(vec3(0.04), surface.material.baseColor, surface.material.metalness); surface.F90 = 1.0; return surface; diff --git a/data/shader/reflection/atrous.csh b/data/shader/reflection/atrous.csh index cc7eded9f..2f12ae863 100644 --- a/data/shader/reflection/atrous.csh +++ b/data/shader/reflection/atrous.csh @@ -1,3 +1,5 @@ +#include <../common/types.hsh> + #include <../common/utility.hsh> #include <../common/convert.hsh> #include <../common/flatten.hsh> @@ -36,7 +38,8 @@ struct PixelData { struct PackedPixelData { // Contains 16 bit color, variance, normal and roughness - uvec4 data; + f16vec4 color; + f16vec4 data; float depth; }; @@ -52,10 +55,9 @@ const float kernelWeights[3] = { 1.0, 2.0 / 3.0, 1.0 / 6.0 }; PackedPixelData PackPixelData(PixelData data) { PackedPixelData compressed; - compressed.data.x = packHalf2x16(data.color.rg); - compressed.data.y = packHalf2x16(data.color.ba); - compressed.data.z = packHalf2x16(data.normal.xy); - compressed.data.w = packHalf2x16(vec2(data.normal.z, data.roughness)); + compressed.color.rgba = f16vec4(data.color); + compressed.data.xyz = f16vec3(data.normal); + compressed.data.w = float16_t(data.roughness); compressed.depth = data.depth; return compressed; @@ -64,12 +66,9 @@ PackedPixelData PackPixelData(PixelData data) { PixelData UnpackPixelData(PackedPixelData compressed) { PixelData data; - data.color.rg = unpackHalf2x16(compressed.data.x); - data.color.ba = unpackHalf2x16(compressed.data.y); - data.normal.xy = unpackHalf2x16(compressed.data.z); - vec2 temp = unpackHalf2x16(compressed.data.w); - data.normal.z = temp.x; - data.roughness = temp.y; + data.color.rgba = compressed.color.rgba; + data.normal.xyz = compressed.data.rgb; + data.roughness = compressed.data.a; data.depth = compressed.depth; return data; @@ -92,12 +91,7 @@ void LoadGroupSharedData() { data.color = texelFetch(inputTexture, texel, 0); data.depth = texelFetch(depthTexture, texel, 0).r; - - uint materialIdx = texelFetch(materialIdxTexture, texel, 0).r; - Material material = UnpackMaterial(materialIdx); - - data.roughness = material.roughness; - data.roughness *= material.roughnessMap ? texelFetch(roughnessTexture, texel, 0).r : 1.0; + data.roughness = texelFetch(roughnessTexture, texel, 0).r; data.normal = DecodeNormal(texelFetch(normalTexture, texel, 0).rg); @@ -243,6 +237,7 @@ void main() { outputColor = outputColor / vec4(vec3(totalWeight), totalWeight * totalWeight); + imageStore(outputImage, pixel, vec4(centerColor.a)); imageStore(outputImage, pixel, outputColor); } \ No newline at end of file diff --git a/data/shader/reflection/rtreflection.csh b/data/shader/reflection/rtreflection.csh index c1e607301..ed4578f0f 100644 --- a/data/shader/reflection/rtreflection.csh +++ b/data/shader/reflection/rtreflection.csh @@ -77,7 +77,11 @@ void main() { vec2 texCoord = (vec2(pixel) + vec2(0.5)) / vec2(resolution); +#ifdef SSR vec4 reflection = imageLoad(rtrImage, pixel); +#else + vec4 reflection = vec4(0.0); +#endif // No need, there is no offset right now int offsetIdx = texelFetch(offsetTexture, pixel, 0).r; @@ -89,7 +93,7 @@ void main() { if (uniforms.halfRes > 0) recontructTexCoord = (2.0 * (vec2(pixel)) + offset + 0.5) / (2.0 * vec2(resolution)); else - recontructTexCoord = (vec2(pixel) + 0.5) / (vec2(resolution)); + recontructTexCoord = (2.0 * (vec2(pixel)) + offset + 0.5) / (2.0 * vec2(resolution)); vec3 viewPos = ConvertDepthToViewSpace(depth, recontructTexCoord); vec3 worldPos = vec3(globalData.ivMatrix * vec4(viewPos, 1.0)); @@ -196,27 +200,27 @@ vec3 EvaluateHit(inout Ray ray) { bool backfaceHit; Surface surface = GetSurfaceParameters(instance, tri, ray, false, backfaceHit, uniforms.textureLevel); - - radiance += surface.material.emissiveColor; - - float curSeed = float(uniforms.frameSeed) / 255.0 + float(ray.ID) * float(uniforms.sampleCount); - // Evaluate direct light - for (int i = 0; i < uniforms.lightSampleCount; i++) { - radiance += EvaluateDirectLight(surface, curSeed); - curSeed += 1.0 / float(uniforms.lightSampleCount); - } - - radiance /= float(uniforms.lightSampleCount); // Evaluate indirect lighting #ifdef DDGI vec3 irradiance = GetLocalIrradiance(surface.P, surface.V, surface.N).rgb; // Approximate indirect specular for ray by using the irradiance grid // This enables metallic materials to have some kind of secondary reflection + + surface.NdotV = saturate(dot(surface.N, surface.V)); vec3 indirect = EvaluateIndirectDiffuseBRDF(surface) * irradiance + EvaluateIndirectSpecularBRDF(surface) * irradiance; - radiance += IsInsideVolume(surface.P) ? indirect * ddgiData.volumeStrength : vec3(0.0); + radiance += IsInsideVolume(surface.P) ? indirect : vec3(0.0); #endif + + radiance += surface.material.emissiveColor; + + float curSeed = float(uniforms.frameSeed) / 255.0 + float(ray.ID) * float(uniforms.sampleCount); + // Evaluate direct light + for (int i = 0; i < uniforms.lightSampleCount; i++) { + radiance += (EvaluateDirectLight(surface, curSeed) / float(uniforms.lightSampleCount)); + curSeed += 1.0 / float(uniforms.lightSampleCount); + } return radiance; diff --git a/data/shader/reflection/temporal.csh b/data/shader/reflection/temporal.csh index eebce87e5..887304f31 100644 --- a/data/shader/reflection/temporal.csh +++ b/data/shader/reflection/temporal.csh @@ -91,7 +91,7 @@ void LoadGroupSharedData() { texel = clamp(texel, ivec2(0), ivec2(resolution) - ivec2(1)); - sharedRadianceDepth[i].rgb = FetchTexel(texel); + sharedRadianceDepth[i].rgb = RGBToYCoCg(FetchTexel(texel)); sharedRadianceDepth[i].a = ConvertDepthToViewSpaceDepth(texelFetch(depthTexture, texel, 0).r); } @@ -317,7 +317,7 @@ void ComputeVarianceMinMax(float roughness, out vec3 mean, out vec3 std) { // This could be varied using the temporal variance estimation // By using a wide neighborhood for variance estimation (8x8) we introduce block artifacts // These are similiar to video compression artifacts, the spatial filter mostly clears them up - const int radius = int(mix(1.0, float(kernelRadius), min(1.0, roughness * 2.0))); + const int radius = int(mix(5.0, float(kernelRadius), min(1.0, roughness * 2.0))); ivec2 pixel = ivec2(gl_GlobalInvocationID); float depth = texelFetch(depthTexture, pixel, 0).r; @@ -331,7 +331,7 @@ void ComputeVarianceMinMax(float roughness, out vec3 mean, out vec3 std) { for (int j = -radius; j <= radius; j++) { int sharedMemoryIdx = GetSharedMemoryIndex(ivec2(i, j)); - vec3 sampleRadiance = RGBToYCoCg(FetchCurrentRadiance(sharedMemoryIdx)); + vec3 sampleRadiance = FetchCurrentRadiance(sharedMemoryIdx); float sampleLinearDepth = FetchDepth(sharedMemoryIdx); float depthPhi = max(1.0, abs(0.025 * linearDepth)); @@ -357,18 +357,14 @@ void main() { pixel.y > imageSize(resolveImage).y) return; - uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; - Material material = UnpackMaterial(materialIdx); - - float roughness = material.roughness; - roughness *= material.roughnessMap ? texelFetch(roughnessMetallicAoTexture, pixel, 0).r : 1.0; + float roughness = texelFetch(roughnessMetallicAoTexture, pixel, 0).r; vec3 mean, std; ComputeVarianceMinMax(roughness, mean, std); ivec2 velocityPixel = pixel; vec2 velocity = texelFetch(velocityTexture, velocityPixel, 0).rg; - + vec2 uv = (vec2(pixel) + vec2(0.5)) * invResolution + velocity; vec2 historyPixel = vec2(pixel) + velocity * resolution; @@ -410,7 +406,7 @@ void main() { currentColor = YCoCgToRGB(currentColor); float temporalWeight = mix(pushConstants.temporalWeight, 0.5, adjClipBlend); - float factor = clamp(32.0 * log(roughness + 1.0), 0.875, temporalWeight); + float factor = clamp(32.0 * log(roughness + 1.0), 0.5, temporalWeight); valid = (uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0 || uv.y > 1.0) ? false : valid; @@ -426,7 +422,7 @@ void main() { factor = min(factor, historyLength / (historyLength + 1.0)); #ifdef UPSCALE - factor = validPixel >= 1.5 ? factor : (valid ? mix(1.0, 0.5, adjClipBlend) : factor); + factor = validPixel >= 1.5 ? factor : (valid ? mix(1.0, 0.0, adjClipBlend) : factor); #endif vec3 resolve = factor <= 0.0 ? currentColor : mix(currentColor, historyColor, factor); @@ -440,6 +436,6 @@ void main() { variance = roughness <= 0.1 ? variance * 0.0 : variance; imageStore(momentsImage, pixel, vec4(momentsResolve, historyLength + 1.0, 0.0)); - imageStore(resolveImage, pixel, vec4(vec3(resolve), 0.0)); + imageStore(resolveImage, pixel, vec4(vec3(resolve), variance)); } \ No newline at end of file diff --git a/data/shader/reflection/upsample.csh b/data/shader/reflection/upsample.csh index 9516bd9c8..d0f7b448a 100644 --- a/data/shader/reflection/upsample.csh +++ b/data/shader/reflection/upsample.csh @@ -92,6 +92,9 @@ vec4 Upsample(float referenceDepth, vec3 referenceNormal, vec2 highResPixel) { float normalWeight = min(pow(max(dot(referenceNormal, normals[sharedMemoryOffset]), 0.0), 256.0), 1.0); float weight = depthWeight * normalWeight * weights[i]; + result += vec4(data[sharedMemoryOffset], 1.0) * weight; + + totalWeight += weight; if (weight > maxWeight) { maxWeight = weight; closestMemoryOffset = sharedMemoryOffset; @@ -99,9 +102,9 @@ vec4 Upsample(float referenceDepth, vec3 referenceNormal, vec2 highResPixel) { } - result = vec4(data[closestMemoryOffset], 1.0); + //result = vec4(data[closestMemoryOffset], 1.0); - return result; + return vec4(result.rgb, 1.0); } @@ -134,8 +137,9 @@ void main() { //upsampleResult.rgb = vec3(offsetIdx); if (downSamplePixel * 2 + offset == pixel) { - int sharedMemoryOffset = Flatten2D(downSamplePixel, unflattenedDepthDataSize); - //upsampleResult.rgb = data[sharedMemoryOffset]; + ivec2 samplePixel = ivec2(gl_LocalInvocationID) / 2 + ivec2(1); + int sharedMemoryOffset = Flatten2D(samplePixel, unflattenedDepthDataSize); + upsampleResult.rgb = data[sharedMemoryOffset]; } imageStore(image, pixel, upsampleResult); diff --git a/data/shader/rtgi/rtgi.csh b/data/shader/rtgi/rtgi.csh index c9979af8f..a0e31f944 100644 --- a/data/shader/rtgi/rtgi.csh +++ b/data/shader/rtgi/rtgi.csh @@ -91,14 +91,20 @@ void main() { vec3 viewPos = ConvertDepthToViewSpace(depth, recontructTexCoord); vec3 worldPos = vec3(globalData.ivMatrix * vec4(viewPos, 1.0)); - vec3 viewVec = vec3(globalData.ivMatrix * vec4(viewPos, 0.0)); + vec3 worldView = normalize(vec3(globalData.ivMatrix * vec4(viewPos, 0.0))); vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(DecodeNormal(textureLod(normalTexture, texCoord, 0).rg), 0.0))); uint materialIdx = texelFetch(materialIdxTexture, pixel, 0).r; Material material = UnpackMaterial(materialIdx); - float roughness = texelFetch(roughnessMetallicAoTexture, pixel, 0).r; - material.roughness *= material.roughnessMap ? roughness : 1.0; +#ifdef DDGI + bool insideVolume = IsInsideVolume(worldPos); + vec3 probeIrradiance = GetLocalIrradiance(worldPos, -worldView, worldNorm).rgb * ddgiData.volumeStrength; + probeIrradiance = insideVolume ? probeIrradiance : vec3(0.0); +#else + bool insideVolume = false; + vec3 probeIrradiance = vec3(0.0); +#endif vec3 reflection = vec3(0.0); @@ -113,7 +119,7 @@ void main() { SampleBlueNoise(pixel, sampleIdx, 1, scramblingRankingTexture, sobolSequenceTexture) ); - vec3 V = normalize(-viewVec); + vec3 V = normalize(-worldView); vec3 N = worldNorm; Surface surface = CreateSurface(V, N, vec3(1.0), material); @@ -123,7 +129,6 @@ void main() { Ray ray; float pdf = 1.0; - BRDFSample brdfSample; float NdotL; ImportanceSampleCosDir(N, blueNoiseVec, ray.direction, NdotL, pdf); @@ -140,14 +145,19 @@ void main() { ray.hitID = -1; ray.hitDistance = 0.0; + float rayLength = insideVolume ? length(GetCellSize(worldPos)) : INF; + vec3 radiance = vec3(0.0); #ifdef OPACITY_CHECK - HitClosestTransparency(ray, INSTANCE_MASK_ALL, 0.0, INF); + HitClosestTransparency(ray, INSTANCE_MASK_ALL, 0.0, rayLength); #else - HitClosest(ray, INSTANCE_MASK_ALL, 0.0, INF); + HitClosest(ray, INSTANCE_MASK_ALL, 0.0, rayLength); #endif - radiance = EvaluateHit(ray); + if (ray.hitID >= 0 || !insideVolume) + radiance = EvaluateHit(ray); + else + radiance = probeIrradiance; float radianceMax = max(max(max(radiance.r, max(radiance.g, radiance.b)), uniforms.radianceLimit), 0.01); @@ -180,28 +190,27 @@ vec3 EvaluateHit(inout Ray ray) { bool backfaceHit; Surface surface = GetSurfaceParameters(instance, tri, ray, false, backfaceHit, uniforms.textureLevel); - - radiance += surface.material.emissiveColor; - - float curSeed = float(uniforms.frameSeed) / 255.0; - // Evaluate direct light - for (int i = 0; i < uniforms.lightSampleCount; i++) { - radiance += EvaluateDirectLight(surface, curSeed); - curSeed += 1.0 / float(uniforms.lightSampleCount); - } - radiance /= float(uniforms.lightSampleCount); - - // Evaluate indirect lighting #ifdef DDGI + surface.NdotV = saturate(dot(surface.N, surface.V)); vec3 irradiance = GetLocalIrradiance(surface.P, surface.V, surface.N).rgb; + //vec3 irradiance = GetLocalIrradiance(surface.P, surface.V, surface.N).rgb; // Approximate indirect specular for ray by using the irradiance grid // This enables metallic materials to have some kind of secondary reflection vec3 indirect = EvaluateIndirectDiffuseBRDF(surface) * irradiance + EvaluateIndirectSpecularBRDF(surface) * irradiance; radiance += IsInsideVolume(surface.P) ? indirect * ddgiData.volumeStrength : vec3(0.0); #endif + + radiance += surface.material.emissiveColor; + float curSeed = float(uniforms.frameSeed) / 255.0; + // Evaluate direct light + for (int i = 0; i < uniforms.lightSampleCount; i++) { + radiance += (EvaluateDirectLight(surface, curSeed) / float(uniforms.lightSampleCount)); + curSeed += 1.0 / float(uniforms.lightSampleCount); + } + return radiance; } @@ -219,21 +228,23 @@ vec3 EvaluateDirectLight(inout Surface surface, inout float seed) { float solidAngle, lightDistance; SampleLight(light, surface, raySeed, seed, solidAngle, lightDistance); +#ifdef USE_SHADOW_MAP + float shadowFactor = CalculateShadowWorldSpace(uniforms.shadow, cascadeMaps, surface.P, + surface.geometryNormal, saturate(dot(surface.L, surface.geometryNormal))); +#else + float shadowFactor = 1.0; + if (light.castShadow) + shadowFactor *= CheckVisibility(surface, lightDistance); +#endif + // Evaluate the BRDF vec3 reflectance = EvaluateDiffuseBRDF(surface) + EvaluateSpecularBRDF(surface); reflectance *= surface.material.opacity; - vec3 radiance = light.radiance * solidAngle; + vec3 radiance = light.radiance * solidAngle * shadowFactor; // Check for visibilty. This is important to get an // estimate of the solid angle of the light from point P // on the surface. -#ifdef USE_SHADOW_MAP - radiance *= CalculateShadowWorldSpace(uniforms.shadow, cascadeMaps, surface.P, - surface.geometryNormal, saturate(dot(surface.L, surface.geometryNormal))); -#else - if (light.castShadow) - radiance *= CheckVisibility(surface, lightDistance); -#endif #ifdef CLOUD_SHADOWS if (light.type == uint(DIRECTIONAL_LIGHT)) { diff --git a/data/shader/rtgi/temporal.csh b/data/shader/rtgi/temporal.csh index d67fad1ed..1dccc5a59 100644 --- a/data/shader/rtgi/temporal.csh +++ b/data/shader/rtgi/temporal.csh @@ -93,7 +93,7 @@ void LoadGroupSharedData() { texel = clamp(texel, ivec2(0), ivec2(resolution) - ivec2(1)); - sharedRadianceDepth[i].rgb = FetchTexel(texel); + sharedRadianceDepth[i].rgb = RGBToYCoCg(FetchTexel(texel)); sharedRadianceDepth[i].a = texelFetch(depthTexture, texel, 0).r; sharedMaterialIdx[i].r = texelFetch(materialIdxTexture, texel, 0).r; } @@ -361,7 +361,7 @@ void ComputeVarianceMinMax(out vec3 mean, out vec3 std) { int sharedMemoryIdx = GetSharedMemoryIndex(ivec2(i, j)); - vec3 sampleRadiance = RGBToYCoCg(FetchCurrentRadiance(sharedMemoryIdx)); + vec3 sampleRadiance = FetchCurrentRadiance(sharedMemoryIdx); float sampleDepth = FetchDepth(sharedMemoryIdx); uint sampleMaterialIdx = FetchMaterialIdx(sharedMemoryIdx); diff --git a/libs/ImguiExtension/panels/ReflectionPanel.cpp b/libs/ImguiExtension/panels/ReflectionPanel.cpp index 5df2dd941..0b8d626c6 100644 --- a/libs/ImguiExtension/panels/ReflectionPanel.cpp +++ b/libs/ImguiExtension/panels/ReflectionPanel.cpp @@ -7,6 +7,8 @@ namespace Atlas::ImguiExtension { ImGui::PushID(GetNameID()); ImGui::Checkbox("Enable", &reflection->enable); + ImGui::Checkbox("Enable RT", &reflection->rt); + ImGui::Checkbox("Enable SSR", &reflection->ssr); ImGui::Checkbox("Half resolution", &reflection->halfResolution); ImGui::Checkbox("Upsample before filtering", &reflection->upsampleBeforeFiltering); diff --git a/src/engine/graphics/Shader.cpp b/src/engine/graphics/Shader.cpp index 094858651..d14c723b6 100644 --- a/src/engine/graphics/Shader.cpp +++ b/src/engine/graphics/Shader.cpp @@ -69,6 +69,10 @@ namespace Atlas { macros.push_back("AE_BINDLESS"); } + if (device->support.shaderFloat16) { + macros.push_back("AE_HALF_FLOAT"); + } + #ifdef AE_OS_MACOS macros.push_back("AE_OS_MACOS"); #endif diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index d90726cba..08079c969 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -136,7 +136,7 @@ namespace Atlas { for (auto entity : subset) { const auto& [meshComponent, transformComponent] = subset.Get(entity); - if (!renderState->blasToBindlessIdx.contains(meshComponent.mesh->blas)) + if (!meshComponent.mesh.IsLoaded() || !renderState->blasToBindlessIdx.contains(meshComponent.mesh->blas)) continue; auto &blasInfo = blasInfos[meshComponent.mesh->blas]; diff --git a/src/engine/renderer/GBufferRenderer.cpp b/src/engine/renderer/GBufferRenderer.cpp index 1d2e364c2..115ff9879 100644 --- a/src/engine/renderer/GBufferRenderer.cpp +++ b/src/engine/renderer/GBufferRenderer.cpp @@ -11,7 +11,7 @@ namespace Atlas { downscalePipelineConfig = PipelineConfig("gbuffer/downsampleGBuffer2x.csh"); downscaleDepthOnlyPipelineConfig = PipelineConfig("gbuffer/downsampleGBuffer2x.csh", {"DEPTH_ONLY"}); - patchNormalPipelineConfig = PipelineConfig("gbuffer/patchGBufferNormals.csh"); + patchNormalPipelineConfig = PipelineConfig("gbuffer/patchGBuffer.csh"); generateReactiveMaskPipelineConfig = PipelineConfig("gbuffer/generateReactiveMask.csh"); } @@ -48,9 +48,9 @@ namespace Atlas { } - void GBufferRenderer::FillNormalTexture(const Ref& target, Graphics::CommandList* commandList) { + void GBufferRenderer::Patch(const Ref& target, Graphics::CommandList* commandList) { - Graphics::Profiler::BeginQuery("Patch GBuffer normals"); + Graphics::Profiler::BeginQuery("Patch GBuffer"); auto pipeline = PipelineManager::GetPipeline(patchNormalPipelineConfig); commandList->BindPipeline(pipeline); @@ -59,6 +59,7 @@ namespace Atlas { auto normal = rt->normalTexture; auto geometryNormal = rt->geometryNormalTexture; + auto roughnessMetallicAo = rt->roughnessMetallicAoTexture; auto materialIdx = rt->materialIdxTexture; ivec2 res = ivec2(normal->width, normal->height); @@ -68,10 +69,12 @@ namespace Atlas { groupCount.y += ((res.y % 8 == 0) ? 0 : 1); commandList->BindImage(normal->image, 3, 0); - commandList->BindImage(geometryNormal->image, geometryNormal->sampler, 3, 1); - commandList->BindImage(materialIdx->image, materialIdx->sampler, 3, 2); + commandList->BindImage(roughnessMetallicAo->image, 3, 1); + commandList->BindImage(geometryNormal->image, geometryNormal->sampler, 3, 2); + commandList->BindImage(materialIdx->image, materialIdx->sampler, 3, 3); - commandList->ImageMemoryBarrier(normal->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT); + commandList->ImageMemoryBarrier(normal->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); + commandList->ImageMemoryBarrier(roughnessMetallicAo->image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); commandList->Dispatch(groupCount.x, groupCount.y, 1); @@ -92,6 +95,7 @@ namespace Atlas { auto reactiveMaskTexture = target->reactiveMaskTexture; auto stencilTexture = rt->stencilTexture; + auto roughnessMetallicAo = rt->roughnessMetallicAoTexture; ivec2 res = ivec2(reactiveMaskTexture.width, reactiveMaskTexture.height); @@ -101,6 +105,7 @@ namespace Atlas { commandList->BindImage(reactiveMaskTexture.image, 3, 0); commandList->BindImage(stencilTexture->image, stencilTexture->sampler, 3, 1); + commandList->BindImage(roughnessMetallicAo->image, roughnessMetallicAo->sampler, 3, 2); commandList->ImageMemoryBarrier(reactiveMaskTexture.image, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_WRITE_BIT); diff --git a/src/engine/renderer/GBufferRenderer.h b/src/engine/renderer/GBufferRenderer.h index 38ec44ab0..705d4d60b 100644 --- a/src/engine/renderer/GBufferRenderer.h +++ b/src/engine/renderer/GBufferRenderer.h @@ -17,7 +17,7 @@ namespace Atlas { void DownscaleDepthOnly(const Ref& target, Graphics::CommandList* commandList); - void FillNormalTexture(const Ref& target, Graphics::CommandList* commandList); + void Patch(const Ref& target, Graphics::CommandList* commandList); void GenerateReactiveMask(const Ref& target, Graphics::CommandList* commandList); diff --git a/src/engine/renderer/MainRenderer.cpp b/src/engine/renderer/MainRenderer.cpp index c1959b600..73d1873a9 100644 --- a/src/engine/renderer/MainRenderer.cpp +++ b/src/engine/renderer/MainRenderer.cpp @@ -302,7 +302,7 @@ namespace Atlas { } } - gBufferRenderer.FillNormalTexture(target, commandList); + gBufferRenderer.Patch(target, commandList); gBufferRenderer.Downscale(target, commandList); @@ -310,7 +310,7 @@ namespace Atlas { rtgiRenderer.Render(target, scene, commandList); - rtrRenderer.Render(target, scene, commandList); + rtrRenderer.Render(target, scene, commandList); sssRenderer.Render(target, scene, commandList); diff --git a/src/engine/renderer/RTReflectionRenderer.cpp b/src/engine/renderer/RTReflectionRenderer.cpp index 0e8c2e624..258cc98f1 100644 --- a/src/engine/renderer/RTReflectionRenderer.cpp +++ b/src/engine/renderer/RTReflectionRenderer.cpp @@ -58,12 +58,14 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Render RT Reflections"); if (target->historyReflectionTexture.image->layout == VK_IMAGE_LAYOUT_UNDEFINED || - target->historyReflectionMomentsTexture.image->layout == VK_IMAGE_LAYOUT_UNDEFINED) { + target->historyReflectionMomentsTexture.image->layout == VK_IMAGE_LAYOUT_UNDEFINED || + target->lightingTexture.image->layers == VK_IMAGE_LAYOUT_UNDEFINED) { VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT; Graphics::ImageBarrier imageBarriers[] = { {target->historyReflectionTexture.image, layout, access}, {target->historyReflectionMomentsTexture.image, layout, access}, + {target->lightingTexture.image, layout, access}, }; commandList->PipelineBarrier(imageBarriers, {}); } @@ -180,7 +182,7 @@ namespace Atlas { Graphics::Profiler::BeginQuery("Trace rays"); // Cast rays and calculate radiance - if (scene->IsRtDataValid()) { + if (scene->IsRtDataValid() && reflection->rt) { ivec2 groupCount = ivec2(rayRes.x / 8, rayRes.y / 4); groupCount.x += ((groupCount.x * 8 == rayRes.x) ? 0 : 1); groupCount.y += ((groupCount.y * 4 == rayRes.y) ? 0 : 1); @@ -192,6 +194,7 @@ namespace Atlas { auto cloudShadowEnabled = clouds && clouds->enable && clouds->castShadow; rtrPipelineConfig.ManageMacro("USE_SHADOW_MAP", reflection->useShadowMap && shadow); + rtrPipelineConfig.ManageMacro("SSR", reflection->ssr); rtrPipelineConfig.ManageMacro("DDGI", reflection->ddgi && ddgiEnabled); rtrPipelineConfig.ManageMacro("DDGI_VISIBILITY", reflection->ddgi && ddgiVisibility); rtrPipelineConfig.ManageMacro("OPACITY_CHECK", reflection->opacityCheck); From b23a32f69ed668cf5df23a5850f98462f942ea1c Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Sun, 3 Nov 2024 10:21:28 +0100 Subject: [PATCH 66/66] Fixed shader issues --- data/shader/common/utility.hsh | 2 ++ data/shader/common/ycocg.hsh | 3 ++- data/shader/deferred/indirect.csh | 3 ++- data/shader/ssgi/ssgi.csh | 6 ++++-- data/shader/ssgi/temporal.csh | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/data/shader/common/utility.hsh b/data/shader/common/utility.hsh index aea15a3d5..5594ccf52 100644 --- a/data/shader/common/utility.hsh +++ b/data/shader/common/utility.hsh @@ -26,6 +26,7 @@ vec4 saturate(vec4 value) { } +#ifdef AE_HALF_FLOAT AeF16 saturate(AeF16 value) { return clamp(value, AeF16(0.0), AeF16(1.0)); @@ -49,6 +50,7 @@ AeF16x4 saturate(AeF16x4 value) { return clamp(value, AeF16x4(0.0), AeF16x4(1.0)); } +#endif float sqr(float value) { diff --git a/data/shader/common/ycocg.hsh b/data/shader/common/ycocg.hsh index 54bd89715..6aaa91106 100644 --- a/data/shader/common/ycocg.hsh +++ b/data/shader/common/ycocg.hsh @@ -18,6 +18,7 @@ vec3 YCoCgToRGB(vec3 YCoCg) { } +#ifdef AE_HALF_FLOAT AeF16x3 RGBToYCoCg(AeF16x3 RGB) { return F16RGBToYCoCgMatrix * RGB; @@ -29,4 +30,4 @@ AeF16x3 YCoCgToRGB(AeF16x3 YCoCg) { return F16YCoCgToRGBMatrix * YCoCg; } - +#endif \ No newline at end of file diff --git a/data/shader/deferred/indirect.csh b/data/shader/deferred/indirect.csh index ad1f3d7b2..52a536d62 100644 --- a/data/shader/deferred/indirect.csh +++ b/data/shader/deferred/indirect.csh @@ -274,7 +274,8 @@ void main() { indirect = (indirectDiffuse + indirectSpecular) * surface.material.ao; #else // This is just there if the new SSGI is enabled - indirect = (indirectSpecular) * surface.material.ao; + // indirect = (indirectSpecular) * surface.material.ao; + indirect = (indirectDiffuse + indirectSpecular) * surface.material.ao; #endif #ifdef SSGI diff --git a/data/shader/ssgi/ssgi.csh b/data/shader/ssgi/ssgi.csh index 64f05e880..12fd79ef2 100644 --- a/data/shader/ssgi/ssgi.csh +++ b/data/shader/ssgi/ssgi.csh @@ -140,6 +140,7 @@ void main() { float viewOffset = max(1.0, length(viewPos)); vec3 viewRayOrigin = viewPos + viewNorm * EPSILON * viewOffset + viewDir * EPSILON * viewOffset; + /* vec2 hitPixel; vec3 hitPoint; float hit = 0.0; @@ -173,8 +174,9 @@ void main() { } //rayIrradiance = probeIrradiance; + */ + - /* float hit = 0.0; for (uint i = 0; i < uniforms.sampleCount; i++) { @@ -220,7 +222,7 @@ void main() { } } - */ + irradiance += (rayIrradiance / max(1.0, float(totalCount))); diff --git a/data/shader/ssgi/temporal.csh b/data/shader/ssgi/temporal.csh index 7179c836f..0749adaad 100644 --- a/data/shader/ssgi/temporal.csh +++ b/data/shader/ssgi/temporal.csh @@ -31,7 +31,7 @@ layout(push_constant) uniform constants { vec2 invResolution = 1.0 / vec2(imageSize(resolveImage)); vec2 resolution = vec2(imageSize(resolveImage)); -const int kernelRadius = 5; +const int kernelRadius = 3; const uint sharedDataSize = (gl_WorkGroupSize.x + 2 * kernelRadius) * (gl_WorkGroupSize.y + 2 * kernelRadius); const ivec2 unflattenedSharedDataSize = ivec2(gl_WorkGroupSize) + 2 * kernelRadius;