adding post processing

This commit is contained in:
2025-05-31 18:03:36 +02:00
parent 88fead6cfc
commit 4319c4096b
18 changed files with 244 additions and 11 deletions

View File

@@ -78,7 +78,7 @@ void Chunk::GenerateMesh()
std::vector<std::uint32_t>& index_data = (is_water ? m_water_mesh_index_data : m_mesh_index_data);
std::uint32_t& offset = (is_water ? water_offset : mesh_offset);
Scop::Vec4f color = is_water ? Scop::Vec4f{ 1.0f, 1.0f, 1.0f, 0.8f } : Scop::Vec4f{ 1.0f };
Scop::Vec4f color = is_water ? Scop::Vec4f{ 1.0f, 1.0f, 1.0f, 0.9f } : Scop::Vec4f{ 1.0f };
std::uint32_t invalid_limit = is_water ? static_cast<std::uint32_t>(BlockType::Air) : static_cast<std::uint32_t>(BlockType::Water);

View File

@@ -1,13 +1,8 @@
#include "Maths/Vec3.h"
#include <Noise.h>
#include <Block.h>
#include <cstdint>
#include <random>
constexpr float HEIGHT_COEFF = 255.0f;
constexpr std::uint32_t WATER_LEVEL = 20;
Noise::Noise(const std::uint32_t seed, float frequency, float amplitude, int octaves, float lacunarity, float persistance, int redistribution, float compensatory_factor): m_seed(std::mt19937(seed)), c_frequency(frequency), c_amplitude(amplitude), c_octaves(octaves), c_lacunarity(lacunarity), c_persistance(persistance), c_redistribution(redistribution), c_compensatory_factor(compensatory_factor)
{
if(c_amplitude > 1.0f || c_amplitude < -1.0f)

View File

@@ -7,7 +7,10 @@
#include <array>
#include <random>
#define NOISE_SIZE 512
constexpr float HEIGHT_COEFF = 255.0f;
constexpr std::uint32_t NOISE_SIZE = 512;
constexpr std::uint32_t WATER_LEVEL = 20;
class Noise
{
public:

View File

@@ -2,6 +2,7 @@
#include <ScopCore.h>
#include <NoiseCollection.h>
#include <World.h>
#include <Utils.h>
@@ -25,6 +26,8 @@ World::World(Scop::Scene& scene) : m_scene(scene), m_previous_chunk_position(-10
std::int32_t z_chunk = static_cast<std::int32_t>(camera->GetPosition().z) / static_cast<std::int32_t>(CHUNK_SIZE.z);
m_current_chunk_position = Scop::Vec2i{ x_chunk, z_chunk };
scene->GetPostProcessData().data.GetDataAs<std::int32_t>()[0] = scene->GetCamera()->GetPosition().y <= WATER_LEVEL;
if(input.IsKeyPressed(SDL_SCANCODE_G))
generation_debounce = true;
else if(generation_debounce)

View File

@@ -10,9 +10,13 @@ int main(int ac, char** av)
Scop::ScopEngine engine(ac, av, "Vox", 0, 0, GetExecutablePath().parent_path().parent_path() / "ScopEngine/Assets");
Scop::Scene& splash_scene = SplashScreen();
std::shared_ptr<Scop::Shader> shader = Scop::LoadShaderFromFile(GetExecutablePath().parent_path().parent_path() / "Resources/Fragment.spv", Scop::ShaderType::Fragment, Scop::DefaultShaderLayout);
std::shared_ptr<Scop::Shader> post_process_shader = Scop::LoadShaderFromFile(GetExecutablePath().parent_path().parent_path() / "Resources/PostProcess.spv", Scop::ShaderType::Fragment, Scop::PostProcessShaderLayout);
Scop::SceneDescriptor main_scene_desc;
main_scene_desc.fragment_shader = shader;
main_scene_desc.post_process_shader = post_process_shader;
main_scene_desc.post_process_data_size = sizeof(std::int32_t);
main_scene_desc.render_post_process_enabled = true;
main_scene_desc.camera = std::make_shared<Scop::FirstPerson3D>(Scop::Vec3f{ 0.0f, 20.0f, 0.0f }, 80.f);
main_scene_desc.culling = Scop::CullMode::Front;
Scop::Scene& main_scene = splash_scene.AddChildScene("main", std::move(main_scene_desc));

View File

@@ -61,6 +61,8 @@ all: $(NAME)
$(NAME): $(OBJ_DIR) $(BIN_DIR) engine $(OBJS)
@printf "$(COLOR)($(_BOLD)100%%$(_RESET)$(COLOR)) $(_RESET)Compiling $(_BOLD)Resources/Fragment.nzsl$(_RESET)\n"
@$(NZSLC) --compile=spv Resources/Fragment.nzsl -o Resources/ --optimize --module="ScopEngine/Assets/Shaders/Modules"
@printf "$(COLOR)($(_BOLD)100%%$(_RESET)$(COLOR)) $(_RESET)Compiling $(_BOLD)Resources/Screen.nzsl$(_RESET)\n"
@$(NZSLC) --compile=spv Resources/PostProcess.nzsl -o Resources/ --optimize --module="ScopEngine/Assets/Shaders/Modules"
@printf "Linking $(_BOLD)$(NAME)$(_RESET)\n"
@$(CXX) -o $(BIN_DIR)/$(NAME) $(OBJS) $(LDFLAGS)
@printf "$(_BOLD)$(NAME)$(_RESET) compiled $(COLOR)$(_BOLD)successfully$(_RESET)\n"

59
Resources/PostProcess.nzsl git.filemode.normal_file
View File

@@ -0,0 +1,59 @@
[nzsl_version("1.0")]
module;
struct VertOut
{
[location(0)] uv: vec2[f32]
}
struct FragOut
{
[location(0)] color: vec4[f32]
}
[layout(std140)]
struct Data
{
underwater: i32,
}
external
{
[set(0), binding(0)] u_texture: sampler2D[f32],
[set(0), binding(1)] u_depth: sampler2D[f32],
[set(0), binding(2)] u_data: uniform[Data],
}
fn Mixf32(a: f32, b: f32, t: f32) -> f32
{
return a + (b - a) * t;
}
fn MixVec4f32(a: vec4[f32], b: vec4[f32], t: f32) -> vec4[f32]
{
return vec4[f32](
Mixf32(a.x, b.x, t),
Mixf32(a.y, b.y, t),
Mixf32(a.z, b.z, t),
Mixf32(a.w, b.w, t)
);
}
[entry(frag)]
fn main(input: VertOut) -> FragOut
{
const fog_near: f32 = 0.9;
const fog_far: f32 = 1.0;
const fog_color: vec4[f32] = vec4[f32](0.0, 0.0, 0.25, 1.0);
let output: FragOut;
output.color = u_texture.Sample(input.uv);
if(u_data.underwater != 0)
{
let depth: f32 = u_depth.Sample(input.uv).r;
let fog_factor: f32 = (fog_far - depth) / (fog_far - fog_near);
fog_factor = clamp(fog_factor, 0.0, 1.0);
output.color = MixVec4f32(fog_color, output.color, fog_factor);
}
return output;
}

View File

@@ -4,7 +4,6 @@
#include <memory>
#include <string>
#include <string_view>
#include <map>
#include <Utils/NonOwningPtr.h>
@@ -24,11 +23,14 @@ namespace Scop
struct SceneDescriptor
{
std::shared_ptr<Shader> fragment_shader;
std::shared_ptr<Shader> post_process_shader = nullptr;
std::shared_ptr<BaseCamera> camera;
CullMode culling;
std::size_t post_process_data_size = 0;
bool render_3D_enabled = true;
bool render_2D_enabled = true;
bool render_skybox_enabled = true;
bool render_post_process_enabled = false;
};
class Scene
@@ -44,6 +46,13 @@ namespace Scop
bool wireframe = false;
};
struct PostProcessData
{
std::shared_ptr<DescriptorSet> set;
std::shared_ptr<UniformBuffer> data_buffer;
CPUBuffer data;
};
public:
Scene(std::string_view name, SceneDescriptor desc);
Scene(std::string_view name, SceneDescriptor desc, NonOwningPtr<Scene> parent);
@@ -67,6 +76,7 @@ namespace Scop
void SwitchToParent() const noexcept;
[[nodiscard]] inline ForwardData& GetForwardData() noexcept { return m_forward; }
[[nodiscard]] inline PostProcessData& GetPostProcessData() noexcept { return m_post_process; }
[[nodiscard]] inline const std::unordered_map<std::uint64_t, Actor>& GetActors() const noexcept { return m_actors; }
[[nodiscard]] inline const std::unordered_map<std::uint64_t, Sprite>& GetSprites() const noexcept { return m_sprites; }
[[nodiscard]] inline const std::string& GetName() const noexcept { return m_name; }
@@ -88,6 +98,7 @@ namespace Scop
private:
GraphicPipeline m_pipeline;
ForwardData m_forward;
PostProcessData m_post_process;
DepthImage m_depth;
SceneDescriptor m_descriptor;
std::shared_ptr<CubeTexture> p_skybox;

View File

@@ -87,7 +87,7 @@ namespace Scop
{
std::vector<VkFormat> candidates = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT };
VkFormat format = kvfFindSupportFormatInCandidates(RenderCore::Get().GetDevice(), candidates.data(), candidates.size(), VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
Image::Init(ImageType::Depth, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, is_multisampled, std::move(name));
Image::Init(ImageType::Depth, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, is_multisampled, std::move(name));
Image::TransitionLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_DEPTH_BIT);
}

View File

@@ -85,6 +85,18 @@ namespace Scop
}
}, {}
);
static const Scop::ShaderLayout PostProcessShaderLayout(
{
{ 0,
Scop::ShaderSetLayout({
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
})
}
}, {}
);
}
#endif

