1760 lines
52 KiB
C++
1760 lines
52 KiB
C++
#include "wiRenderPath3D.h"
|
|
#include "wiRenderer.h"
|
|
#include "wiImage.h"
|
|
#include "wiHelper.h"
|
|
#include "wiTextureHelper.h"
|
|
#include "wiProfiler.h"
|
|
|
|
using namespace wi::graphics;
|
|
using namespace wi::enums;
|
|
|
|
namespace wi
|
|
{
|
|
|
|
void RenderPath3D::ResizeBuffers()
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
XMUINT2 internalResolution = GetInternalResolution();
|
|
|
|
camera->CreatePerspective((float)internalResolution.x, (float)internalResolution.y, camera->zNearP, camera->zFarP);
|
|
|
|
// Render targets:
|
|
|
|
{
|
|
TextureDesc desc;
|
|
desc.format = Format::R11G11B10_FLOAT;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.sample_count = 1;
|
|
|
|
device->CreateTexture(&desc, nullptr, &rtMain);
|
|
device->SetName(&rtMain, "rtMain");
|
|
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.sample_count = getMSAASampleCount();
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE;
|
|
|
|
device->CreateTexture(&desc, nullptr, &rtMain_render);
|
|
device->SetName(&rtMain_render, "rtMain_render");
|
|
}
|
|
else
|
|
{
|
|
rtMain_render = rtMain;
|
|
}
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.format = Format::R32_UINT;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.sample_count = 1;
|
|
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
|
device->CreateTexture(&desc, nullptr, &rtPrimitiveID);
|
|
device->SetName(&rtPrimitiveID, "rtPrimitiveID");
|
|
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.sample_count = getMSAASampleCount();
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE;
|
|
device->CreateTexture(&desc, nullptr, &rtPrimitiveID_render);
|
|
device->SetName(&rtPrimitiveID_render, "rtPrimitiveID_render");
|
|
}
|
|
else
|
|
{
|
|
rtPrimitiveID_render = rtPrimitiveID;
|
|
}
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE;
|
|
desc.format = Format::R16G16_FLOAT;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.sample_count = getMSAASampleCount();
|
|
device->CreateTexture(&desc, nullptr, &rtParticleDistortion);
|
|
device->SetName(&rtParticleDistortion, "rtParticleDistortion");
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.sample_count = 1;
|
|
device->CreateTexture(&desc, nullptr, &rtParticleDistortion_Resolved);
|
|
device->SetName(&rtParticleDistortion_Resolved, "rtParticleDistortion_Resolved");
|
|
}
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.format = Format::R16G16B16A16_FLOAT;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.width = internalResolution.x / 4;
|
|
desc.height = internalResolution.y / 4;
|
|
device->CreateTexture(&desc, nullptr, &rtVolumetricLights[0]);
|
|
device->SetName(&rtVolumetricLights[0], "rtVolumetricLights[0]");
|
|
device->CreateTexture(&desc, nullptr, &rtVolumetricLights[1]);
|
|
device->SetName(&rtVolumetricLights[1], "rtVolumetricLights[1]");
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE;
|
|
desc.format = Format::R16G16_FLOAT;
|
|
desc.width = internalResolution.x / 8;
|
|
desc.height = internalResolution.y / 8;
|
|
device->CreateTexture(&desc, nullptr, &rtWaterRipple);
|
|
device->SetName(&rtWaterRipple, "rtWaterRipple");
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS | BindFlag::RENDER_TARGET;
|
|
desc.format = Format::R11G11B10_FLOAT;
|
|
desc.width = internalResolution.x / 2;
|
|
desc.height = internalResolution.y / 2;
|
|
desc.mip_levels = std::min(8u, (uint32_t)std::log2(std::max(desc.width, desc.height)));
|
|
device->CreateTexture(&desc, nullptr, &rtSceneCopy);
|
|
device->SetName(&rtSceneCopy, "rtSceneCopy");
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
device->CreateTexture(&desc, nullptr, &rtSceneCopy_tmp);
|
|
device->SetName(&rtSceneCopy_tmp, "rtSceneCopy_tmp");
|
|
|
|
for (uint32_t i = 0; i < rtSceneCopy.GetDesc().mip_levels; ++i)
|
|
{
|
|
int subresource_index;
|
|
subresource_index = device->CreateSubresource(&rtSceneCopy, SubresourceType::SRV, 0, 1, i, 1);
|
|
assert(subresource_index == i);
|
|
subresource_index = device->CreateSubresource(&rtSceneCopy_tmp, SubresourceType::SRV, 0, 1, i, 1);
|
|
assert(subresource_index == i);
|
|
subresource_index = device->CreateSubresource(&rtSceneCopy, SubresourceType::UAV, 0, 1, i, 1);
|
|
assert(subresource_index == i);
|
|
subresource_index = device->CreateSubresource(&rtSceneCopy_tmp, SubresourceType::UAV, 0, 1, i, 1);
|
|
assert(subresource_index == i);
|
|
}
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE;
|
|
desc.format = Format::R11G11B10_FLOAT;
|
|
desc.width = internalResolution.x / 4;
|
|
desc.height = internalResolution.y / 4;
|
|
device->CreateTexture(&desc, nullptr, &rtReflection);
|
|
device->SetName(&rtReflection, "rtReflection");
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE;
|
|
desc.format = Format::R11G11B10_FLOAT;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.sample_count = getMSAASampleCount();
|
|
device->CreateTexture(&desc, nullptr, &rtSun[0]);
|
|
device->SetName(&rtSun[0], "rtSun[0]");
|
|
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.sample_count = 1;
|
|
desc.width = internalResolution.x / 2;
|
|
desc.height = internalResolution.y / 2;
|
|
device->CreateTexture(&desc, nullptr, &rtSun[1]);
|
|
device->SetName(&rtSun[1], "rtSun[1]");
|
|
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.sample_count = 1;
|
|
device->CreateTexture(&desc, nullptr, &rtSun_resolved);
|
|
device->SetName(&rtSun_resolved, "rtSun_resolved");
|
|
}
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = Format::R11G11B10_FLOAT;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
device->CreateTexture(&desc, nullptr, &rtPostprocess);
|
|
device->SetName(&rtPostprocess, "rtPostprocess");
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = Format::R10G10B10A2_UNORM;
|
|
desc.width = internalResolution.x / 4;
|
|
desc.height = internalResolution.y / 4;
|
|
desc.bind_flags = BindFlag::UNORDERED_ACCESS | BindFlag::SHADER_RESOURCE;
|
|
device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[0]);
|
|
device->SetName(&rtGUIBlurredBackground[0], "rtGUIBlurredBackground[0]");
|
|
|
|
desc.width /= 4;
|
|
desc.height /= 4;
|
|
device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[1]);
|
|
device->SetName(&rtGUIBlurredBackground[1], "rtGUIBlurredBackground[1]");
|
|
device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[2]);
|
|
device->SetName(&rtGUIBlurredBackground[2], "rtGUIBlurredBackground[2]");
|
|
}
|
|
if(device->CheckCapability(GraphicsDeviceCapability::VARIABLE_RATE_SHADING_TIER2) &&
|
|
wi::renderer::GetVariableRateShadingClassification())
|
|
{
|
|
uint32_t tileSize = device->GetVariableRateShadingTileSize();
|
|
|
|
TextureDesc desc;
|
|
desc.layout = ResourceState::UNORDERED_ACCESS;
|
|
desc.bind_flags = BindFlag::UNORDERED_ACCESS | BindFlag::SHADING_RATE;
|
|
desc.format = Format::R8_UINT;
|
|
desc.width = (internalResolution.x + tileSize - 1) / tileSize;
|
|
desc.height = (internalResolution.y + tileSize - 1) / tileSize;
|
|
|
|
device->CreateTexture(&desc, nullptr, &rtShadingRate);
|
|
device->SetName(&rtShadingRate, "rtShadingRate");
|
|
}
|
|
rtVelocity = {};
|
|
rtAO = {};
|
|
rtShadow = {};
|
|
rtSSR = {};
|
|
|
|
// Depth buffers:
|
|
{
|
|
TextureDesc desc;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
|
|
desc.sample_count = getMSAASampleCount();
|
|
desc.layout = ResourceState::DEPTHSTENCIL_READONLY;
|
|
desc.format = Format::R32G8X24_TYPELESS;
|
|
desc.bind_flags = BindFlag::DEPTH_STENCIL;
|
|
device->CreateTexture(&desc, nullptr, &depthBuffer_Main);
|
|
device->SetName(&depthBuffer_Main, "depthBuffer_Main");
|
|
|
|
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
|
desc.format = Format::R32_FLOAT;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.sample_count = 1;
|
|
desc.mip_levels = 5;
|
|
device->CreateTexture(&desc, nullptr, &depthBuffer_Copy);
|
|
device->SetName(&depthBuffer_Copy, "depthBuffer_Copy");
|
|
device->CreateTexture(&desc, nullptr, &depthBuffer_Copy1);
|
|
device->SetName(&depthBuffer_Copy1, "depthBuffer_Copy1");
|
|
|
|
for (uint32_t i = 0; i < depthBuffer_Copy.desc.mip_levels; ++i)
|
|
{
|
|
int subresource = 0;
|
|
subresource = device->CreateSubresource(&depthBuffer_Copy, SubresourceType::SRV, 0, 1, i, 1);
|
|
assert(subresource == i);
|
|
subresource = device->CreateSubresource(&depthBuffer_Copy, SubresourceType::UAV, 0, 1, i, 1);
|
|
assert(subresource == i);
|
|
subresource = device->CreateSubresource(&depthBuffer_Copy1, SubresourceType::SRV, 0, 1, i, 1);
|
|
assert(subresource == i);
|
|
subresource = device->CreateSubresource(&depthBuffer_Copy1, SubresourceType::UAV, 0, 1, i, 1);
|
|
assert(subresource == i);
|
|
}
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::DEPTH_STENCIL | BindFlag::SHADER_RESOURCE;
|
|
desc.format = Format::R32_TYPELESS;
|
|
desc.width = internalResolution.x / 4;
|
|
desc.height = internalResolution.y / 4;
|
|
desc.layout = ResourceState::DEPTHSTENCIL_READONLY;
|
|
device->CreateTexture(&desc, nullptr, &depthBuffer_Reflection);
|
|
device->SetName(&depthBuffer_Reflection, "depthBuffer_Reflection");
|
|
}
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = Format::R32_FLOAT;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.mip_levels = 5;
|
|
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
|
device->CreateTexture(&desc, nullptr, &rtLinearDepth);
|
|
device->SetName(&rtLinearDepth, "rtLinearDepth");
|
|
|
|
for (uint32_t i = 0; i < desc.mip_levels; ++i)
|
|
{
|
|
int subresource_index;
|
|
subresource_index = device->CreateSubresource(&rtLinearDepth, SubresourceType::SRV, 0, 1, i, 1);
|
|
assert(subresource_index == i);
|
|
subresource_index = device->CreateSubresource(&rtLinearDepth, SubresourceType::UAV, 0, 1, i, 1);
|
|
assert(subresource_index == i);
|
|
}
|
|
}
|
|
|
|
// Render passes:
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::DepthStencil(
|
|
&depthBuffer_Main,
|
|
RenderPassAttachment::LoadOp::CLEAR,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL,
|
|
ResourceState::DEPTHSTENCIL_READONLY
|
|
)
|
|
);
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::RenderTarget(
|
|
&rtPrimitiveID_render,
|
|
RenderPassAttachment::LoadOp::CLEAR,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::SHADER_RESOURCE_COMPUTE,
|
|
ResourceState::RENDERTARGET,
|
|
ResourceState::SHADER_RESOURCE_COMPUTE
|
|
)
|
|
);
|
|
device->CreateRenderPass(&desc, &renderpass_depthprepass);
|
|
|
|
desc.attachments.clear();
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::RenderTarget(
|
|
&rtMain_render,
|
|
RenderPassAttachment::LoadOp::LOAD
|
|
)
|
|
);
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::DepthStencil(
|
|
&depthBuffer_Main,
|
|
RenderPassAttachment::LoadOp::LOAD,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL_READONLY
|
|
)
|
|
);
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.attachments.push_back(RenderPassAttachment::Resolve(&rtMain));
|
|
}
|
|
|
|
if (device->CheckCapability(GraphicsDeviceCapability::VARIABLE_RATE_SHADING_TIER2) && rtShadingRate.IsValid())
|
|
{
|
|
desc.attachments.push_back(RenderPassAttachment::ShadingRateSource(&rtShadingRate, ResourceState::UNORDERED_ACCESS, ResourceState::UNORDERED_ACCESS));
|
|
}
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_main);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtMain_render, RenderPassAttachment::LoadOp::LOAD));
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::DepthStencil(
|
|
&depthBuffer_Main,
|
|
RenderPassAttachment::LoadOp::LOAD,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL,
|
|
ResourceState::DEPTHSTENCIL_READONLY
|
|
)
|
|
);
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.attachments.push_back(RenderPassAttachment::Resolve(&rtMain));
|
|
}
|
|
device->CreateRenderPass(&desc, &renderpass_transparent);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::DepthStencil(
|
|
&depthBuffer_Reflection,
|
|
RenderPassAttachment::LoadOp::CLEAR,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL,
|
|
ResourceState::SHADER_RESOURCE
|
|
)
|
|
);
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_reflection_depthprepass);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::RenderTarget(
|
|
&rtReflection,
|
|
RenderPassAttachment::LoadOp::DONTCARE,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::SHADER_RESOURCE,
|
|
ResourceState::RENDERTARGET,
|
|
ResourceState::SHADER_RESOURCE
|
|
)
|
|
);
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::DepthStencil(
|
|
&depthBuffer_Reflection,
|
|
RenderPassAttachment::LoadOp::LOAD,
|
|
RenderPassAttachment::StoreOp::DONTCARE,
|
|
ResourceState::SHADER_RESOURCE,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL_READONLY
|
|
)
|
|
);
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_reflection);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtSceneCopy, RenderPassAttachment::LoadOp::DONTCARE));
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_downsamplescene);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::DepthStencil(
|
|
&depthBuffer_Main,
|
|
RenderPassAttachment::LoadOp::LOAD,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL_READONLY
|
|
)
|
|
);
|
|
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtSun[0], RenderPassAttachment::LoadOp::CLEAR));
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.attachments.back().storeop = RenderPassAttachment::StoreOp::DONTCARE;
|
|
desc.attachments.push_back(RenderPassAttachment::Resolve(&rtSun_resolved));
|
|
}
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_lightshafts);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtVolumetricLights[0], RenderPassAttachment::LoadOp::CLEAR));
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_volumetriclight);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtParticleDistortion, RenderPassAttachment::LoadOp::CLEAR));
|
|
desc.attachments.push_back(
|
|
RenderPassAttachment::DepthStencil(
|
|
&depthBuffer_Main,
|
|
RenderPassAttachment::LoadOp::LOAD,
|
|
RenderPassAttachment::StoreOp::STORE,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL_READONLY,
|
|
ResourceState::DEPTHSTENCIL_READONLY
|
|
)
|
|
);
|
|
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
desc.attachments.push_back(RenderPassAttachment::Resolve(&rtParticleDistortion_Resolved));
|
|
}
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_particledistortion);
|
|
}
|
|
{
|
|
RenderPassDesc desc;
|
|
desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtWaterRipple, RenderPassAttachment::LoadOp::CLEAR));
|
|
|
|
device->CreateRenderPass(&desc, &renderpass_waterripples);
|
|
}
|
|
|
|
|
|
// Other resources:
|
|
{
|
|
TextureDesc desc;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.mip_levels = 1;
|
|
desc.array_size = 1;
|
|
desc.format = Format::R8G8B8A8_UNORM;
|
|
desc.sample_count = 1;
|
|
desc.usage = Usage::DEFAULT;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
|
|
device->CreateTexture(&desc, nullptr, &debugUAV);
|
|
device->SetName(&debugUAV, "debugUAV");
|
|
}
|
|
wi::renderer::CreateVisibilityResources(visibilityResources, internalResolution);
|
|
wi::renderer::CreateTiledLightResources(tiledLightResources, internalResolution);
|
|
wi::renderer::CreateTiledLightResources(tiledLightResources_planarReflection, XMUINT2(depthBuffer_Reflection.desc.width, depthBuffer_Reflection.desc.height));
|
|
wi::renderer::CreateLuminanceResources(luminanceResources, internalResolution);
|
|
wi::renderer::CreateScreenSpaceShadowResources(screenspaceshadowResources, internalResolution);
|
|
wi::renderer::CreateDepthOfFieldResources(depthoffieldResources, internalResolution);
|
|
wi::renderer::CreateMotionBlurResources(motionblurResources, internalResolution);
|
|
wi::renderer::CreateVolumetricCloudResources(volumetriccloudResources, internalResolution);
|
|
wi::renderer::CreateVolumetricCloudResources(volumetriccloudResources_reflection, XMUINT2(depthBuffer_Reflection.desc.width, depthBuffer_Reflection.desc.height));
|
|
wi::renderer::CreateBloomResources(bloomResources, internalResolution);
|
|
wi::renderer::CreateSurfelGIResources(surfelGIResources, internalResolution);
|
|
temporalAAResources = {};
|
|
|
|
if (device->CheckCapability(GraphicsDeviceCapability::RAYTRACING))
|
|
{
|
|
wi::renderer::CreateRTShadowResources(rtshadowResources, internalResolution);
|
|
}
|
|
|
|
setAO(ao);
|
|
setSSREnabled(ssrEnabled);
|
|
setRaytracedReflectionsEnabled(raytracedReflectionsEnabled);
|
|
setFSREnabled(fsrEnabled);
|
|
|
|
RenderPath2D::ResizeBuffers();
|
|
}
|
|
|
|
void RenderPath3D::PreUpdate()
|
|
{
|
|
camera_previous = *camera;
|
|
camera_reflection_previous = camera_reflection;
|
|
}
|
|
|
|
void RenderPath3D::Update(float dt)
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
if (rtMain_render.desc.sample_count != msaaSampleCount)
|
|
{
|
|
ResizeBuffers();
|
|
}
|
|
|
|
RenderPath2D::Update(dt);
|
|
|
|
if (getSceneUpdateEnabled())
|
|
{
|
|
if (wi::renderer::GetSurfelGIEnabled() ||
|
|
wi::renderer::GetDDGIEnabled() ||
|
|
wi::renderer::GetRaytracedShadowsEnabled() ||
|
|
getAO() == AO_RTAO ||
|
|
getRaytracedReflectionEnabled())
|
|
{
|
|
scene->SetAccelerationStructureUpdateRequested(true);
|
|
}
|
|
|
|
scene->camera = *camera;
|
|
scene->Update(dt * wi::renderer::GetGameSpeed());
|
|
}
|
|
|
|
// Frustum culling for main camera:
|
|
visibility_main.layerMask = getLayerMask();
|
|
visibility_main.scene = scene;
|
|
visibility_main.camera = camera;
|
|
visibility_main.flags = wi::renderer::Visibility::ALLOW_EVERYTHING;
|
|
wi::renderer::UpdateVisibility(visibility_main);
|
|
|
|
if (visibility_main.planar_reflection_visible)
|
|
{
|
|
// Frustum culling for planar reflections:
|
|
camera_reflection = *camera;
|
|
camera_reflection.jitter = XMFLOAT2(0, 0);
|
|
camera_reflection.Reflect(visibility_main.reflectionPlane);
|
|
visibility_reflection.layerMask = getLayerMask();
|
|
visibility_reflection.scene = scene;
|
|
visibility_reflection.camera = &camera_reflection;
|
|
visibility_reflection.flags = wi::renderer::Visibility::ALLOW_OBJECTS;
|
|
wi::renderer::UpdateVisibility(visibility_reflection);
|
|
}
|
|
|
|
XMUINT2 internalResolution = GetInternalResolution();
|
|
|
|
wi::renderer::UpdatePerFrameData(
|
|
*scene,
|
|
visibility_main,
|
|
frameCB,
|
|
getSceneUpdateEnabled() ? dt : 0
|
|
);
|
|
|
|
if (wi::renderer::GetTemporalAAEnabled())
|
|
{
|
|
const XMFLOAT4& halton = wi::math::GetHaltonSequence(wi::graphics::GetDevice()->GetFrameCount() % 256);
|
|
camera->jitter.x = (halton.x * 2 - 1) / (float)internalResolution.x;
|
|
camera->jitter.y = (halton.y * 2 - 1) / (float)internalResolution.y;
|
|
if (!temporalAAResources.IsValid())
|
|
{
|
|
wi::renderer::CreateTemporalAAResources(temporalAAResources, internalResolution);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
camera->jitter = XMFLOAT2(0, 0);
|
|
temporalAAResources = {};
|
|
}
|
|
camera->UpdateCamera();
|
|
|
|
if (getAO() != AO_RTAO)
|
|
{
|
|
rtaoResources.frame = 0;
|
|
}
|
|
if (!wi::renderer::GetRaytracedShadowsEnabled())
|
|
{
|
|
rtshadowResources.frame = 0;
|
|
}
|
|
if (!getSSREnabled() && !getRaytracedReflectionEnabled())
|
|
{
|
|
rtSSR = {};
|
|
}
|
|
if (getAO() == AO_DISABLED)
|
|
{
|
|
rtAO = {};
|
|
}
|
|
|
|
// Check whether velocity buffer is required:
|
|
if (
|
|
getMotionBlurEnabled() ||
|
|
wi::renderer::GetTemporalAAEnabled() ||
|
|
getSSREnabled() ||
|
|
getRaytracedReflectionEnabled() ||
|
|
wi::renderer::GetRaytracedShadowsEnabled() ||
|
|
getAO() == AO::AO_RTAO
|
|
)
|
|
{
|
|
if (!rtVelocity.IsValid())
|
|
{
|
|
TextureDesc desc;
|
|
desc.format = Format::R16G16_FLOAT;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
|
device->CreateTexture(&desc, nullptr, &rtVelocity);
|
|
device->SetName(&rtVelocity, "rtVelocity");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rtVelocity = {};
|
|
}
|
|
|
|
// Check whether shadow mask is required:
|
|
if(wi::renderer::GetScreenSpaceShadowsEnabled() || wi::renderer::GetRaytracedShadowsEnabled())
|
|
{
|
|
if (!rtShadow.IsValid())
|
|
{
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = Format::R32G32B32A32_UINT;
|
|
desc.width = internalResolution.x / 2;
|
|
desc.height = internalResolution.y / 2;
|
|
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
|
device->CreateTexture(&desc, nullptr, &rtShadow);
|
|
device->SetName(&rtShadow, "rtShadow");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rtShadow = {};
|
|
}
|
|
|
|
// Keep a copy of last frame's depth buffer for temporal disocclusion checks, so swap with current one every frame:
|
|
std::swap(depthBuffer_Copy, depthBuffer_Copy1);
|
|
|
|
visibilityResources.depthbuffer = &depthBuffer_Copy;
|
|
visibilityResources.lineardepth = &rtLinearDepth;
|
|
if (getMSAASampleCount() > 1)
|
|
{
|
|
visibilityResources.primitiveID_resolved = &rtPrimitiveID;
|
|
}
|
|
else
|
|
{
|
|
visibilityResources.primitiveID_resolved = nullptr;
|
|
}
|
|
|
|
camera->canvas.init(*this);
|
|
camera->width = (float)internalResolution.x;
|
|
camera->height = (float)internalResolution.y;
|
|
camera->sample_count = depthBuffer_Main.desc.sample_count;
|
|
camera->texture_primitiveID_index = device->GetDescriptorIndex(&rtPrimitiveID, SubresourceType::SRV);
|
|
camera->texture_depth_index = device->GetDescriptorIndex(&depthBuffer_Copy, SubresourceType::SRV);
|
|
camera->texture_lineardepth_index = device->GetDescriptorIndex(&rtLinearDepth, SubresourceType::SRV);
|
|
camera->texture_velocity_index = device->GetDescriptorIndex(&rtVelocity, SubresourceType::SRV);
|
|
camera->texture_normal_index = device->GetDescriptorIndex(&visibilityResources.texture_normals, SubresourceType::SRV);
|
|
camera->texture_roughness_index = device->GetDescriptorIndex(&visibilityResources.texture_roughness, SubresourceType::SRV);
|
|
camera->buffer_entitytiles_opaque_index = device->GetDescriptorIndex(&tiledLightResources.entityTiles_Opaque, SubresourceType::SRV);
|
|
camera->buffer_entitytiles_transparent_index = device->GetDescriptorIndex(&tiledLightResources.entityTiles_Transparent, SubresourceType::SRV);
|
|
camera->texture_reflection_index = device->GetDescriptorIndex(&rtReflection, SubresourceType::SRV);
|
|
camera->texture_refraction_index = device->GetDescriptorIndex(&rtSceneCopy, SubresourceType::SRV);
|
|
camera->texture_waterriples_index = device->GetDescriptorIndex(&rtWaterRipple, SubresourceType::SRV);
|
|
camera->texture_ao_index = device->GetDescriptorIndex(&rtAO, SubresourceType::SRV);
|
|
camera->texture_ssr_index = device->GetDescriptorIndex(&rtSSR, SubresourceType::SRV);
|
|
camera->texture_rtshadow_index = device->GetDescriptorIndex(&rtShadow, SubresourceType::SRV);
|
|
camera->texture_surfelgi_index = device->GetDescriptorIndex(&surfelGIResources.result, SubresourceType::SRV);
|
|
|
|
camera_reflection.canvas.init(*this);
|
|
camera_reflection.width = (float)depthBuffer_Reflection.desc.width;
|
|
camera_reflection.height = (float)depthBuffer_Reflection.desc.height;
|
|
camera_reflection.sample_count = depthBuffer_Reflection.desc.sample_count;
|
|
camera_reflection.texture_primitiveID_index = -1;
|
|
camera_reflection.texture_depth_index = device->GetDescriptorIndex(&depthBuffer_Reflection, SubresourceType::SRV);
|
|
camera_reflection.texture_lineardepth_index = -1;
|
|
camera_reflection.texture_velocity_index = -1;
|
|
camera_reflection.texture_normal_index = -1;
|
|
camera_reflection.texture_roughness_index = -1;
|
|
camera_reflection.buffer_entitytiles_opaque_index = device->GetDescriptorIndex(&tiledLightResources_planarReflection.entityTiles_Opaque, SubresourceType::SRV);
|
|
camera_reflection.buffer_entitytiles_transparent_index = device->GetDescriptorIndex(&tiledLightResources_planarReflection.entityTiles_Transparent, SubresourceType::SRV);
|
|
camera_reflection.texture_reflection_index = -1;
|
|
camera_reflection.texture_refraction_index = -1;
|
|
camera_reflection.texture_waterriples_index = -1;
|
|
camera_reflection.texture_ao_index = -1;
|
|
camera_reflection.texture_ssr_index = -1;
|
|
camera_reflection.texture_rtshadow_index = -1;
|
|
camera_reflection.texture_surfelgi_index = -1;
|
|
}
|
|
|
|
void RenderPath3D::Render() const
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
wi::jobsystem::context ctx;
|
|
|
|
// Preparing the frame:
|
|
CommandList cmd = device->BeginCommandList();
|
|
CommandList cmd_prepareframe = cmd;
|
|
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
|
wi::renderer::BindCameraCB(
|
|
*camera,
|
|
camera_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
wi::renderer::UpdateRenderData(visibility_main, frameCB, cmd);
|
|
});
|
|
|
|
// async compute parallel with depth prepass
|
|
cmd = device->BeginCommandList(QUEUE_COMPUTE);
|
|
CommandList cmd_prepareframe_async = cmd;
|
|
device->WaitCommandList(cmd, cmd_prepareframe);
|
|
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::renderer::BindCameraCB(
|
|
*camera,
|
|
camera_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
wi::renderer::UpdateRenderDataAsync(visibility_main, frameCB, cmd);
|
|
|
|
if (scene->IsAccelerationStructureUpdateRequested())
|
|
{
|
|
wi::renderer::UpdateRaytracingAccelerationStructures(*scene, cmd);
|
|
}
|
|
|
|
if (wi::renderer::GetSurfelGIEnabled())
|
|
{
|
|
wi::renderer::SurfelGI(
|
|
surfelGIResources,
|
|
*scene,
|
|
cmd,
|
|
instanceInclusionMask_SurfelGI
|
|
);
|
|
}
|
|
|
|
if (wi::renderer::GetDDGIEnabled())
|
|
{
|
|
wi::renderer::DDGI(
|
|
*scene,
|
|
cmd,
|
|
instanceInclusionMask_DDGI
|
|
);
|
|
}
|
|
|
|
});
|
|
|
|
static const uint32_t drawscene_flags =
|
|
wi::renderer::DRAWSCENE_OPAQUE |
|
|
wi::renderer::DRAWSCENE_IMPOSTOR |
|
|
wi::renderer::DRAWSCENE_HAIRPARTICLE |
|
|
wi::renderer::DRAWSCENE_TESSELLATION |
|
|
wi::renderer::DRAWSCENE_OCCLUSIONCULLING
|
|
;
|
|
static const uint32_t drawscene_flags_reflections =
|
|
wi::renderer::DRAWSCENE_OPAQUE |
|
|
wi::renderer::DRAWSCENE_IMPOSTOR
|
|
;
|
|
|
|
// Main camera depth prepass + occlusion culling:
|
|
cmd = device->BeginCommandList();
|
|
CommandList cmd_maincamera_prepass = cmd;
|
|
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::renderer::BindCameraCB(
|
|
*camera,
|
|
camera_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
|
|
wi::renderer::OcclusionCulling_Reset(visibility_main, cmd); // must be outside renderpass!
|
|
|
|
device->RenderPassBegin(&renderpass_depthprepass, cmd);
|
|
|
|
device->EventBegin("Opaque Z-prepass", cmd);
|
|
auto range = wi::profiler::BeginRangeGPU("Z-Prepass", cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)depthBuffer_Main.GetDesc().width;
|
|
vp.height = (float)depthBuffer_Main.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
wi::renderer::DrawScene(visibility_main, RENDERPASS_PREPASS, cmd, drawscene_flags);
|
|
|
|
wi::profiler::EndRange(range);
|
|
device->EventEnd(cmd);
|
|
|
|
if (getOcclusionCullingEnabled())
|
|
{
|
|
wi::renderer::OcclusionCulling_Render(*camera, visibility_main, cmd);
|
|
}
|
|
|
|
device->RenderPassEnd(cmd);
|
|
|
|
wi::renderer::OcclusionCulling_Resolve(visibility_main, cmd); // must be outside renderpass!
|
|
|
|
});
|
|
|
|
// Main camera compute effects:
|
|
// (async compute, parallel to "shadow maps" and "update textures",
|
|
// must finish before "main scene opaque color pass")
|
|
cmd = device->BeginCommandList(QUEUE_COMPUTE);
|
|
device->WaitCommandList(cmd, cmd_maincamera_prepass);
|
|
CommandList cmd_maincamera_compute_effects = cmd;
|
|
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::renderer::BindCameraCB(
|
|
*camera,
|
|
camera_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
|
|
wi::renderer::Visibility_Prepare(
|
|
visibilityResources,
|
|
rtPrimitiveID_render,
|
|
cmd
|
|
);
|
|
|
|
wi::renderer::ComputeTiledLightCulling(
|
|
tiledLightResources,
|
|
debugUAV,
|
|
cmd
|
|
);
|
|
|
|
if (visibility_shading_in_compute)
|
|
{
|
|
wi::renderer::Visibility_Surface(
|
|
visibilityResources,
|
|
rtMain,
|
|
cmd
|
|
);
|
|
}
|
|
else if(
|
|
getSSREnabled() ||
|
|
getRaytracedReflectionEnabled() ||
|
|
wi::renderer::GetScreenSpaceShadowsEnabled() ||
|
|
wi::renderer::GetRaytracedShadowsEnabled()
|
|
)
|
|
{
|
|
// These post effects require surface normals and/or roughness
|
|
wi::renderer::Visibility_Surface_Reduced(
|
|
visibilityResources,
|
|
cmd
|
|
);
|
|
}
|
|
|
|
if (rtVelocity.IsValid())
|
|
{
|
|
wi::renderer::Visibility_Velocity(
|
|
visibilityResources,
|
|
rtVelocity,
|
|
cmd
|
|
);
|
|
}
|
|
|
|
if (wi::renderer::GetSurfelGIEnabled())
|
|
{
|
|
wi::renderer::SurfelGI_Coverage(
|
|
surfelGIResources,
|
|
*scene,
|
|
debugUAV,
|
|
cmd
|
|
);
|
|
}
|
|
|
|
RenderAO(cmd);
|
|
|
|
if (wi::renderer::GetVariableRateShadingClassification() && device->CheckCapability(GraphicsDeviceCapability::VARIABLE_RATE_SHADING_TIER2))
|
|
{
|
|
wi::renderer::ComputeShadingRateClassification(
|
|
rtShadingRate,
|
|
debugUAV,
|
|
cmd
|
|
);
|
|
}
|
|
|
|
if (scene->weather.IsVolumetricClouds())
|
|
{
|
|
wi::renderer::Postprocess_VolumetricClouds(
|
|
volumetriccloudResources,
|
|
cmd
|
|
);
|
|
}
|
|
|
|
RenderSSR(cmd);
|
|
|
|
if (wi::renderer::GetScreenSpaceShadowsEnabled())
|
|
{
|
|
wi::renderer::Postprocess_ScreenSpaceShadow(
|
|
screenspaceshadowResources,
|
|
tiledLightResources.entityTiles_Opaque,
|
|
rtShadow,
|
|
cmd,
|
|
getScreenSpaceShadowRange(),
|
|
getScreenSpaceShadowSampleCount()
|
|
);
|
|
}
|
|
|
|
if (wi::renderer::GetRaytracedShadowsEnabled())
|
|
{
|
|
wi::renderer::Postprocess_RTShadow(
|
|
rtshadowResources,
|
|
*scene,
|
|
tiledLightResources.entityTiles_Opaque,
|
|
rtShadow,
|
|
cmd,
|
|
instanceInclusionMask_RTShadow
|
|
);
|
|
}
|
|
|
|
});
|
|
|
|
// Shadow maps:
|
|
if (getShadowsEnabled())
|
|
{
|
|
cmd = device->BeginCommandList();
|
|
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
|
wi::renderer::DrawShadowmaps(visibility_main, cmd);
|
|
});
|
|
}
|
|
|
|
// Updating textures:
|
|
cmd = device->BeginCommandList();
|
|
device->WaitCommandList(cmd, cmd_prepareframe_async);
|
|
wi::jobsystem::Execute(ctx, [cmd, this](wi::jobsystem::JobArgs args) {
|
|
wi::renderer::BindCommonResources(cmd);
|
|
wi::renderer::BindCameraCB(
|
|
*camera,
|
|
camera_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
wi::renderer::RefreshLightmaps(*scene, cmd, instanceInclusionMask_Lightmap);
|
|
wi::renderer::RefreshEnvProbes(visibility_main, cmd);
|
|
wi::renderer::RefreshImpostors(*scene, cmd);
|
|
});
|
|
|
|
// Voxel GI:
|
|
if (wi::renderer::GetVoxelRadianceEnabled())
|
|
{
|
|
cmd = device->BeginCommandList();
|
|
wi::jobsystem::Execute(ctx, [cmd, this](wi::jobsystem::JobArgs args) {
|
|
wi::renderer::VoxelRadiance(visibility_main, cmd);
|
|
});
|
|
}
|
|
|
|
if (visibility_main.IsRequestedPlanarReflections())
|
|
{
|
|
// Planar reflections depth prepass:
|
|
cmd = device->BeginCommandList();
|
|
wi::jobsystem::Execute(ctx, [cmd, this](wi::jobsystem::JobArgs args) {
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::renderer::BindCameraCB(
|
|
camera_reflection,
|
|
camera_reflection_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
|
|
device->EventBegin("Planar reflections Z-Prepass", cmd);
|
|
auto range = wi::profiler::BeginRangeGPU("Planar Reflections Z-Prepass", cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)depthBuffer_Reflection.GetDesc().width;
|
|
vp.height = (float)depthBuffer_Reflection.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
device->RenderPassBegin(&renderpass_reflection_depthprepass, cmd);
|
|
|
|
wi::renderer::DrawScene(visibility_reflection, RENDERPASS_PREPASS, cmd, drawscene_flags_reflections);
|
|
|
|
device->RenderPassEnd(cmd);
|
|
|
|
if (scene->weather.IsVolumetricClouds())
|
|
{
|
|
wi::renderer::Postprocess_VolumetricClouds(
|
|
volumetriccloudResources_reflection,
|
|
cmd
|
|
);
|
|
}
|
|
|
|
wi::profiler::EndRange(range); // Planar Reflections
|
|
device->EventEnd(cmd);
|
|
|
|
});
|
|
|
|
// Planar reflections opaque color pass:
|
|
cmd = device->BeginCommandList();
|
|
wi::jobsystem::Execute(ctx, [cmd, this](wi::jobsystem::JobArgs args) {
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::renderer::BindCameraCB(
|
|
camera_reflection,
|
|
camera_reflection_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
|
|
wi::renderer::ComputeTiledLightCulling(
|
|
tiledLightResources_planarReflection,
|
|
Texture(),
|
|
cmd
|
|
);
|
|
|
|
device->EventBegin("Planar reflections", cmd);
|
|
auto range = wi::profiler::BeginRangeGPU("Planar Reflections", cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)depthBuffer_Reflection.GetDesc().width;
|
|
vp.height = (float)depthBuffer_Reflection.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
|
|
device->RenderPassBegin(&renderpass_reflection, cmd);
|
|
|
|
wi::renderer::DrawScene(visibility_reflection, RENDERPASS_MAIN, cmd, drawscene_flags_reflections);
|
|
wi::renderer::DrawSky(*scene, cmd);
|
|
|
|
// Blend the volumetric clouds on top:
|
|
if (scene->weather.IsVolumetricClouds())
|
|
{
|
|
device->EventBegin("Volumetric Clouds Reflection Blend", cmd);
|
|
wi::image::Params fx;
|
|
fx.enableFullScreen();
|
|
fx.blendFlag = BLENDMODE_PREMULTIPLIED;
|
|
wi::image::Draw(&volumetriccloudResources_reflection.texture_temporal[device->GetFrameCount() % 2], fx, cmd);
|
|
device->EventEnd(cmd);
|
|
}
|
|
|
|
device->RenderPassEnd(cmd);
|
|
|
|
wi::profiler::EndRange(range); // Planar Reflections
|
|
device->EventEnd(cmd);
|
|
});
|
|
}
|
|
|
|
// Main camera opaque color pass:
|
|
cmd = device->BeginCommandList();
|
|
device->WaitCommandList(cmd, cmd_maincamera_compute_effects);
|
|
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
device->EventBegin("Opaque Scene", cmd);
|
|
|
|
wi::renderer::BindCameraCB(
|
|
*camera,
|
|
camera_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
|
|
// This can't run in "main camera compute effects" async compute,
|
|
// because it depends on shadow maps, and envmaps
|
|
if (getRaytracedReflectionEnabled())
|
|
{
|
|
wi::renderer::Postprocess_RTReflection(
|
|
rtreflectionResources,
|
|
*scene,
|
|
rtSSR,
|
|
cmd,
|
|
instanceInclusionMask_RTReflection
|
|
);
|
|
}
|
|
|
|
// Depth buffers were created on COMPUTE queue, so make them available for pixel shaders here:
|
|
{
|
|
GPUBarrier barriers[] = {
|
|
GPUBarrier::Image(&rtLinearDepth, rtLinearDepth.desc.layout, ResourceState::SHADER_RESOURCE),
|
|
GPUBarrier::Image(&depthBuffer_Copy, depthBuffer_Copy.desc.layout, ResourceState::SHADER_RESOURCE),
|
|
};
|
|
device->Barrier(barriers, arraysize(barriers), cmd);
|
|
}
|
|
|
|
if (wi::renderer::GetRaytracedShadowsEnabled() || wi::renderer::GetScreenSpaceShadowsEnabled())
|
|
{
|
|
GPUBarrier barrier = GPUBarrier::Image(&rtShadow, rtShadow.desc.layout, ResourceState::SHADER_RESOURCE);
|
|
device->Barrier(&barrier, 1, cmd);
|
|
}
|
|
|
|
if (visibility_shading_in_compute)
|
|
{
|
|
wi::renderer::Visibility_Shade(
|
|
visibilityResources,
|
|
rtMain,
|
|
cmd
|
|
);
|
|
}
|
|
|
|
Viewport vp;
|
|
vp.width = (float)depthBuffer_Main.GetDesc().width;
|
|
vp.height = (float)depthBuffer_Main.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
device->RenderPassBegin(&renderpass_main, cmd);
|
|
|
|
if (visibility_shading_in_compute)
|
|
{
|
|
// In visibility compute shading, the impostors must still be drawn using rasterization:
|
|
wi::renderer::DrawScene(visibility_main, RENDERPASS_MAIN, cmd, wi::renderer::DRAWSCENE_IMPOSTOR);
|
|
}
|
|
else
|
|
{
|
|
auto range = wi::profiler::BeginRangeGPU("Opaque Scene", cmd);
|
|
wi::renderer::DrawScene(visibility_main, RENDERPASS_MAIN, cmd, drawscene_flags);
|
|
wi::renderer::DrawSky(*scene, cmd);
|
|
wi::profiler::EndRange(range); // Opaque Scene
|
|
}
|
|
|
|
RenderOutline(cmd);
|
|
|
|
// Upsample + Blend the volumetric clouds on top:
|
|
if (scene->weather.IsVolumetricClouds())
|
|
{
|
|
device->EventBegin("Volumetric Clouds Upsample + Blend", cmd);
|
|
wi::renderer::Postprocess_Upsample_Bilateral(
|
|
volumetriccloudResources.texture_temporal[device->GetFrameCount() % 2],
|
|
rtLinearDepth,
|
|
rtMain_render, // only desc is taken if pixel shader upsampling is used
|
|
cmd,
|
|
true // pixel shader upsampling
|
|
);
|
|
device->EventEnd(cmd);
|
|
}
|
|
|
|
device->RenderPassEnd(cmd);
|
|
|
|
if (wi::renderer::GetRaytracedShadowsEnabled() || wi::renderer::GetScreenSpaceShadowsEnabled())
|
|
{
|
|
GPUBarrier barrier = GPUBarrier::Image(&rtShadow, ResourceState::SHADER_RESOURCE, rtShadow.desc.layout);
|
|
device->Barrier(&barrier, 1, cmd);
|
|
}
|
|
|
|
device->EventEnd(cmd);
|
|
});
|
|
|
|
// Transparents, post processes, etc:
|
|
cmd = device->BeginCommandList();
|
|
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::renderer::BindCameraCB(
|
|
*camera,
|
|
camera_previous,
|
|
camera_reflection,
|
|
cmd
|
|
);
|
|
wi::renderer::BindCommonResources(cmd);
|
|
|
|
RenderLightShafts(cmd);
|
|
|
|
RenderVolumetrics(cmd);
|
|
|
|
RenderSceneMIPChain(cmd);
|
|
|
|
RenderTransparents(cmd);
|
|
|
|
RenderPostprocessChain(cmd);
|
|
|
|
// Depth buffers expect a non-pixel shader resource state as they are generated on compute queue:
|
|
{
|
|
GPUBarrier barriers[] = {
|
|
GPUBarrier::Image(&rtLinearDepth, ResourceState::SHADER_RESOURCE, rtLinearDepth.desc.layout),
|
|
GPUBarrier::Image(&depthBuffer_Copy, ResourceState::SHADER_RESOURCE, depthBuffer_Copy.desc.layout),
|
|
};
|
|
device->Barrier(barriers, arraysize(barriers), cmd);
|
|
}
|
|
|
|
});
|
|
|
|
RenderPath2D::Render();
|
|
|
|
wi::jobsystem::Wait(ctx);
|
|
}
|
|
|
|
void RenderPath3D::Compose(CommandList cmd) const
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::image::Params fx;
|
|
fx.blendFlag = BLENDMODE_OPAQUE;
|
|
fx.quality = wi::image::QUALITY_LINEAR;
|
|
fx.enableFullScreen();
|
|
|
|
device->EventBegin("Composition", cmd);
|
|
wi::image::Draw(GetLastPostprocessRT(), fx, cmd);
|
|
device->EventEnd(cmd);
|
|
|
|
if (
|
|
wi::renderer::GetDebugLightCulling() ||
|
|
wi::renderer::GetVariableRateShadingClassificationDebug() ||
|
|
wi::renderer::GetSurfelGIDebugEnabled()
|
|
)
|
|
{
|
|
fx.enableFullScreen();
|
|
fx.blendFlag = BLENDMODE_PREMULTIPLIED;
|
|
wi::image::Draw(&debugUAV, fx, cmd);
|
|
}
|
|
|
|
RenderPath2D::Compose(cmd);
|
|
}
|
|
|
|
void RenderPath3D::RenderAO(CommandList cmd) const
|
|
{
|
|
|
|
if (getAOEnabled())
|
|
{
|
|
switch (getAO())
|
|
{
|
|
case AO_SSAO:
|
|
wi::renderer::Postprocess_SSAO(
|
|
ssaoResources,
|
|
rtLinearDepth,
|
|
rtAO,
|
|
cmd,
|
|
getAORange(),
|
|
getAOSampleCount(),
|
|
getAOPower()
|
|
);
|
|
break;
|
|
case AO_HBAO:
|
|
wi::renderer::Postprocess_HBAO(
|
|
ssaoResources,
|
|
*camera,
|
|
rtLinearDepth,
|
|
rtAO,
|
|
cmd,
|
|
getAOPower()
|
|
);
|
|
break;
|
|
case AO_MSAO:
|
|
wi::renderer::Postprocess_MSAO(
|
|
msaoResources,
|
|
*camera,
|
|
rtLinearDepth,
|
|
rtAO,
|
|
cmd,
|
|
getAOPower()
|
|
);
|
|
break;
|
|
case AO_RTAO:
|
|
wi::renderer::Postprocess_RTAO(
|
|
rtaoResources,
|
|
*scene,
|
|
rtAO,
|
|
cmd,
|
|
getAORange(),
|
|
getAOPower(),
|
|
instanceInclusionMask_RTAO
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
void RenderPath3D::RenderSSR(CommandList cmd) const
|
|
{
|
|
if (getSSREnabled() && !getRaytracedReflectionEnabled())
|
|
{
|
|
wi::renderer::Postprocess_SSR(
|
|
ssrResources,
|
|
rtSceneCopy,
|
|
rtSSR,
|
|
cmd
|
|
);
|
|
}
|
|
}
|
|
void RenderPath3D::RenderOutline(CommandList cmd) const
|
|
{
|
|
if (getOutlineEnabled())
|
|
{
|
|
wi::renderer::Postprocess_Outline(rtLinearDepth, cmd, getOutlineThreshold(), getOutlineThickness(), getOutlineColor());
|
|
}
|
|
}
|
|
void RenderPath3D::RenderLightShafts(CommandList cmd) const
|
|
{
|
|
XMVECTOR sunDirection = XMLoadFloat3(&scene->weather.sunDirection);
|
|
if (getLightShaftsEnabled() && XMVectorGetX(XMVector3Dot(sunDirection, camera->GetAt())) > 0)
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
device->EventBegin("Light Shafts", cmd);
|
|
|
|
// Render sun stencil cutout:
|
|
{
|
|
device->RenderPassBegin(&renderpass_lightshafts, cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)depthBuffer_Main.GetDesc().width;
|
|
vp.height = (float)depthBuffer_Main.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
wi::renderer::DrawSun(cmd);
|
|
|
|
if (scene->weather.IsVolumetricClouds())
|
|
{
|
|
device->EventBegin("Volumetric cloud occlusion mask", cmd);
|
|
wi::image::Params fx;
|
|
fx.enableFullScreen();
|
|
fx.blendFlag = BLENDMODE_MULTIPLY;
|
|
wi::image::Draw(&volumetriccloudResources.texture_cloudMask, fx, cmd);
|
|
device->EventEnd(cmd);
|
|
}
|
|
|
|
device->RenderPassEnd(cmd);
|
|
}
|
|
|
|
// Radial blur on the sun:
|
|
{
|
|
XMVECTOR sunPos = XMVector3Project(camera->GetEye() + sunDirection * camera->zFarP, 0, 0,
|
|
1.0f, 1.0f, 0.1f, 1.0f,
|
|
camera->GetProjection(), camera->GetView(), XMMatrixIdentity());
|
|
{
|
|
XMFLOAT2 sun;
|
|
XMStoreFloat2(&sun, sunPos);
|
|
wi::renderer::Postprocess_LightShafts(*renderpass_lightshafts.desc.attachments.back().texture, rtSun[1], cmd, sun);
|
|
}
|
|
}
|
|
device->EventEnd(cmd);
|
|
}
|
|
}
|
|
void RenderPath3D::RenderVolumetrics(CommandList cmd) const
|
|
{
|
|
if (getVolumeLightsEnabled() && visibility_main.IsRequestedVolumetricLights())
|
|
{
|
|
auto range = wi::profiler::BeginRangeGPU("Volumetric Lights", cmd);
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
device->RenderPassBegin(&renderpass_volumetriclight, cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)rtVolumetricLights[0].GetDesc().width;
|
|
vp.height = (float)rtVolumetricLights[0].GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
wi::renderer::DrawVolumeLights(visibility_main, cmd);
|
|
|
|
device->RenderPassEnd(cmd);
|
|
|
|
wi::renderer::Postprocess_Blur_Bilateral(
|
|
rtVolumetricLights[0],
|
|
rtLinearDepth,
|
|
rtVolumetricLights[1],
|
|
rtVolumetricLights[0],
|
|
cmd
|
|
);
|
|
|
|
wi::profiler::EndRange(range);
|
|
}
|
|
}
|
|
void RenderPath3D::RenderSceneMIPChain(CommandList cmd) const
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
auto range = wi::profiler::BeginRangeGPU("Scene MIP Chain", cmd);
|
|
device->EventBegin("RenderSceneMIPChain", cmd);
|
|
|
|
device->RenderPassBegin(&renderpass_downsamplescene, cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)rtSceneCopy.GetDesc().width;
|
|
vp.height = (float)rtSceneCopy.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
wi::image::Params fx;
|
|
fx.enableFullScreen();
|
|
fx.sampleFlag = wi::image::SAMPLEMODE_CLAMP;
|
|
fx.quality = wi::image::QUALITY_LINEAR;
|
|
fx.blendFlag = BLENDMODE_OPAQUE;
|
|
wi::image::Draw(&rtMain, fx, cmd);
|
|
|
|
device->RenderPassEnd(cmd);
|
|
|
|
wi::renderer::MIPGEN_OPTIONS mipopt;
|
|
mipopt.gaussian_temp = &rtSceneCopy_tmp;
|
|
wi::renderer::GenerateMipChain(rtSceneCopy, wi::renderer::MIPGENFILTER_GAUSSIAN, cmd, mipopt);
|
|
|
|
device->EventEnd(cmd);
|
|
wi::profiler::EndRange(range);
|
|
}
|
|
void RenderPath3D::RenderTransparents(CommandList cmd) const
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
// Water ripple rendering:
|
|
device->RenderPassBegin(&renderpass_waterripples, cmd); // always clear the water ripple rt, because it will always be sampled, whether there were any ripples or not
|
|
if(!scene->waterRipples.empty())
|
|
{
|
|
Viewport vp;
|
|
vp.width = (float)rtWaterRipple.GetDesc().width;
|
|
vp.height = (float)rtWaterRipple.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
wi::renderer::DrawWaterRipples(visibility_main, cmd);
|
|
}
|
|
device->RenderPassEnd(cmd);
|
|
|
|
device->RenderPassBegin(&renderpass_transparent, cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)depthBuffer_Main.GetDesc().width;
|
|
vp.height = (float)depthBuffer_Main.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
// Transparent scene
|
|
{
|
|
auto range = wi::profiler::BeginRangeGPU("Transparent Scene", cmd);
|
|
device->EventBegin("Transparent Scene", cmd);
|
|
|
|
uint32_t drawscene_flags = 0;
|
|
drawscene_flags |= wi::renderer::DRAWSCENE_TRANSPARENT;
|
|
drawscene_flags |= wi::renderer::DRAWSCENE_OCCLUSIONCULLING;
|
|
drawscene_flags |= wi::renderer::DRAWSCENE_HAIRPARTICLE;
|
|
drawscene_flags |= wi::renderer::DRAWSCENE_TESSELLATION;
|
|
wi::renderer::DrawScene(visibility_main, RENDERPASS_MAIN, cmd, drawscene_flags);
|
|
|
|
device->EventEnd(cmd);
|
|
wi::profiler::EndRange(range); // Transparent Scene
|
|
}
|
|
|
|
wi::renderer::DrawLightVisualizers(visibility_main, cmd);
|
|
|
|
wi::renderer::DrawSoftParticles(visibility_main, rtLinearDepth, false, cmd);
|
|
|
|
if (getVolumeLightsEnabled() && visibility_main.IsRequestedVolumetricLights())
|
|
{
|
|
device->EventBegin("Contribute Volumetric Lights", cmd);
|
|
wi::renderer::Postprocess_Upsample_Bilateral(rtVolumetricLights[0], rtLinearDepth,
|
|
*renderpass_transparent.desc.attachments[0].texture, cmd, true, 1.5f);
|
|
device->EventEnd(cmd);
|
|
}
|
|
|
|
XMVECTOR sunDirection = XMLoadFloat3(&scene->weather.sunDirection);
|
|
if (getLightShaftsEnabled() && XMVectorGetX(XMVector3Dot(sunDirection, camera->GetAt())) > 0)
|
|
{
|
|
device->EventBegin("Contribute LightShafts", cmd);
|
|
wi::image::Params fx;
|
|
fx.enableFullScreen();
|
|
fx.blendFlag = BLENDMODE_ADDITIVE;
|
|
wi::image::Draw(&rtSun[1], fx, cmd);
|
|
device->EventEnd(cmd);
|
|
}
|
|
|
|
if (getLensFlareEnabled())
|
|
{
|
|
wi::renderer::DrawLensFlares(
|
|
visibility_main,
|
|
cmd,
|
|
scene->weather.IsVolumetricClouds() ? &volumetriccloudResources.texture_cloudMask : nullptr
|
|
);
|
|
}
|
|
|
|
wi::renderer::DrawDebugWorld(*scene, *camera, *this, cmd);
|
|
|
|
device->RenderPassEnd(cmd);
|
|
|
|
// Distortion particles:
|
|
{
|
|
device->RenderPassBegin(&renderpass_particledistortion, cmd);
|
|
|
|
Viewport vp;
|
|
vp.width = (float)rtParticleDistortion.GetDesc().width;
|
|
vp.height = (float)rtParticleDistortion.GetDesc().height;
|
|
device->BindViewports(1, &vp, cmd);
|
|
|
|
wi::renderer::DrawSoftParticles(visibility_main, rtLinearDepth, true, cmd);
|
|
|
|
device->RenderPassEnd(cmd);
|
|
}
|
|
}
|
|
void RenderPath3D::RenderPostprocessChain(CommandList cmd) const
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
const Texture* rt_first = nullptr; // not ping-ponged with read / write
|
|
const Texture* rt_read = &rtMain;
|
|
const Texture* rt_write = &rtPostprocess;
|
|
|
|
// 1.) HDR post process chain
|
|
{
|
|
if (wi::renderer::GetTemporalAAEnabled() && !wi::renderer::GetTemporalAADebugEnabled())
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
wi::renderer::Postprocess_TemporalAA(
|
|
temporalAAResources,
|
|
*rt_read,
|
|
cmd
|
|
);
|
|
rt_first = temporalAAResources.GetCurrent();
|
|
}
|
|
|
|
if (scene->weather.IsOceanEnabled())
|
|
{
|
|
wi::renderer::Postprocess_Underwater(
|
|
rt_first == nullptr ? *rt_read : *rt_first,
|
|
*rt_write,
|
|
cmd
|
|
);
|
|
|
|
rt_first = nullptr;
|
|
std::swap(rt_read, rt_write);
|
|
}
|
|
|
|
if (getDepthOfFieldEnabled() && camera->aperture_size > 0 && getDepthOfFieldStrength() > 0)
|
|
{
|
|
wi::renderer::Postprocess_DepthOfField(
|
|
depthoffieldResources,
|
|
rt_first == nullptr ? *rt_read : *rt_first,
|
|
*rt_write,
|
|
cmd,
|
|
getDepthOfFieldStrength()
|
|
);
|
|
|
|
rt_first = nullptr;
|
|
std::swap(rt_read, rt_write);
|
|
}
|
|
|
|
if (getMotionBlurEnabled() && getMotionBlurStrength() > 0)
|
|
{
|
|
wi::renderer::Postprocess_MotionBlur(
|
|
motionblurResources,
|
|
rt_first == nullptr ? *rt_read : *rt_first,
|
|
*rt_write,
|
|
cmd,
|
|
getMotionBlurStrength()
|
|
);
|
|
|
|
rt_first = nullptr;
|
|
std::swap(rt_read, rt_write);
|
|
}
|
|
}
|
|
|
|
// 2.) Tone mapping HDR -> LDR
|
|
{
|
|
// Bloom and eye adaption is not part of post process "chain",
|
|
// because they will be applied to the screen in tonemap
|
|
if (getEyeAdaptionEnabled())
|
|
{
|
|
wi::renderer::ComputeLuminance(
|
|
luminanceResources,
|
|
rt_first == nullptr ? *rt_read : *rt_first,
|
|
cmd,
|
|
getEyeAdaptionRate(),
|
|
getEyeAdaptionKey()
|
|
);
|
|
}
|
|
if (getBloomEnabled())
|
|
{
|
|
wi::renderer::ComputeBloom(
|
|
bloomResources,
|
|
rt_first == nullptr ? *rt_read : *rt_first,
|
|
cmd,
|
|
getBloomThreshold(),
|
|
getExposure(),
|
|
getEyeAdaptionEnabled() ? &luminanceResources.luminance : nullptr
|
|
);
|
|
}
|
|
|
|
wi::renderer::Postprocess_Tonemap(
|
|
rt_first == nullptr ? *rt_read : *rt_first,
|
|
*rt_write,
|
|
cmd,
|
|
getExposure(),
|
|
getDitherEnabled(),
|
|
getColorGradingEnabled() ? (scene->weather.colorGradingMap.IsValid() ? &scene->weather.colorGradingMap.GetTexture() : nullptr) : nullptr,
|
|
getMSAASampleCount() > 1 ? &rtParticleDistortion_Resolved : &rtParticleDistortion,
|
|
getEyeAdaptionEnabled() ? &luminanceResources.luminance : nullptr,
|
|
getBloomEnabled() ? &bloomResources.texture_bloom : nullptr,
|
|
colorspace
|
|
);
|
|
|
|
rt_first = nullptr;
|
|
std::swap(rt_read, rt_write);
|
|
}
|
|
|
|
// 3.) LDR post process chain
|
|
{
|
|
if (getSharpenFilterEnabled())
|
|
{
|
|
wi::renderer::Postprocess_Sharpen(*rt_read, *rt_write, cmd, getSharpenFilterAmount());
|
|
|
|
std::swap(rt_read, rt_write);
|
|
}
|
|
|
|
if (getFXAAEnabled())
|
|
{
|
|
wi::renderer::Postprocess_FXAA(*rt_read, *rt_write, cmd);
|
|
|
|
std::swap(rt_read, rt_write);
|
|
}
|
|
|
|
if (getChromaticAberrationEnabled())
|
|
{
|
|
wi::renderer::Postprocess_Chromatic_Aberration(*rt_read, *rt_write, cmd, getChromaticAberrationAmount());
|
|
|
|
std::swap(rt_read, rt_write);
|
|
}
|
|
|
|
lastPostprocessRT = rt_read;
|
|
|
|
// GUI Background blurring:
|
|
{
|
|
auto range = wi::profiler::BeginRangeGPU("GUI Background Blur", cmd);
|
|
device->EventBegin("GUI Background Blur", cmd);
|
|
wi::renderer::Postprocess_Downsample4x(*rt_read, rtGUIBlurredBackground[0], cmd);
|
|
wi::renderer::Postprocess_Downsample4x(rtGUIBlurredBackground[0], rtGUIBlurredBackground[2], cmd);
|
|
wi::renderer::Postprocess_Blur_Gaussian(rtGUIBlurredBackground[2], rtGUIBlurredBackground[1], rtGUIBlurredBackground[2], cmd, -1,-1, true);
|
|
device->EventEnd(cmd);
|
|
wi::profiler::EndRange(range);
|
|
}
|
|
|
|
if (rtFSR[0].IsValid() && getFSREnabled())
|
|
{
|
|
wi::renderer::Postprocess_FSR(*rt_read, rtFSR[1], rtFSR[0], cmd, getFSRSharpness());
|
|
lastPostprocessRT = &rtFSR[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderPath3D::setAO(AO value)
|
|
{
|
|
ao = value;
|
|
|
|
rtAO = {};
|
|
ssaoResources = {};
|
|
msaoResources = {};
|
|
rtaoResources = {};
|
|
|
|
if (ao == AO_DISABLED)
|
|
{
|
|
return;
|
|
}
|
|
|
|
XMUINT2 internalResolution = GetInternalResolution();
|
|
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = Format::R8_UNORM;
|
|
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
|
|
|
switch (ao)
|
|
{
|
|
case RenderPath3D::AO_SSAO:
|
|
case RenderPath3D::AO_HBAO:
|
|
desc.width = internalResolution.x / 2;
|
|
desc.height = internalResolution.y / 2;
|
|
wi::renderer::CreateSSAOResources(ssaoResources, internalResolution);
|
|
break;
|
|
case RenderPath3D::AO_MSAO:
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
wi::renderer::CreateMSAOResources(msaoResources, internalResolution);
|
|
break;
|
|
case RenderPath3D::AO_RTAO:
|
|
desc.width = internalResolution.x / 2;
|
|
desc.height = internalResolution.y / 2;
|
|
wi::renderer::CreateRTAOResources(rtaoResources, internalResolution);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
device->CreateTexture(&desc, nullptr, &rtAO);
|
|
device->SetName(&rtAO, "rtAO");
|
|
}
|
|
|
|
void RenderPath3D::setSSREnabled(bool value)
|
|
{
|
|
ssrEnabled = value;
|
|
|
|
if (value)
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
XMUINT2 internalResolution = GetInternalResolution();
|
|
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = Format::R16G16B16A16_FLOAT;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
desc.layout = ResourceState::SHADER_RESOURCE_COMPUTE;
|
|
device->CreateTexture(&desc, nullptr, &rtSSR);
|
|
device->SetName(&rtSSR, "rtSSR");
|
|
|
|
wi::renderer::CreateSSRResources(ssrResources, internalResolution);
|
|
}
|
|
else
|
|
{
|
|
ssrResources = {};
|
|
}
|
|
}
|
|
|
|
void RenderPath3D::setRaytracedReflectionsEnabled(bool value)
|
|
{
|
|
raytracedReflectionsEnabled = value;
|
|
|
|
if (value)
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
XMUINT2 internalResolution = GetInternalResolution();
|
|
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = Format::R16G16B16A16_FLOAT;
|
|
desc.width = internalResolution.x;
|
|
desc.height = internalResolution.y;
|
|
device->CreateTexture(&desc, nullptr, &rtSSR);
|
|
device->SetName(&rtSSR, "rtSSR");
|
|
|
|
wi::renderer::CreateRTReflectionResources(rtreflectionResources, internalResolution);
|
|
}
|
|
else
|
|
{
|
|
rtreflectionResources = {};
|
|
}
|
|
}
|
|
|
|
void RenderPath3D::setFSREnabled(bool value)
|
|
{
|
|
fsrEnabled = value;
|
|
|
|
if (resolutionScale < 1.0f && fsrEnabled)
|
|
{
|
|
GraphicsDevice* device = wi::graphics::GetDevice();
|
|
|
|
TextureDesc desc;
|
|
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
|
|
desc.format = rtPostprocess.desc.format;
|
|
desc.width = GetPhysicalWidth();
|
|
desc.height = GetPhysicalHeight();
|
|
device->CreateTexture(&desc, nullptr, &rtFSR[0]);
|
|
device->SetName(&rtFSR[0], "rtFSR[0]");
|
|
device->CreateTexture(&desc, nullptr, &rtFSR[1]);
|
|
device->SetName(&rtFSR[1], "rtFSR[1]");
|
|
}
|
|
else
|
|
{
|
|
rtFSR[0] = {};
|
|
rtFSR[1] = {};
|
|
}
|
|
}
|
|
|
|
}
|