From 2d67be55f5fb9c5ca83f39272484996df4a71744 Mon Sep 17 00:00:00 2001 From: Simon Tippe Date: Thu, 17 Oct 2024 20:07:05 +0200 Subject: [PATCH] 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 {