View File

@@ -5,6 +5,7 @@
#include <Renderer/RenderPasses/SkyboxPass.h>
#include <Renderer/RenderPasses/ForwardPass.h>
#include <Renderer/RenderPasses/FinalPass.h>
#include <Renderer/RenderPasses/PostProcessPass.h>
#include <Renderer/RenderPasses/2DPass.h>
namespace Scop
@@ -21,6 +22,7 @@ namespace Scop
private:
SkyboxPass m_skybox;
Render2DPass m_2Dpass;
PostProcessPass m_post_process;
FinalPass m_final;
Texture m_main_render_texture;
ForwardPass m_forward;

View File

@@ -0,0 +1,28 @@
#ifndef __SCOP_POST_PROCESS_PASS__
#define __SCOP_POST_PROCESS_PASS__
#include <Renderer/Descriptor.h>
#include <Renderer/Pipelines/Shader.h>
#include <Renderer/Pipelines/Graphics.h>
namespace Scop
{
class PostProcessPass
{
public:
PostProcessPass() = default;
void Init();
void Pass(class Scene& scene, class Renderer& renderer, class Texture& render_target);
void Destroy();
[[nodiscard]] inline Texture& GetProcessTexture() noexcept { return m_render_texture; }
~PostProcessPass() = default;
private:
GraphicPipeline m_pipeline;
Texture m_render_texture;
std::shared_ptr<Shader> p_vertex_shader;
};
}
#endif

