mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-10 06:25:31 +01:00
Take the ambient occlusion into the lighting and add a probe of the cab
This commit is contained in:
@@ -116,6 +116,70 @@ void vulkan14_renderer::destroy_ao()
|
||||
scene.ssao_noise.reset();
|
||||
}
|
||||
|
||||
// the ambient occlusion goes into the light of the surfaces of the colour pass of the main view (gfx.postfx.ao.lighting,
|
||||
// opengl46_renderer::Ao_Lighting_Wanted()): the ground truth one, made from the depth of the whole scene drawn before the colour,
|
||||
// which needs a perspective projection with the far plane at infinity (the distance of a surface worked out from its depth)
|
||||
bool vulkan14_renderer::ao_lighting_wanted(viewport_config const &Viewport) const
|
||||
{
|
||||
if ((Global.gfx_postfx_ao != 2) || (false == Global.gfx_postfx_ao_lighting) || (false == Viewport.main) || Global.bWireFrame || Global.gfx_skippipeline)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto const &targets{m_context->scene.targets};
|
||||
if (targets.empty() || (false == bool(targets.front().ssao)) || (false == bool(targets.front().ssao_blur)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto const &projection{scene_ubs.projection};
|
||||
return (projection[2][3] != 0.f) && (projection[2][2] == 0.f) && (projection[3][2] > 0.f);
|
||||
}
|
||||
|
||||
// the ground truth ambient occlusion of the depth of the scene drawn before the colour (render_scene_depth()), for the shading of the
|
||||
// colour pass, left in the layout it reads it in. outside a rendering
|
||||
bool vulkan14_renderer::compute_ao_lighting(std::size_t const Index)
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
auto &targets{scene.targets[Index]};
|
||||
auto const commands{ctx.commands};
|
||||
if ((false == bool(targets.ssao)) || (false == bool(targets.ssao_blur)) || (false == bool(targets.scene_depth)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ctx.passes.begin_pass("ambient occlusion");
|
||||
// the projection the depth was drawn with
|
||||
auto const &projection{m_colorpass.pass_camera.projection()};
|
||||
auto const inverseprojection{glm::inverse(projection)};
|
||||
auto const width{targets.ssao->desc().extent.width};
|
||||
auto const height{targets.ssao->desc().extent.height};
|
||||
auto const groups_x{(width + GROUP_SIZE - 1) / GROUP_SIZE};
|
||||
auto const groups_y{(height + GROUP_SIZE - 1) / GROUP_SIZE};
|
||||
// horizon search
|
||||
vk14::barriers(commands, {vk14::use_of(*targets.scene_depth, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampled_stage, sampled_access),
|
||||
vk14::use_of(*targets.ssao, VK_IMAGE_LAYOUT_GENERAL, compute_stage, VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT)});
|
||||
gtao_constants constants{};
|
||||
constants.inv_projection = inverseprojection;
|
||||
constants.params = glm::vec2{Global.gfx_postfx_ao_radius, projection[0][0] * 0.5f * static_cast<float>(width)};
|
||||
constants.clipw_row = glm::vec4{projection[0][3], projection[1][3], projection[2][3], projection[3][3]};
|
||||
constants.quality = glm::ivec2{Global.gfx_postfx_ao_slices, Global.gfx_postfx_ao_steps};
|
||||
auto const depthimage{vk14::image_descriptor(ctx.sampling.clamp_nearest, targets.scene_depth->view(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)};
|
||||
scene.gtao_main.dispatch(commands, {depthimage, vk14::storage_image(targets.ssao->view())}, constants, groups_x, groups_y);
|
||||
// smoothing
|
||||
vk14::barriers(commands, {vk14::use_of(*targets.ssao, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampled_stage, sampled_access),
|
||||
vk14::use_of(*targets.ssao_blur, VK_IMAGE_LAYOUT_GENERAL, compute_stage, VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT)});
|
||||
scene.gtao_denoise.dispatch(commands, {depthimage, vk14::image_descriptor(ctx.sampling.clamp_nearest, targets.ssao->view(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL), vk14::storage_image(targets.ssao_blur->view())},
|
||||
inverseprojection, groups_x, groups_y);
|
||||
vk14::barriers(commands, {vk14::use_of(*targets.ssao_blur, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampled_stage, sampled_access)});
|
||||
return true;
|
||||
}
|
||||
|
||||
// the block of the scene of the colour pass set up to read the occlusion (light_common.glsl, ambient_occlusion())
|
||||
void vulkan14_renderer::setup_ao_lighting()
|
||||
{
|
||||
scene_ubs.ao_params = glm::vec4{1.f, Global.gfx_postfx_ao_strength, 0.f, 0.f};
|
||||
upload_scene_block();
|
||||
}
|
||||
|
||||
// the ambient occlusion of the viewport from the depth of its scene (resolved), multiplied into its colour
|
||||
// (opengl46_renderer::Render_ambient_occlusion()). Mode: Global.gfx_postfx_ao. outside a rendering
|
||||
void vulkan14_renderer::render_ao(std::size_t const Index, int const Mode)
|
||||
|
||||
@@ -73,7 +73,14 @@ constexpr std::uint32_t SCENE_DEPTH_TEX = 24;
|
||||
constexpr std::uint32_t SSR_HISTORY_TEX = 25;
|
||||
// the water on the windscreens (gfx::windscreen_water): the drops, their grids and the wetted paths the glasses read
|
||||
constexpr std::uint32_t WATER_SSBO = 26;
|
||||
constexpr std::uint32_t PASS_BINDING_COUNT = 27;
|
||||
// the ambient occlusion of the main view in the light of the surfaces (gfx.postfx.ao.lighting, the stage A3), half its size
|
||||
constexpr std::uint32_t SCENE_AO_TEX = 27;
|
||||
// the probe of the occupied cab (gfx::cab_probe, the stage A4): the cube maps of the light of its lamps the cab reflects and of its
|
||||
// albedo, and the light it lights the cab with again (gl::cab_probe_data)
|
||||
constexpr std::uint32_t CAB_PROBE_TEX = 28;
|
||||
constexpr std::uint32_t CAB_PROBE_ALBEDO_TEX = 29;
|
||||
constexpr std::uint32_t CAB_PROBE_SSBO = 30;
|
||||
constexpr std::uint32_t PASS_BINDING_COUNT = 31;
|
||||
// the offsets of the bindings above with dynamic offsets, in the order of the bindings
|
||||
constexpr std::uint32_t PASS_DYNAMIC_OFFSETS = 6;
|
||||
// the textures of a material take the bindings of their units (#pragma texture(name, unit, ...)), 0 .. MAX_TEXTURES - 1
|
||||
|
||||
405
rendering/vulkan14/vulkan14cabprobe.cpp
Normal file
405
rendering/vulkan14/vulkan14cabprobe.cpp
Normal file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// the probe of the occupied cab in the vulkan renderer (the stage A4 of the plan; opengl46_cab_probe and
|
||||
// opengl46_renderer::Render_cab_probe()): the maps of vk14::cab_probe_maps, the cab drawn to them by the colour mode of the shared walk
|
||||
// of the scene with the programs of the probe (the six faces at once by multiview), their mipmaps and the spherical harmonics of
|
||||
// the light the cab reflects (cabprobe_sh.comp)
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "rendering/vulkan14/vulkan14context.h"
|
||||
#include "rendering/vulkan14/vulkan14commands.h"
|
||||
#include "simulation/simulation.h"
|
||||
#include "utilities/Globals.h"
|
||||
#include "vehicle/DynObj.h"
|
||||
#include "vehicle/Train.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
VkPipelineStageFlags2 const colour_stage{VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
VkAccessFlags2 const colour_access{VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT};
|
||||
VkPipelineStageFlags2 const depth_stage{VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT};
|
||||
VkAccessFlags2 const depth_access{VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT};
|
||||
VkPipelineStageFlags2 const sampled_stage{VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT};
|
||||
VkAccessFlags2 const sampled_access{VK_ACCESS_2_SHADER_SAMPLED_READ_BIT};
|
||||
|
||||
// the formats of the maps: the light reflected (hdr) and the albedo
|
||||
VkFormat const LIGHT_FORMAT{VK_FORMAT_R16G16B16A16_SFLOAT};
|
||||
VkFormat const ALBEDO_FORMAT{VK_FORMAT_R8G8B8A8_UNORM};
|
||||
|
||||
// the mipmaps of a cube map whose first level was drawn: each level from the one before it, all of them left in the layout the
|
||||
// shading reads them in (the environment map makes its own the same way, render_reflections())
|
||||
void make_cube_mipmaps(vk14::command_stream *Commands, vk14::image &Image)
|
||||
{
|
||||
auto const mips{Image.desc().mips};
|
||||
auto const size{static_cast<std::int32_t>(Image.desc().extent.width)};
|
||||
auto barrier = [&](std::uint32_t Level, std::uint32_t Count, VkImageLayout From, VkImageLayout To, VkPipelineStageFlags2 SrcStage, VkAccessFlags2 SrcAccess, VkPipelineStageFlags2 DstStage, VkAccessFlags2 DstAccess) {
|
||||
VkImageMemoryBarrier2 entry{};
|
||||
entry.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||
entry.srcStageMask = SrcStage;
|
||||
entry.srcAccessMask = SrcAccess;
|
||||
entry.dstStageMask = DstStage;
|
||||
entry.dstAccessMask = DstAccess;
|
||||
entry.oldLayout = From;
|
||||
entry.newLayout = To;
|
||||
entry.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
entry.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
entry.image = Image.handle();
|
||||
entry.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, Level, Count, 0, 6};
|
||||
VkDependencyInfo dependency{};
|
||||
dependency.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
||||
dependency.imageMemoryBarrierCount = 1;
|
||||
dependency.pImageMemoryBarriers = &entry;
|
||||
Commands->pipeline_barrier2(&dependency);
|
||||
};
|
||||
// the first level was drawn, the others are undefined
|
||||
barrier(0, 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colour_stage, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_2_BLIT_BIT, VK_ACCESS_2_TRANSFER_READ_BIT);
|
||||
if (mips > 1)
|
||||
{
|
||||
barrier(1, mips - 1, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_2_NONE, VK_ACCESS_2_NONE, VK_PIPELINE_STAGE_2_BLIT_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
}
|
||||
for (std::uint32_t level = 1; level < mips; ++level)
|
||||
{
|
||||
VkImageBlit2 blit{};
|
||||
blit.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2;
|
||||
blit.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, level - 1, 0, 6};
|
||||
blit.srcOffsets[1] = {std::max(size >> (level - 1), 1), std::max(size >> (level - 1), 1), 1};
|
||||
blit.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, level, 0, 6};
|
||||
blit.dstOffsets[1] = {std::max(size >> level, 1), std::max(size >> level, 1), 1};
|
||||
VkBlitImageInfo2 info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2;
|
||||
info.srcImage = Image.handle();
|
||||
info.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
info.dstImage = Image.handle();
|
||||
info.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
info.regionCount = 1;
|
||||
info.pRegions = &blit;
|
||||
info.filter = VK_FILTER_LINEAR;
|
||||
Commands->blit_image2(&info);
|
||||
barrier(level, 1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_2_BLIT_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_2_BLIT_BIT, VK_ACCESS_2_TRANSFER_READ_BIT);
|
||||
}
|
||||
barrier(0, mips, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_2_BLIT_BIT, VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT, sampled_stage, sampled_access);
|
||||
Image.state = vk14::image_state{VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampled_stage, sampled_access};
|
||||
}
|
||||
|
||||
VkRenderingAttachmentInfo cleared_attachment(VkImageView const View, VkImageLayout const Layout, VkClearValue const &Value)
|
||||
{
|
||||
VkRenderingAttachmentInfo info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
|
||||
info.imageView = View;
|
||||
info.imageLayout = Layout;
|
||||
info.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
info.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
info.clearValue = Value;
|
||||
return info;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vk14
|
||||
{
|
||||
|
||||
cab_probe_maps::~cab_probe_maps()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void cab_probe_maps::init(VkDevice const Device, allocator &Memory, deletion_queue &Deletions)
|
||||
{
|
||||
m_device = Device;
|
||||
m_memory = &Memory;
|
||||
m_deletions = &Deletions;
|
||||
}
|
||||
|
||||
void cab_probe_maps::destroy()
|
||||
{
|
||||
// the device is idle: the maps go at once
|
||||
m_deletions = nullptr;
|
||||
let_go();
|
||||
}
|
||||
|
||||
bool cab_probe_maps::gpu_allocate(int const Size)
|
||||
{
|
||||
if ((m_memory == nullptr) || (Size <= 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto const size{static_cast<std::uint32_t>(Size)};
|
||||
// the maps: cube maps with their mipmaps, read by the shading, drawn to through a view of the six layers of the first level
|
||||
auto make_map = [&](std::shared_ptr<image> &Map, VkImageView &View, VkFormat const Format, char const *Name) {
|
||||
image_desc desc;
|
||||
desc.format = Format;
|
||||
desc.extent = {size, size, 1};
|
||||
desc.layers = 6;
|
||||
desc.mips = static_cast<std::uint32_t>(std::floor(std::log2(static_cast<float>(size)))) + 1;
|
||||
desc.view_type = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
desc.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
desc.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
Map = std::make_shared<image>();
|
||||
if (false == Map->create(*m_memory, desc, Name))
|
||||
{
|
||||
Map.reset();
|
||||
return false;
|
||||
}
|
||||
VkImageViewCreateInfo info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
info.image = Map->handle();
|
||||
info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
info.format = Format;
|
||||
info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 6};
|
||||
if (vkCreateImageView(m_device, &info, nullptr, &View) != VK_SUCCESS)
|
||||
{
|
||||
View = VK_NULL_HANDLE;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if ((false == make_map(m_light, m_lightview, LIGHT_FORMAT, "cab probe light")) || (false == make_map(m_albedo, m_albedoview, ALBEDO_FORMAT, "cab probe albedo")))
|
||||
{
|
||||
let_go();
|
||||
return false;
|
||||
}
|
||||
image_desc depth;
|
||||
depth.format = VK_FORMAT_D32_SFLOAT;
|
||||
depth.extent = {size, size, 1};
|
||||
depth.layers = 6;
|
||||
depth.view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
depth.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
m_depth = std::make_shared<image>();
|
||||
if (false == m_depth->create(*m_memory, depth, "cab probe depth"))
|
||||
{
|
||||
let_go();
|
||||
return false;
|
||||
}
|
||||
m_target = draw_target{m_light.get(), m_albedo.get(), m_depth.get(), m_lightview, m_albedoview, size};
|
||||
m_drawn = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void cab_probe_maps::gpu_release()
|
||||
{
|
||||
let_go();
|
||||
}
|
||||
|
||||
void cab_probe_maps::let_go()
|
||||
{
|
||||
m_target = draw_target{};
|
||||
m_drawn = false;
|
||||
std::vector<VkImageView> views;
|
||||
for (auto *view : {&m_lightview, &m_albedoview})
|
||||
{
|
||||
if (*view != VK_NULL_HANDLE)
|
||||
{
|
||||
views.push_back(*view);
|
||||
}
|
||||
*view = VK_NULL_HANDLE;
|
||||
}
|
||||
if (m_deletions != nullptr)
|
||||
{
|
||||
// the frames in flight may still read them
|
||||
m_deletions->push(m_value, [device = m_device, views = std::move(views), light = std::move(m_light), albedo = std::move(m_albedo), depth = std::move(m_depth)]() {
|
||||
for (auto *view : views)
|
||||
{
|
||||
vkDestroyImageView(device, view, nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto *view : views)
|
||||
{
|
||||
vkDestroyImageView(m_device, view, nullptr);
|
||||
}
|
||||
}
|
||||
m_light.reset();
|
||||
m_albedo.reset();
|
||||
m_depth.reset();
|
||||
}
|
||||
|
||||
} // namespace vk14
|
||||
|
||||
bool vulkan14_renderer::init_cab_probe(std::string &Reason)
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
auto const device{ctx.device.handle()};
|
||||
try
|
||||
{
|
||||
auto program = [&](char const *Fragment) {
|
||||
auto result{std::make_shared<vk14::scene_program>()};
|
||||
result->vertex = ctx.shaders.get("cabprobe.vert");
|
||||
result->fragment = ctx.shaders.get(Fragment);
|
||||
result->fragment_name = Fragment;
|
||||
result->vertex_name = "cabprobe.vert";
|
||||
result->vertices = vk14::vertex_kind::scene;
|
||||
result->name = std::string("cabprobe.vert + ") + Fragment;
|
||||
return result;
|
||||
};
|
||||
scene.cabprobe_program = program("cabprobe.frag");
|
||||
scene.cabprobe_alpha_program = program("cabprobe_alpha.frag");
|
||||
if (false == scene.cabprobe_sh.create(device, ctx.pipelines, ctx.shaders.get("cabprobe_sh.comp"), scene.pass_layout, {}, "cab probe spherical harmonics"))
|
||||
{
|
||||
Reason = "no compute pipeline of the cab probe";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (gfx::shader_exception const &e)
|
||||
{
|
||||
Reason = std::string("invalid shader: ") + e.what();
|
||||
return false;
|
||||
}
|
||||
// the light reflected and the albedo, the six faces drawn at once
|
||||
scene.cabprobe_formats.colour = {LIGHT_FORMAT, ALBEDO_FORMAT};
|
||||
scene.cabprobe_formats.colours = 2;
|
||||
scene.cabprobe_formats.depth = VK_FORMAT_D32_SFLOAT;
|
||||
scene.cabprobe_formats.view_mask = 0x3f;
|
||||
scene.cabprobe_formats.id = ++scene.formats_count;
|
||||
// the light the cab lights itself with again, cleared with the stand-ins in the first frame
|
||||
if (false == scene.cabprobe_bounce.create(ctx.memory, sizeof(gl::cab_probe_data), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, vk14::memory_kind::device, "cab probe bounce"))
|
||||
{
|
||||
Reason = "no buffer of the cab probe";
|
||||
return false;
|
||||
}
|
||||
// the stand-in of the maps: 1x1 faces of nothing, cleared with the other stand-ins in the first frame
|
||||
vk14::image_desc desc;
|
||||
desc.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.view_type = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
desc.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
desc.layers = 6;
|
||||
desc.extent = {1, 1, 1};
|
||||
desc.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
scene.cabprobe_empty = std::make_shared<vk14::image>();
|
||||
if (false == scene.cabprobe_empty->create(ctx.memory, desc, "empty cab probe"))
|
||||
{
|
||||
scene.cabprobe_empty.reset();
|
||||
Reason = "no stand-in of the cab probe";
|
||||
return false;
|
||||
}
|
||||
scene.cabprobe.init(device, ctx.memory, ctx.deletions);
|
||||
return true;
|
||||
}
|
||||
|
||||
void vulkan14_renderer::destroy_cab_probe()
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
scene.cabprobe.destroy();
|
||||
scene.cabprobe_sh.destroy(ctx.device.handle());
|
||||
scene.cabprobe_program.reset();
|
||||
scene.cabprobe_alpha_program.reset();
|
||||
scene.cabprobe_bounce.destroy();
|
||||
scene.cabprobe_empty.reset();
|
||||
}
|
||||
|
||||
TDynamicObject *vulkan14_renderer::cab_probe_vehicle() const
|
||||
{
|
||||
// the conditions of Render_cab()
|
||||
if (FreeFlyModeFlag || (false == Global.render_cab) || (simulation::Train == nullptr))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto *vehicle{simulation::Train->Dynamic()};
|
||||
if ((vehicle == nullptr) || (false == vehicle->bDisplayCab) || (vehicle->mdKabina == nullptr) || (vehicle->mdKabina == vehicle->mdModel))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
void vulkan14_renderer::render_cab_probe()
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
auto &probe{scene.cabprobe};
|
||||
auto const commands{ctx.commands};
|
||||
auto *vehicle{cab_probe_vehicle()};
|
||||
glm::vec3 center{0.f};
|
||||
glm::vec3 extent{0.f};
|
||||
if ((vehicle != nullptr) && (false == m_locallights.cab_bounds(vehicle->mdKabina, m_geometry, center, extent)))
|
||||
{
|
||||
vehicle = nullptr;
|
||||
}
|
||||
// the cab lamp lights the probe when it's a light of the frame
|
||||
auto const *lamp{(vehicle != nullptr) && (m_locallights.cab_lamp_vehicle() == vehicle) ? m_locallights.cab_lamp() : nullptr};
|
||||
if (false == probe.update_wanted(vehicle, (vehicle != nullptr ? vehicle->mdKabina : nullptr), center, extent, lamp, m_framestamp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto const &target{probe.target()};
|
||||
if ((target.light == nullptr) || (target.albedo == nullptr) || (target.depth == nullptr) || (false == bool(scene.cabprobe_program)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ctx.passes.begin_pass("cab probe");
|
||||
// the lamp with its shadow map, when the map holds the shadows of the lamp where it is
|
||||
auto const shadows{(lamp != nullptr) && scene.lamps.ready(vehicle) && (scene.lamps.lamp() == m_locallights.cab_lamp_local())};
|
||||
probe.setup_drawing(scene_ubs, lamp, m_locallights.cab_lamp_local(), shadows, scene.lamps.weights());
|
||||
// the cab drawn by the colour mode with the programs of the probe. the camera is put at the vehicle, which Render_cab() places the cab
|
||||
// relative to, and the modelview takes the cab model to the space of the probe
|
||||
m_renderpass.draw_mode = rendermode::color;
|
||||
m_renderpass.pass_camera.position() = vehicle->GetPosition();
|
||||
m_renderpass.draw_stats = {};
|
||||
OpenGLMatrices.mode(GL_MODELVIEW);
|
||||
OpenGLMatrices.load_matrix(glm::mat4{probe.model_to_probe() * glm::inverse(vehicle->mMatrix)});
|
||||
probe.begin();
|
||||
std::vector<vk14::image_use> const uses{vk14::use_of(*target.light, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colour_stage, colour_access),
|
||||
vk14::use_of(*target.albedo, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colour_stage, colour_access),
|
||||
vk14::use_of(*target.depth, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, depth_stage, depth_access)};
|
||||
vk14::barriers(commands, uses);
|
||||
VkClearValue nothing{};
|
||||
nothing.color = {{0.f, 0.f, 0.f, 0.f}};
|
||||
VkClearValue farthest{};
|
||||
farthest.depthStencil = {0.f, 0};
|
||||
std::array<VkRenderingAttachmentInfo, 2> colours{cleared_attachment(target.light_view, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, nothing),
|
||||
cleared_attachment(target.albedo_view, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, nothing)};
|
||||
auto depth{cleared_attachment(target.depth->view(), VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, farthest)};
|
||||
VkRenderingInfo rendering{};
|
||||
rendering.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
|
||||
rendering.renderArea = {{0, 0}, {target.size, target.size}};
|
||||
rendering.layerCount = 1;
|
||||
rendering.viewMask = scene.cabprobe_formats.view_mask;
|
||||
rendering.colorAttachmentCount = static_cast<std::uint32_t>(colours.size());
|
||||
rendering.pColorAttachments = colours.data();
|
||||
rendering.pDepthAttachment = &depth;
|
||||
commands->begin_rendering(&rendering);
|
||||
remember_rendering(rendering, uses);
|
||||
// one sided walls face the probe from either side
|
||||
start_draws(scene.cabprobe_formats, static_cast<int>(target.size), static_cast<int>(target.size), vk14::scene_state::set_plain, false);
|
||||
m_draw->cullface = false;
|
||||
walk_blending(false);
|
||||
upload_scene_block();
|
||||
upload_light_header();
|
||||
m_draw->probepass = true;
|
||||
m_draw->depthskip = true;
|
||||
Render_cab(vehicle, 0.0f, false);
|
||||
m_draw->probepass = false;
|
||||
m_draw->depthskip = true;
|
||||
if (m_draw->rendering)
|
||||
{
|
||||
commands->end_rendering();
|
||||
}
|
||||
end_draws();
|
||||
// the mipmaps, and the light the cab lights itself with again from a small level of the light reflected
|
||||
make_cube_mipmaps(commands, *target.light);
|
||||
make_cube_mipmaps(commands, *target.albedo);
|
||||
struct
|
||||
{
|
||||
glm::ivec2 level;
|
||||
} constants{glm::ivec2{probe.sh_level(), probe.sh_size()}};
|
||||
scene.cabprobe_sh.dispatch(commands,
|
||||
{vk14::image_descriptor(ctx.sampling.clamp_linear, target.light->view(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
|
||||
vk14::buffer_descriptor(scene.cabprobe_bounce.handle(), 0, sizeof(gl::cab_probe_data))},
|
||||
constants, 1);
|
||||
vk14::memory_barrier(commands, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_STORAGE_READ_BIT);
|
||||
probe.drawn();
|
||||
probe.end(static_cast<std::uint32_t>(m_renderpass.draw_stats.drawcalls));
|
||||
m_renderpass = m_colorpass;
|
||||
ctx.passes.end_pass();
|
||||
}
|
||||
93
rendering/vulkan14/vulkan14cabprobe.h
Normal file
93
rendering/vulkan14/vulkan14cabprobe.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// the probe of the occupied cab in the vulkan renderer (the stage A4 of the plan, opengl46_cab_probe): the maps of gfx::cab_probe,
|
||||
// which tells when they're drawn and what the shading reads. the six faces are drawn at once by multiview (cabprobe.vert reads the
|
||||
// face from gl_ViewIndex) instead of the geometry shader of the opengl renderer; the renderer draws to the target the class keeps
|
||||
// (target()), makes the mipmaps and the spherical harmonics (vulkan14cabprobe.cpp)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rendering/common/cabprobe.h"
|
||||
#include "rendering/vulkan14/vulkan14memory.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace vk14
|
||||
{
|
||||
|
||||
class cab_probe_maps : public gfx::cab_probe
|
||||
{
|
||||
public:
|
||||
// what the drawing draws to: the views of the six layers of the first level of the maps and of the depth
|
||||
struct draw_target
|
||||
{
|
||||
image *light{nullptr};
|
||||
image *albedo{nullptr};
|
||||
image *depth{nullptr};
|
||||
VkImageView light_view{VK_NULL_HANDLE};
|
||||
VkImageView albedo_view{VK_NULL_HANDLE};
|
||||
std::uint32_t size{0};
|
||||
};
|
||||
|
||||
cab_probe_maps() = default;
|
||||
~cab_probe_maps() override;
|
||||
|
||||
// Device, Memory, Deletions: what the maps are made and let go with; called once
|
||||
void init(VkDevice Device, allocator &Memory, deletion_queue &Deletions);
|
||||
// the maps go (the device is about to)
|
||||
void destroy();
|
||||
// the value of the timeline the gpu reaches when it's done with the frame being recorded, before the drawing
|
||||
void begin_frame(std::uint64_t const Value)
|
||||
{
|
||||
m_value = Value;
|
||||
}
|
||||
draw_target const &target() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
// the maps, once drawn (in the layout the shading reads them in), for the pass sets; null: the stand-in is read
|
||||
image *light_map() const
|
||||
{
|
||||
return m_drawn ? m_light.get() : nullptr;
|
||||
}
|
||||
image *albedo_map() const
|
||||
{
|
||||
return m_drawn ? m_albedo.get() : nullptr;
|
||||
}
|
||||
// the maps were drawn and are in the layout the shading reads them in
|
||||
void drawn()
|
||||
{
|
||||
m_drawn = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool gpu_allocate(int const Size) override;
|
||||
void gpu_release() override;
|
||||
// the drawing is recorded by the renderer
|
||||
void gpu_begin() override {}
|
||||
void gpu_end() override {}
|
||||
|
||||
private:
|
||||
void let_go();
|
||||
|
||||
VkDevice m_device{VK_NULL_HANDLE};
|
||||
allocator *m_memory{nullptr};
|
||||
deletion_queue *m_deletions{nullptr};
|
||||
std::uint64_t m_value{0};
|
||||
std::shared_ptr<image> m_light;
|
||||
std::shared_ptr<image> m_albedo;
|
||||
std::shared_ptr<image> m_depth;
|
||||
VkImageView m_lightview{VK_NULL_HANDLE};
|
||||
VkImageView m_albedoview{VK_NULL_HANDLE};
|
||||
draw_target m_target;
|
||||
bool m_drawn{false};
|
||||
};
|
||||
|
||||
} // namespace vk14
|
||||
@@ -28,6 +28,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "rendering/vulkan14/vulkan14compute.h"
|
||||
#include "rendering/vulkan14/vulkan14cull.h"
|
||||
#include "rendering/vulkan14/vulkan14shadows.h"
|
||||
#include "rendering/vulkan14/vulkan14cabprobe.h"
|
||||
#include "rendering/vulkan14/vulkan14terrain.h"
|
||||
#include "rendering/vulkan14/vulkan14grass.h"
|
||||
#include "rendering/vulkan14/vulkan14particles.h"
|
||||
@@ -390,6 +391,14 @@ struct scene_state
|
||||
local_shadow_maps lamps;
|
||||
std::shared_ptr<scene_program> cube_shadow, cube_alpha_shadow;
|
||||
target_formats cube_formats;
|
||||
// the probe of the occupied cab (the stage A4): its maps, the programs and the targets drawing it, the kernel of the spherical
|
||||
// harmonics of the light it reflects and their storage (CAB_PROBE_SSBO), and the stand-in of its maps
|
||||
cab_probe_maps cabprobe;
|
||||
std::shared_ptr<scene_program> cabprobe_program, cabprobe_alpha_program;
|
||||
target_formats cabprobe_formats;
|
||||
compute_kernel cabprobe_sh;
|
||||
buffer cabprobe_bounce;
|
||||
std::shared_ptr<image> cabprobe_empty;
|
||||
// the materials of the heightmap terrain (the stage P6), made with the bank of the textures
|
||||
std::unique_ptr<terrain_materials> terrain;
|
||||
// the grass of the heightmap terrain, and its program, made when it's first drawn
|
||||
@@ -643,6 +652,8 @@ struct vulkan14_renderer::draw_state
|
||||
// don't draw is left out (depthskip, set by walk_material())
|
||||
bool depthpass{false};
|
||||
bool depthskip{true};
|
||||
// the probe of the cab (the stage A4): the walk draws with the programs of the probe, what they don't draw is left out alike
|
||||
bool probepass{false};
|
||||
// the pass sets of a culling, the instance buffer its output, for the indirect draws of its instances; null: the pass sets
|
||||
VkDescriptorSet const *cull_sets{nullptr};
|
||||
// the rendering under way, begun again where it was after it was ended for the compute passes of the culling
|
||||
|
||||
@@ -164,6 +164,10 @@ std::string vulkan14_renderer::scene_info()
|
||||
text += " contact shadows: " + std::string{Global.gfx_contactshadows == 3 ? "high" : Global.gfx_contactshadows == 2 ? "medium" : "low"} + ", rays " +
|
||||
to_string(Global.gfx_contactshadows_length, 2) + " m within " + to_string(Global.gfx_contactshadows_range, 0) + " m\n";
|
||||
}
|
||||
if (Global.gfx_cabprobe > 0)
|
||||
{
|
||||
text += " " + scene.cabprobe.info() + "\n";
|
||||
}
|
||||
text += cascades + line(" submodels:", colour.submodels, shadowstats.submodels) + line(" paths: ", colour.paths, shadowstats.paths) +
|
||||
line(" shapes: ", colour.shapes, shadowstats.shapes) + " traction: " + to_string(colour.traction, 7) + "\n" + " lines: " + to_string(colour.lines, 7) + "\n" +
|
||||
"particles: " + to_string(colour.particles, 7) + "\nlights: " + to_string(static_cast<int>(m_lights_lit), 7) + " (" + std::to_string(m_lights_dropped) + " over capacity), " +
|
||||
@@ -223,6 +227,8 @@ void vulkan14_renderer::draw_debug_ui()
|
||||
ImGui::Separator();
|
||||
scene.lamps.draw_debug_ui();
|
||||
ImGui::Separator();
|
||||
scene.cabprobe.draw_debug_ui();
|
||||
ImGui::Separator();
|
||||
char const *contactlevels[]{"no", "low (the sun)", "medium (the sun and 2 lamps)", "high (the sun and 4 lamps)"};
|
||||
ImGui::Combo("contact shadows (gfx.contactshadows)", &Global.gfx_contactshadows, contactlevels, IM_ARRAYSIZE(contactlevels));
|
||||
ImGui::SliderFloat("length of their rays, m (gfx.contactshadows.length)", &Global.gfx_contactshadows_length, 0.05f, 5.f, "%.2f", ImGuiSliderFlags_Logarithmic);
|
||||
@@ -323,6 +329,7 @@ void vulkan14_renderer::draw_debug_ui()
|
||||
ImGui::SliderFloat("ao bounce albedo", &Global.gfx_postfx_ao_bounce, 0.f, 1.f);
|
||||
ImGui::SliderInt("ao slices", &Global.gfx_postfx_ao_slices, 1, 8);
|
||||
ImGui::SliderInt("ao steps per side", &Global.gfx_postfx_ao_steps, 1, 16);
|
||||
ImGui::Checkbox("ao in the ambient light, not over the image (gfx.postfx.ao.lighting)", &Global.gfx_postfx_ao_lighting);
|
||||
}
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -609,6 +609,7 @@ bool vulkan14_renderer::Render()
|
||||
scene.cull.main.begin_frame(slot, value, ctx.completed());
|
||||
}
|
||||
scene.lamps.begin_frame(ctx.commands, value);
|
||||
scene.cabprobe.begin_frame(value);
|
||||
if (scene.terrain)
|
||||
{
|
||||
// textures of new heightmap terrain layers go to the arrays the terrain shader reads them from
|
||||
@@ -679,7 +680,8 @@ bool vulkan14_renderer::Render()
|
||||
if (false == scene.images_ready)
|
||||
{
|
||||
scene.images_ready = true;
|
||||
std::vector<vk14::image *> const standins{scene.shadow_empty.get(), scene.env_empty.get(), scene.volume_empty.get(), scene.cube_shadow_empty.get(), scene.headlight_shadow_empty.get(), scene.depth_empty.get()};
|
||||
std::vector<vk14::image *> const standins{scene.shadow_empty.get(), scene.env_empty.get(), scene.volume_empty.get(), scene.cube_shadow_empty.get(),
|
||||
scene.headlight_shadow_empty.get(), scene.depth_empty.get(), scene.cabprobe_empty.get()};
|
||||
std::vector<vk14::image_use> clears;
|
||||
for (auto *image : standins)
|
||||
{
|
||||
@@ -715,6 +717,8 @@ bool vulkan14_renderer::Render()
|
||||
vk14::barriers(ctx.commands, uses);
|
||||
// no light is assigned to any cluster until the culling pass runs
|
||||
ctx.commands->fill_buffer(scene.clusters.ranges.handle(), 0, VK_WHOLE_SIZE, 0);
|
||||
// nor does the cab light itself until its probe is drawn
|
||||
ctx.commands->fill_buffer(scene.cabprobe_bounce.handle(), 0, VK_WHOLE_SIZE, 0);
|
||||
VkMemoryBarrier2 barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2;
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT;
|
||||
@@ -1500,6 +1504,8 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
render_lamp_shadows();
|
||||
render_headlight_shadows();
|
||||
ready_lamp_maps();
|
||||
// the probe of the cab, which reads the map of the cab lamp
|
||||
render_cab_probe();
|
||||
}
|
||||
// the scenery around the camera the reflections are traced through, before the passes which trace them
|
||||
auto const raytracing{raytracing_wanted(vp)};
|
||||
@@ -1557,6 +1563,11 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
upload_weather_block();
|
||||
}
|
||||
|
||||
// the ambient occlusion the shading may read (SCENE_AO_TEX) is in the layout it's read in from the first frame on
|
||||
if (targets.ssao_blur && (targets.ssao_blur->state.layout == VK_IMAGE_LAYOUT_UNDEFINED))
|
||||
{
|
||||
vk14::barriers(commands, {vk14::use_of(*targets.ssao_blur, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampled_stage, sampled_access)});
|
||||
}
|
||||
// the colour of the scene: drawn to the images with the samples, resolved to the single ones
|
||||
auto const uses{colour_target_uses(targets)};
|
||||
ctx.passes.begin_pass("sky", uses);
|
||||
@@ -1579,11 +1590,25 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
setup_shadow_matrices();
|
||||
upload_scene_block();
|
||||
|
||||
// the probe of the cab, which the parts of the cab drawn in the colour pass of the main view read
|
||||
if (vp.main)
|
||||
{
|
||||
scene.cabprobe.setup_scene(scene_ubs, cab_probe_vehicle(), m_colorpass.pass_camera.position(), glm::mat3{m_colorpass.pass_camera.modelview()});
|
||||
m_cabprobelit = (scene_ubs.cab_probe_box.w > 0.f);
|
||||
if (m_cabprobelit)
|
||||
{
|
||||
upload_scene_block();
|
||||
}
|
||||
}
|
||||
|
||||
// the depth of the whole opaque scene before its colour, which the contact shadows need
|
||||
m_indirectcolourpending = false;
|
||||
m_aolighting = false;
|
||||
auto const contactshadows{contact_shadows_wanted(vp)};
|
||||
auto const reflections{m_ssrframe && (false == Global.bWireFrame)};
|
||||
if ((Global.gfx_depthprepass_scene || contactshadows || reflections) && vp.main && (false == Global.bWireFrame))
|
||||
// and the ambient occlusion in the light of the surfaces
|
||||
auto const aolighting{ao_lighting_wanted(vp)};
|
||||
if ((Global.gfx_depthprepass_scene || contactshadows || reflections || aolighting) && vp.main && (false == Global.bWireFrame))
|
||||
{
|
||||
render_scene_depth(Index, future);
|
||||
if (contactshadows)
|
||||
@@ -1594,6 +1619,10 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
{
|
||||
setup_screen_reflections(Index, taa);
|
||||
}
|
||||
if (m_aolighting)
|
||||
{
|
||||
setup_ao_lighting();
|
||||
}
|
||||
}
|
||||
|
||||
// opaque parts...
|
||||
@@ -1668,14 +1697,17 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
}
|
||||
commands->end_rendering();
|
||||
end_draws();
|
||||
if (m_contactshadows || m_ssractive)
|
||||
if (m_contactshadows || m_ssractive || m_aolighting || m_cabprobelit)
|
||||
{
|
||||
// the depth they read is of this view only
|
||||
// the depth they read is of this view only, and so is the probe of the cab
|
||||
m_contactshadows = false;
|
||||
m_ssractive = false;
|
||||
m_cabprobelit = false;
|
||||
scene_ubs.contact_shadow_params = glm::vec4{0.f};
|
||||
scene_ubs.contact_shadow_lamps = glm::vec4{0.f};
|
||||
scene_ubs.ao_params = glm::vec4{0.f};
|
||||
gfx::screen_reflections::clear(scene_ubs);
|
||||
gfx::cab_probe::clear_scene(scene_ubs);
|
||||
}
|
||||
// the images resolved and drawn are read by the post-processing
|
||||
m_colorpass.draw_stats = m_renderpass.draw_stats;
|
||||
@@ -1698,8 +1730,10 @@ void vulkan14_renderer::render_scene_depth(std::size_t const Index, glm::mat4 co
|
||||
auto &draw{*m_draw};
|
||||
auto const commands{ctx.commands};
|
||||
auto const msaa{targets.samples != VK_SAMPLE_COUNT_1_BIT};
|
||||
// the depth copied apart from the one the colour pass goes on with, for the contact shadows and the screen space reflections
|
||||
auto const contact{contact_shadows_wanted(m_viewports[Index]) || m_ssrframe};
|
||||
// the depth copied apart from the one the colour pass goes on with, for the contact shadows, the screen space reflections and the
|
||||
// ambient occlusion in the light of the surfaces
|
||||
auto const aolighting{ao_lighting_wanted(m_viewports[Index])};
|
||||
auto const contact{contact_shadows_wanted(m_viewports[Index]) || m_ssrframe || aolighting};
|
||||
commands->end_rendering();
|
||||
// what the draws go on with
|
||||
auto const set{draw.set};
|
||||
@@ -1794,6 +1828,11 @@ void vulkan14_renderer::render_scene_depth(std::size_t const Index, glm::mat4 co
|
||||
copy.pRegions = ®ion;
|
||||
commands->copy_image2(©);
|
||||
vk14::barriers(commands, {vk14::use_of(*targets.scene_depth, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampled_stage, sampled_access)});
|
||||
// the ambient occlusion of the depth, between the renderings (compute)
|
||||
if (aolighting)
|
||||
{
|
||||
m_aolighting = compute_ao_lighting(Index);
|
||||
}
|
||||
}
|
||||
// the colour pass goes on where the sky left it
|
||||
vk14::barriers(commands, colour_target_uses(targets));
|
||||
@@ -3478,8 +3517,9 @@ void vulkan14_renderer::render_post(std::size_t const Index, bool const Motionbl
|
||||
auto const commands{ctx.commands};
|
||||
|
||||
// the occlusion goes into the image before the blur, which smears both alike. the targets are there only when it was on as they
|
||||
// were made
|
||||
auto const aomode{(targets.ssao != nullptr) ? Global.gfx_postfx_ao : 0};
|
||||
// were made. in the light of the surfaces it's in the image already
|
||||
auto const aomode{((targets.ssao != nullptr) && (false == m_aolighting)) ? Global.gfx_postfx_ao : 0};
|
||||
m_aolighting = false;
|
||||
if (aomode != 0)
|
||||
{
|
||||
ctx.passes.begin_pass("ambient occlusion");
|
||||
|
||||
@@ -389,6 +389,19 @@ class vulkan14_renderer : public gfx_renderer, public gfx::scene_walk
|
||||
bool init_ao(std::string &Reason);
|
||||
void destroy_ao();
|
||||
void render_ao(std::size_t const Viewport, int const Mode);
|
||||
// the ambient occlusion in the light of the surfaces (gfx.postfx.ao.lighting, the stage A3): whether the colour pass of the
|
||||
// viewport takes it, the occlusion worked out from the depth of the scene drawn before the colour (outside a rendering; false: it
|
||||
// couldn't be), and the block of the scene set up for the colour pass to read it
|
||||
bool ao_lighting_wanted(viewport_config const &Viewport) const;
|
||||
bool compute_ao_lighting(std::size_t const Viewport);
|
||||
void setup_ao_lighting();
|
||||
bool m_aolighting{false};
|
||||
// the probe of the occupied cab (vulkan14cabprobe.cpp, the stage A4; opengl46_renderer::Render_cab_probe()): the resources, the
|
||||
// occupied vehicle whose cab is drawn (nullptr: none), the drawing of the probe when it needs it in this frame
|
||||
bool init_cab_probe(std::string &Reason);
|
||||
void destroy_cab_probe();
|
||||
TDynamicObject *cab_probe_vehicle() const;
|
||||
void render_cab_probe();
|
||||
// the particles of the gpu: what the colour pass under way draws them with, and the depth of the scene drawn so far copied for
|
||||
// the soft particles (false: they aren't soft)
|
||||
gfx::gpu_particles::view particles_view() const;
|
||||
|
||||
@@ -151,6 +151,7 @@ VkDescriptorType pass_binding_type(std::uint32_t const Binding)
|
||||
case CLUSTER_INDEX_SSBO:
|
||||
case SKY_SSBO:
|
||||
case WATER_SSBO:
|
||||
case CAB_PROBE_SSBO:
|
||||
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
case ATMOSPHERE_UBO:
|
||||
case WEATHER_HORIZON_UBO:
|
||||
@@ -193,6 +194,14 @@ std::array<std::array<VkImageView, vk14::bindings::PASS_BINDING_COUNT>, 3> pass_
|
||||
views[SCENE_DEPTH_TEX] = (colour && (false == scene.targets.empty()) && scene.targets.front().scene_depth ? scene.targets.front().scene_depth->view() : scene.depth_empty->view());
|
||||
// the image of the last frame of the main view, which the screen space reflections take their colour from
|
||||
views[SSR_HISTORY_TEX] = (colour && (false == scene.targets.empty()) && scene.targets.front().ssr_history ? scene.targets.front().ssr_history->view() : scene.white->view());
|
||||
// the ambient occlusion of the main view the shading takes into the ambient light (the stage A3)
|
||||
views[SCENE_AO_TEX] = (colour && (false == scene.targets.empty()) && scene.targets.front().ssao_blur ? scene.targets.front().ssao_blur->view() : scene.white->view());
|
||||
// the probe of the cab, once it was drawn (the stage A4)
|
||||
auto const *probelight{scene.cabprobe.light_map()};
|
||||
auto const *probealbedo{scene.cabprobe.albedo_map()};
|
||||
auto const probeempty{scene.cabprobe_empty ? scene.cabprobe_empty->view() : scene.env_empty->view()};
|
||||
views[CAB_PROBE_TEX] = (colour && (probelight != nullptr) ? probelight->view() : probeempty);
|
||||
views[CAB_PROBE_ALBEDO_TEX] = (colour && (probealbedo != nullptr) ? probealbedo->view() : probeempty);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -650,7 +659,7 @@ bool vulkan14_renderer::init_scene(std::string &Reason)
|
||||
}
|
||||
|
||||
// the light of the sky, the exposure, the weather
|
||||
if ((false == init_sky(Reason)) || (false == init_weather(Reason)) || (false == init_ao(Reason)))
|
||||
if ((false == init_sky(Reason)) || (false == init_weather(Reason)) || (false == init_ao(Reason)) || (false == init_cab_probe(Reason)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -822,6 +831,7 @@ void vulkan14_renderer::destroy_scene()
|
||||
destroy_sky();
|
||||
destroy_weather();
|
||||
destroy_ao();
|
||||
destroy_cab_probe();
|
||||
for (auto *pool : scene.occlusion_pools)
|
||||
{
|
||||
vkDestroyQueryPool(device, pool, nullptr);
|
||||
@@ -968,6 +978,7 @@ void vulkan14_renderer::write_pass_sets(vk14::instance_cull *Cull)
|
||||
VkDescriptorBufferInfo const weatherblock{ctx.ring.handle(), 0, offsetof(gl::weather_ubs, fog_horizon)};
|
||||
VkDescriptorBufferInfo const horizonblock{scene.weather_horizon.handle(), 0, sizeof(glm::vec4) * gl::FOG_HORIZON_SAMPLES};
|
||||
VkDescriptorBufferInfo const water{scene.water.storage(), 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo const cabprobe{scene.cabprobe_bounce.handle(), 0, sizeof(gl::cab_probe_data)};
|
||||
VkDescriptorImageInfo const headlightsinfo{scene.headlights_sampler, scene.headlights_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
std::vector<std::unique_ptr<VkDescriptorImageInfo>> images;
|
||||
@@ -1017,6 +1028,10 @@ void vulkan14_renderer::write_pass_sets(vk14::instance_cull *Cull)
|
||||
write(handle, HEADLIGHT_SHADOW_TEX, nullptr, image(ctx.sampling.shadow, views[HEADLIGHT_SHADOW_TEX]));
|
||||
write(handle, SCENE_DEPTH_TEX, nullptr, image(ctx.sampling.clamp_nearest, views[SCENE_DEPTH_TEX]));
|
||||
write(handle, SSR_HISTORY_TEX, nullptr, image(ctx.sampling.clamp_linear, views[SSR_HISTORY_TEX]));
|
||||
write(handle, SCENE_AO_TEX, nullptr, image(ctx.sampling.clamp_nearest, views[SCENE_AO_TEX]));
|
||||
write(handle, CAB_PROBE_TEX, nullptr, image(ctx.sampling.clamp_linear, views[CAB_PROBE_TEX]));
|
||||
write(handle, CAB_PROBE_ALBEDO_TEX, nullptr, image(ctx.sampling.clamp_linear, views[CAB_PROBE_ALBEDO_TEX]));
|
||||
write(handle, CAB_PROBE_SSBO, &cabprobe, nullptr);
|
||||
}
|
||||
vkUpdateDescriptorSets(device, static_cast<std::uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
@@ -1403,7 +1418,7 @@ void vulkan14_renderer::walk_material(material_handle const Material, TSubModel
|
||||
// materials which declare texture variants provide a different texture set per model instance
|
||||
auto const &materialtextures{material.texture_variants.empty() ? material.textures : material.GetTextures(TSubModel::VariantId(Submodel))};
|
||||
auto &draw{*m_draw};
|
||||
if (draw.depthpass)
|
||||
if (draw.depthpass || draw.probepass)
|
||||
{
|
||||
// the depth of the whole scene: the programs of the depth prepass. what they can't draw (blended, materials of other programs)
|
||||
// is left to the colour pass
|
||||
@@ -1418,6 +1433,27 @@ void vulkan14_renderer::walk_material(material_handle const Material, TSubModel
|
||||
return;
|
||||
}
|
||||
auto &scene{m_context->scene};
|
||||
if (draw.probepass)
|
||||
{
|
||||
// the probe of the cab: the programs of the probe, of the same materials, the albedo from the diffuse texture (the white
|
||||
// stand-in without it), alpha tested as the depth prepass tests it
|
||||
if (prepassclass == 2)
|
||||
{
|
||||
if (materialtextures[0] == null_handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto &texture{m_context->textures->mark_as_used(materialtextures[0])};
|
||||
if ((false == texture.create()) || (m_context->images.find(texture.get_id()) == nullptr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
walk_texture(0, materialtextures[0]);
|
||||
draw.program = (prepassclass == 2 ? scene.cabprobe_alpha_program.get() : scene.cabprobe_program.get());
|
||||
draw.depthskip = (draw.program == nullptr);
|
||||
return;
|
||||
}
|
||||
if (prepassclass == 2)
|
||||
{
|
||||
// a texture which isn't there (yet) would leave the one bound before to the alpha test
|
||||
@@ -1769,7 +1805,7 @@ void vulkan14_renderer::draw_chunk(gfx::geometry_handle const &Geometry, bool co
|
||||
}
|
||||
auto const &chunk{static_cast<vk14::vulkan14_geometrybank *>(m_banks[Geometry.bank - 1])->last()};
|
||||
|
||||
if (draw.depthpass && (draw.depthskip || (topology_class(chunk.topology) != VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)))
|
||||
if ((draw.depthpass || draw.probepass) && (draw.depthskip || (topology_class(chunk.topology) != VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)))
|
||||
{
|
||||
// the depth of the scene: what the programs of the prepass don't draw, and no points or lines
|
||||
return;
|
||||
|
||||
@@ -803,6 +803,10 @@ std::string binding_preamble(bool const Raytracing)
|
||||
define("SCENE_DEPTH_TEX", SCENE_DEPTH_TEX);
|
||||
define("SSR_HISTORY_TEX", SSR_HISTORY_TEX);
|
||||
define("WATER_SSBO", WATER_SSBO);
|
||||
define("SCENE_AO_TEX", SCENE_AO_TEX);
|
||||
define("CAB_PROBE_TEX", CAB_PROBE_TEX);
|
||||
define("CAB_PROBE_ALBEDO_TEX", CAB_PROBE_ALBEDO_TEX);
|
||||
define("CAB_PROBE_SSBO", CAB_PROBE_SSBO);
|
||||
define("PASS_BINDING_COUNT", PASS_BINDING_COUNT);
|
||||
define("MATERIAL_TEXTURE_FIRST", MATERIAL_TEXTURE_FIRST);
|
||||
define("CL_CLUSTER_UBO", CL_CLUSTER_UBO);
|
||||
@@ -873,6 +877,8 @@ std::string binding_preamble(bool const Raytracing)
|
||||
define("WATER_TRAIL", gl::WATER_TRAIL);
|
||||
define("WATER_MAP", gl::WATER_MAP);
|
||||
define("WATER_GROUP_SIZE", gl::WATER_GROUP_SIZE);
|
||||
define("CAB_PROBE_SH_SIZE", static_cast<unsigned int>(gl::CAB_PROBE_SH_SIZE));
|
||||
define("CAB_PROBE_SH_GROUP_SIZE", static_cast<unsigned int>(gl::CAB_PROBE_SH_GROUP_SIZE));
|
||||
return preamble;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user