View File

@@ -26,6 +26,21 @@ namespace Scop
return buffer;
}
inline void Allocate(std::size_t size)
{
if(m_data != nullptr)
FatalError("cannot allocate an already allocated CPU buffer");
try
{
m_data = std::make_shared<std::uint8_t[]>(size);
m_size = size;
}
catch(...)
{
FatalError("memory allocation for a CPU buffer failed");
}
}
inline bool Empty() const { return m_size == 0; }
[[nodiscard]] inline std::size_t GetSize() const noexcept { return m_size; }

View File

@@ -114,6 +114,7 @@ namespace Scop
{
m_depth.Destroy();
m_depth.Init(renderer->GetSwapchain().GetSwapchainImages().back().GetWidth(), renderer->GetSwapchain().GetSwapchainImages().back().GetHeight(), false, m_name + "_depth");
m_depth.CreateSampler();
}
if(event.What() == Event::ResizeEventCode || event.What() == Event::SceneHasChangedEventCode)
@@ -121,8 +122,18 @@ namespace Scop
};
EventBus::RegisterListener({ functor, m_name + std::to_string(reinterpret_cast<std::uintptr_t>(this)) });
if(m_descriptor.post_process_shader)
{
m_post_process.set = std::make_shared<DescriptorSet>(m_descriptor.post_process_shader->GetShaderLayout().set_layouts[0].second, m_descriptor.post_process_shader->GetPipelineLayout().set_layouts[0], ShaderType::Fragment);
m_post_process.data_buffer = std::make_shared<UniformBuffer>();
m_post_process.data_buffer->Init(m_descriptor.post_process_data_size, m_name + "_post_process_data_buffer");
}
m_post_process.data.Allocate(m_descriptor.post_process_data_size);
auto vertex_shader = RenderCore::Get().GetDefaultVertexShader();
m_depth.Init(renderer->GetSwapchain().GetSwapchainImages().back().GetWidth(), renderer->GetSwapchain().GetSwapchainImages().back().GetHeight(), false, m_name + "_depth");
m_depth.CreateSampler();
m_forward.matrices_buffer = std::make_shared<UniformBuffer>();
m_forward.matrices_buffer->Init(sizeof(ViewerData), m_name + "_matrice_buffer");
@@ -160,7 +171,10 @@ namespace Scop
m_sprites.clear();
m_pipeline.Destroy();
m_descriptor.fragment_shader.reset();
m_descriptor.post_process_shader.reset();
m_forward.matrices_buffer->Destroy();
if(m_post_process.data_buffer)
m_post_process.data_buffer->Destroy();
for(auto& child : m_scene_children)
child.Destroy();
}

View File

@@ -5,6 +5,8 @@
#include <Graphics/Scene.h>
#include <Maths/Mat4.h>
#include <map>
namespace Scop
{
struct ModelData

View File

@@ -8,6 +8,7 @@ namespace Scop
{
m_skybox.Init();
m_2Dpass.Init();
m_post_process.Init();
m_final.Init();
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
@@ -36,8 +37,13 @@ namespace Scop
m_skybox.Pass(scene, renderer, m_main_render_texture);
if(scene.GetDescription().render_2D_enabled)
m_2Dpass.Pass(scene, renderer, m_main_render_texture);
m_final.Pass(scene, renderer, m_main_render_texture);
if(scene.GetDescription().render_post_process_enabled && scene.GetDescription().post_process_shader)
{
m_post_process.Pass(scene, renderer, m_main_render_texture);
m_final.Pass(scene, renderer, m_post_process.GetProcessTexture());
}
else
m_final.Pass(scene, renderer, m_main_render_texture);
}
void RenderPasses::Destroy()
@@ -45,6 +51,7 @@ namespace Scop
RenderCore::Get().WaitDeviceIdle();
m_skybox.Destroy();
m_2Dpass.Destroy();
m_post_process.Destroy();
m_final.Destroy();
m_main_render_texture.Destroy();
}

View File

@@ -0,0 +1,74 @@
#include <Renderer/RenderPasses/PostProcessPass.h>
#include <Renderer/Pipelines/Graphics.h>
#include <Renderer/Renderer.h>
#include <Graphics/Scene.h>
#include <Core/EventBus.h>
#include <Core/Engine.h>
namespace Scop
{
void PostProcessPass::Init()
{
ShaderLayout vertex_shader_layout(
{}, {}
);
p_vertex_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ScreenVertex.spv", ShaderType::Vertex, std::move(vertex_shader_layout));
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
{
if(event.What() == Event::ResizeEventCode)
{
m_render_texture.Destroy();
m_pipeline.Destroy();
}
};
EventBus::RegisterListener({ functor, "__ScopPostProcessPass" });
}
void PostProcessPass::Pass(Scene& scene, Renderer& renderer, Texture& render_target)
{
Scene::PostProcessData& data = scene.GetPostProcessData();
if(!m_render_texture.IsInit())
{
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain().Get());
m_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_UNORM, false, "scop_post_process_render_texture", true);
}
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
{
GraphicPipelineDescriptor pipeline_descriptor;
pipeline_descriptor.vertex_shader = p_vertex_shader;
pipeline_descriptor.fragment_shader = scene.GetDescription().post_process_shader;
pipeline_descriptor.color_attachments = { &m_render_texture };
pipeline_descriptor.culling = VK_CULL_MODE_NONE;
pipeline_descriptor.clear_color_attachments = false;
pipeline_descriptor.no_vertex_inputs = true;
pipeline_descriptor.name = "post_process_pass_pipeline";
m_pipeline.Init(pipeline_descriptor);
}
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
data.set->SetImage(renderer.GetCurrentFrameIndex(), 0, render_target);
data.set->SetImage(renderer.GetCurrentFrameIndex(), 1, scene.GetDepth());
data.set->SetUniformBuffer(renderer.GetCurrentFrameIndex(), 2, data.data_buffer->Get(renderer.GetCurrentFrameIndex()));
data.set->Update(renderer.GetCurrentFrameIndex(), cmd);
m_pipeline.BindPipeline(cmd, 0, {});
VkDescriptorSet set = data.set->GetSet(renderer.GetCurrentFrameIndex());
RenderCore::Get().vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, 1, &set, 0, nullptr);
RenderCore::Get().vkCmdDraw(cmd, 3, 1, 0, 0);
renderer.GetDrawCallsCounterRef()++;
renderer.GetPolygonDrawnCounterRef()++;
m_pipeline.EndPipeline(cmd);
}
void PostProcessPass::Destroy()
{
RenderCore::Get().WaitDeviceIdle();
m_render_texture.Destroy();
m_pipeline.Destroy();
p_vertex_shader.reset();
}
}

View File

@@ -29,6 +29,8 @@ namespace Scop
std::memcpy(buffer.GetData(), &data, buffer.GetSize());
scene.GetForwardData().matrices_buffer->SetData(buffer, renderer.GetCurrentFrameIndex());
}
if(scene.GetDescription().render_post_process_enabled && scene.GetDescription().post_process_shader)
scene.GetPostProcessData().data_buffer->SetData(scene.GetPostProcessData().data, renderer.GetCurrentFrameIndex());
m_passes.Pass(scene, renderer);
}