Commit e077459c authored by Florian Oetke's avatar Florian Oetke
Browse files

blue noise for dithering

parent 2857ed30
......@@ -4,6 +4,7 @@ tex:black = textures/default_black.png
tex:white = textures/default_white.ktx
tex:normal = textures/default_normal.png
tex:placeholder = textures/default_placeholder.ktx
tex:blue_noise = textures/blue_noise.ktx
tex:x_font = textures/x.template_regular_48.tga
tex:satisfy_font = textures/satisfy_regular_20.tga
......
......@@ -16,6 +16,7 @@ layout(location = 0) out vec4 out_color;
layout(set=1, binding = 0) uniform sampler2D color_sampler;
layout(set=1, binding = 1) uniform sampler2D avg_log_luminance_sampler;
layout(set=1, binding = 2) uniform sampler2D bloom_sampler;
layout(set=1, binding = 3) uniform sampler2D blue_noise;
layout(push_constant) uniform Settings {
vec4 options;
......@@ -127,7 +128,25 @@ vec3 resolve_fxaa() {
}
}
vec3 highlow_mix(vec3 color, float cutoff, vec3 low, vec3 high) {
return mix(high, low, lessThan(color, vec3(cutoff)));
}
// Based on http://momentsingraphics.de/?p=127
vec3 dither(vec3 color) {
vec3 color_srgb = highlow_mix(color, 0.0031308, 12.92*color, 1.055*pow(color, vec3(1.0/2.4))-0.055);
vec3 rand = texture(blue_noise, vertex_out.tex_coords*vec2(1920,1080)/128.0).rgb;
vec3 rand_tri = rand*2.0-1.0;
rand_tri = sign(rand_tri) * (1.0-sqrt(1.0-abs(rand_tri)));
color_srgb += rand / 253.0;
return highlow_mix(color_srgb, 0.04045, color_srgb/12.92, pow(color_srgb/1.055 + 0.055/1.055, vec3(2.4)));
}
void main() {
//out_color = vec4(tone_mapping(texture(color_sampler, vertex_out.tex_coords).rgb), 1.0);
out_color = vec4(tone_mapping(resolve_fxaa().rgb) + random(vec4(vertex_out.tex_coords,global_uniforms.time.x,0))/255.0/2.0, 1.0);
out_color = vec4(dither(tone_mapping(resolve_fxaa().rgb)), 1.0);
}
......@@ -82,7 +82,7 @@ void main() {
}
float calc_penumbra(vec3 surface_lightspace, float light_size,
float calc_penumbra(vec3 surface_lightspace, float light_size, float rand,
out int num_occluders);
float sample_shadowmap(vec3 view_pos) {
......@@ -97,8 +97,10 @@ float sample_shadowmap(vec3 view_pos) {
float shadowmap_size = textureSize(sampler2D(shadowmaps[shadowmap], shadowmap_depth_sampler), 0).x;
float light_size = model_uniforms.light_data.r / 800.0;
int num_occluders;
float penumbra_softness = calc_penumbra(lightspace_pos.xyz, light_size, num_occluders);
vec2 rand = PDnrand2(vec4(global_uniforms.time.y, vertex_out.tex_coords, lightspace_pos.x));
int num_occluders = 0;
float penumbra_softness = calc_penumbra(lightspace_pos.xyz, light_size, rand.r, num_occluders);
//return penumbra_softness>=0.5 ? 1.0 : 0.0;
......@@ -113,9 +115,12 @@ float sample_shadowmap(vec3 view_pos) {
if(SHADOW_QUALITY<=1)
samples = min(samples, 8);
if(SHADOW_QUALITY>=2)
samples = 16;
float z_bias = 0.00035;
float angle = random(vec4(lightspace_pos.xyz, global_uniforms.time.y));
float angle = rand.g;
float sin_angle = sin(angle);
float cos_angle = cos(angle);
......@@ -131,20 +136,18 @@ float sample_shadowmap(vec3 view_pos) {
vec3(p, lightspace_pos.z-z_bias)));
}
visiblity *= visiblity;
return clamp(smoothstep(0, 1, visiblity), 0.0, 1.0);
}
float calc_avg_occluder(vec3 surface_lightspace, float search_area,
float calc_avg_occluder(vec3 surface_lightspace, float search_area, float rand,
out int num_occluders) {
int shadowmap = int(model_uniforms.light_data2.r);
float depth_acc=0;
float depth_count=0;
num_occluders = 0;
float depth_acc = 0;
float depth_count = 0;
num_occluders = 0;
float angle = random(vec4(surface_lightspace, global_uniforms.time.y));
float angle = rand;
float sin_angle = sin(angle);
float cos_angle = cos(angle);
......@@ -166,8 +169,8 @@ float calc_avg_occluder(vec3 surface_lightspace, float search_area,
return depth_acc / depth_count;
}
float calc_penumbra(vec3 surface_lightspace, float light_size, out int num_occluders) {
float avg_occluder = calc_avg_occluder(surface_lightspace, light_size, num_occluders);
float calc_penumbra(vec3 surface_lightspace, float light_size, float rand, out int num_occluders) {
float avg_occluder = calc_avg_occluder(surface_lightspace, light_size, rand, num_occluders);
const float scale = 10.0;
float softness = (surface_lightspace.z - avg_occluder) * scale;
......
......@@ -4,6 +4,8 @@
// Based on http://graphics.cs.williams.edu/papers/SAOHPG12/McGuire12SAO.pdf
// Based on http://graphics.cs.williams.edu/papers/SAOHPG12/McGuire12SAO.pdf
layout(location = 0) in Vertex_data {
vec2 tex_coords;
} vertex_out;
......
......@@ -26,16 +26,17 @@ namespace mirrage {
, _renderer_factory(std::make_unique<renderer::Deferred_renderer_factory>(
graphics_context(),
window(),
util::make_vector(renderer::make_pass_factory<renderer::Shadowmapping_pass_factory>(),
renderer::make_pass_factory<renderer::Deferred_pass_factory>(),
renderer::make_pass_factory<renderer::Gen_mipmap_pass_factory>(),
renderer::make_pass_factory<renderer::Ssao_pass_factory>(),
renderer::make_pass_factory<renderer::Gi_pass_factory>(),
renderer::make_pass_factory<renderer::Taa_pass_factory>(),
renderer::make_pass_factory<renderer::Tone_mapping_pass_factory>(),
renderer::make_pass_factory<renderer::Bloom_pass_factory>(),
renderer::make_pass_factory<renderer::Blit_pass_factory>(),
renderer::make_pass_factory<renderer::Gui_pass_factory>()))) {}
util::make_vector(
renderer::make_pass_factory<renderer::Shadowmapping_pass_factory>(),
renderer::make_pass_factory<renderer::Deferred_pass_factory>(),
renderer::make_pass_factory<renderer::Gen_mipmap_pass_factory>(),
renderer::make_pass_factory<renderer::Ssao_pass_factory>(),
renderer::make_pass_factory<renderer::Gi_pass_factory>(),
renderer::make_pass_factory<renderer::Taa_pass_factory>(),
renderer::make_pass_factory<renderer::Tone_mapping_pass_factory>(),
renderer::make_pass_factory<renderer::Bloom_pass_factory>(),
renderer::make_pass_factory<renderer::Blit_pass_factory>(),
renderer::make_pass_factory<renderer::Gui_pass_factory>()))) {}
Game_engine::~Game_engine() {
screens().clear(); // destroy all screens before the engine
......
......@@ -10,20 +10,23 @@ namespace mirrage::graphic {
: _device(device), _pool(std::move(pool)) {}
Command_buffer_pool::~Command_buffer_pool() { _device.waitIdle(); }
auto Command_buffer_pool::create_primary(std::size_t count) -> std::vector<vk::UniqueCommandBuffer> {
auto Command_buffer_pool::create_primary(std::size_t count)
-> std::vector<vk::UniqueCommandBuffer> {
return _device.allocateCommandBuffersUnique(
vk::CommandBufferAllocateInfo(*_pool, vk::CommandBufferLevel::ePrimary, count));
}
auto Command_buffer_pool::create_secondary(std::size_t count) -> std::vector<vk::UniqueCommandBuffer> {
auto Command_buffer_pool::create_secondary(std::size_t count)
-> std::vector<vk::UniqueCommandBuffer> {
return _device.allocateCommandBuffersUnique(
vk::CommandBufferAllocateInfo(*_pool, vk::CommandBufferLevel::eSecondary, count));
}
auto Descriptor_pool::create_descriptor(vk::DescriptorSetLayout layout) -> vk::UniqueDescriptorSet {
return std::move(
_device.allocateDescriptorSetsUnique(vk::DescriptorSetAllocateInfo{*_pool, 1, &layout})[0]);
auto Descriptor_pool::create_descriptor(vk::DescriptorSetLayout layout)
-> vk::UniqueDescriptorSet {
return std::move(_device.allocateDescriptorSetsUnique(
vk::DescriptorSetAllocateInfo{*_pool, 1, &layout})[0]);
}
Descriptor_pool::Descriptor_pool(const vk::Device& device, vk::UniqueDescriptorPool pool)
......@@ -61,7 +64,8 @@ namespace mirrage::graphic {
std::initializer_list<vk::ImageView> images) {
MIRRAGE_INVARIANT(images.size() <= _image_number,
"Number of images (" << images.size() << ") doesn't match size of descriptor set ("
"Number of images (" << images.size()
<< ") doesn't match size of descriptor set ("
<< _image_number << ")");
auto desc_images = std::vector<vk::DescriptorImageInfo>();
......@@ -82,15 +86,19 @@ namespace mirrage::graphic {
nullptr);
}
_device.vk_device()->updateDescriptorSets(desc_writes.size(), desc_writes.data(), 0, nullptr);
_device.vk_device()->updateDescriptorSets(
desc_writes.size(), desc_writes.data(), 0, nullptr);
}
Fence::operator bool() const { return _device.getFenceStatus(*_fence) == vk::Result::eSuccess; }
void Fence::reset() { _device.resetFences({*_fence}); }
void Fence::wait() { _device.waitForFences({*_fence}, true, std::numeric_limits<std::uint64_t>::max()); }
void Fence::wait() {
_device.waitForFences({*_fence}, true, std::numeric_limits<std::uint64_t>::max());
}
Fence::Fence(const vk::Device& device) : _device(device), _fence(_device.createFenceUnique({})) {}
Fence::Fence(const vk::Device& device)
: _device(device), _fence(_device.createFenceUnique({})) {}
auto create_fence(Device& d) -> Fence { return d.create_fence(); }
......@@ -102,7 +110,8 @@ namespace mirrage::graphic {
std::vector<vk::ClearValue> cv)
: _fb(std::move(fb)), _viewport(viewport), _scissor(scissor), _clear_values(std::move(cv)) {}
void Framebuffer::viewport(float x, float y, float width, float height, float min_depth, float max_depth) {
void Framebuffer::viewport(
float x, float y, float width, float height, float min_depth, float max_depth) {
_viewport.x = x;
_viewport.y = y;
_viewport.width = width;
......@@ -129,8 +138,11 @@ namespace mirrage::graphic {
case vk::ImageLayout::eColorAttachmentOptimal:
return vk::AccessFlagBits::eColorAttachmentWrite;
case vk::ImageLayout::eDepthReadOnlyStencilAttachmentOptimalKHR:
case vk::ImageLayout::eDepthAttachmentStencilReadOnlyOptimalKHR:
case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
return vk::AccessFlagBits::eDepthStencilAttachmentRead;
return vk::AccessFlagBits::eDepthStencilAttachmentRead;
case vk::ImageLayout::eDepthStencilAttachmentOptimal:
return vk::AccessFlagBits::eDepthStencilAttachmentRead
......@@ -138,12 +150,15 @@ namespace mirrage::graphic {
case vk::ImageLayout::eTransferSrcOptimal: return vk::AccessFlagBits::eTransferRead;
case vk::ImageLayout::eTransferDstOptimal: return vk::AccessFlagBits::eTransferWrite;
case vk::ImageLayout::eTransferDstOptimal:
return vk::AccessFlagBits::eTransferWrite;
case vk::ImageLayout::eShaderReadOnlyOptimal: return vk::AccessFlagBits::eShaderRead;
case vk::ImageLayout::eShaderReadOnlyOptimal:
return vk::AccessFlagBits::eShaderRead;
case vk::ImageLayout::eSharedPresentKHR:
case vk::ImageLayout::ePresentSrcKHR: return vk::AccessFlagBits::eColorAttachmentWrite;
case vk::ImageLayout::ePresentSrcKHR:
return vk::AccessFlagBits::eColorAttachmentWrite;
}
MIRRAGE_FAIL("Unreachable");
}
......@@ -281,16 +296,19 @@ namespace mirrage::graphic {
}
auto src_range = std::array<vk::Offset3D, 2>{
vk::Offset3D{0, 0, 0}, vk::Offset3D{int32_t(src.width()), int32_t(src.height()), 1}};
vk::Offset3D{0, 0, 0},
vk::Offset3D{int32_t(src.width()), int32_t(src.height()), 1}};
auto dst_range = std::array<vk::Offset3D, 2>{
vk::Offset3D{0, 0, 0}, vk::Offset3D{int32_t(dst.width()), int32_t(dst.height()), 1}};
auto blit = vk::ImageBlit{// src
vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
src_range,
// dst
vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
dst_range};
vk::Offset3D{0, 0, 0},
vk::Offset3D{int32_t(dst.width()), int32_t(dst.height()), 1}};
auto blit =
vk::ImageBlit{// src
vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
src_range,
// dst
vk::ImageSubresourceLayers{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
dst_range};
cb.blitImage(src.image(),
vk::ImageLayout::eTransferSrcOptimal,
dst.image(),
......@@ -340,11 +358,12 @@ namespace mirrage::graphic {
initial_mip_level,
mip_levels);
cb.clearColorImage(img.image(),
vk::ImageLayout::eTransferDstOptimal,
vk::ClearColorValue{std::array<float, 4>{color.r, color.g, color.b, color.a}},
{vk::ImageSubresourceRange{
vk::ImageAspectFlagBits::eColor, initial_mip_level, mip_levels, 0, 1}});
cb.clearColorImage(
img.image(),
vk::ImageLayout::eTransferDstOptimal,
vk::ClearColorValue{std::array<float, 4>{color.r, color.g, color.b, color.a}},
{vk::ImageSubresourceRange{
vk::ImageAspectFlagBits::eColor, initial_mip_level, mip_levels, 0, 1}});
graphic::image_layout_transition(cb,
img.image(),
......
......@@ -26,6 +26,7 @@ namespace mirrage::renderer {
private:
Deferred_renderer& _renderer;
graphic::Texture_2D& _src;
graphic::Texture_ptr _blue_noise;
vk::UniqueSampler _sampler;
graphic::Image_descriptor_set_layout _descriptor_set_layout;
vk::UniqueDescriptorSet _descriptor_set;
......@@ -42,8 +43,9 @@ namespace mirrage::renderer {
util::maybe<Meta_system&>,
bool& write_first_pp_buffer) -> std::unique_ptr<Pass> override;
auto rank_device(vk::PhysicalDevice, util::maybe<std::uint32_t> graphics_queue, int current_score)
-> int override;
auto rank_device(vk::PhysicalDevice,
util::maybe<std::uint32_t> graphics_queue,
int current_score) -> int override;
void configure_device(vk::PhysicalDevice,
util::maybe<std::uint32_t> graphics_queue,
......
......@@ -9,7 +9,9 @@ namespace mirrage::renderer {
class Gi_pass : public Pass {
public:
Gi_pass(Deferred_renderer&, graphic::Render_target_2D& in_out, graphic::Render_target_2D& diffuse_in);
Gi_pass(Deferred_renderer&,
graphic::Render_target_2D& in_out,
graphic::Render_target_2D& diffuse_in);
void update(util::Time dt) override;
......@@ -110,8 +112,9 @@ namespace mirrage::renderer {
util::maybe<Meta_system&>,
bool& write_first_pp_buffer) -> std::unique_ptr<Pass> override;
auto rank_device(vk::PhysicalDevice, util::maybe<std::uint32_t> graphics_queue, int current_score)
-> int override;
auto rank_device(vk::PhysicalDevice,
util::maybe<std::uint32_t> graphics_queue,
int current_score) -> int override;
void configure_device(vk::PhysicalDevice,
util::maybe<std::uint32_t> graphics_queue,
......
......@@ -10,16 +10,16 @@ namespace mirrage::renderer {
auto builder = renderer.device().create_render_pass_builder();
auto screen =
builder.add_attachment(vk::AttachmentDescription{vk::AttachmentDescriptionFlags{},
renderer.swapchain().image_format(),
vk::SampleCountFlagBits::e1,
vk::AttachmentLoadOp::eDontCare,
vk::AttachmentStoreOp::eStore,
vk::AttachmentLoadOp::eDontCare,
vk::AttachmentStoreOp::eDontCare,
vk::ImageLayout::eUndefined,
vk::ImageLayout::ePresentSrcKHR});
auto screen = builder.add_attachment(
vk::AttachmentDescription{vk::AttachmentDescriptionFlags{},
renderer.swapchain().image_format(),
vk::SampleCountFlagBits::e1,
vk::AttachmentLoadOp::eDontCare,
vk::AttachmentStoreOp::eStore,
vk::AttachmentLoadOp::eDontCare,
vk::AttachmentStoreOp::eDontCare,
vk::ImageLayout::eUndefined,
vk::ImageLayout::ePresentSrcKHR});
auto pipeline = graphic::Pipeline_description{};
pipeline.input_assembly.topology = vk::PrimitiveTopology::eTriangleList;
......@@ -39,30 +39,31 @@ namespace mirrage::renderer {
.shader("frag_shader:blit"_aid, graphic::Shader_stage::fragment)
.shader("vert_shader:blit"_aid, graphic::Shader_stage::vertex);
builder.add_dependency(
util::nothing,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlags{},
pass,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite);
builder.add_dependency(util::nothing,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlags{},
pass,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlagBits::eColorAttachmentRead
| vk::AccessFlagBits::eColorAttachmentWrite);
builder.add_dependency(
pass,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
util::nothing,
vk::PipelineStageFlagBits::eBottomOfPipe,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eShaderRead
| vk::AccessFlagBits::eTransferRead);
builder.add_dependency(pass,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlagBits::eColorAttachmentRead
| vk::AccessFlagBits::eColorAttachmentWrite,
util::nothing,
vk::PipelineStageFlagBits::eBottomOfPipe,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eShaderRead
| vk::AccessFlagBits::eTransferRead);
auto render_pass = builder.build();
for(auto& sc_image : renderer.swapchain().get_images()) {
out_framebuffers.emplace_back(builder.build_framebuffer({*sc_image, util::Rgba{}},
renderer.swapchain().image_width(),
renderer.swapchain().image_height()));
out_framebuffers.emplace_back(
builder.build_framebuffer({*sc_image, util::Rgba{}},
renderer.swapchain().image_width(),
renderer.swapchain().image_height()));
}
return render_pass;
......@@ -76,17 +77,19 @@ namespace mirrage::renderer {
graphic::Texture_2D& src)
: _renderer(renderer)
, _src(src)
, _blue_noise(renderer.texture_cache().load("tex:blue_noise"_aid))
, _sampler(renderer.device().create_sampler(1,
vk::SamplerAddressMode::eClampToEdge,
vk::SamplerAddressMode::eRepeat,
vk::BorderColor::eIntOpaqueBlack,
vk::Filter::eLinear,
vk::SamplerMipmapMode::eNearest))
, _descriptor_set_layout(renderer.device(), *_sampler, 3)
, _descriptor_set_layout(renderer.device(), *_sampler, 4)
, _descriptor_set(_descriptor_set_layout.create_set(
renderer.descriptor_pool(),
{src.view(),
renderer.gbuffer().avg_log_luminance.get_or_other(src).view(),
renderer.gbuffer().bloom.get_or_other(src).view()}))
renderer.gbuffer().bloom.get_or_other(src).view(),
_blue_noise->view()}))
, _render_pass(build_render_pass(renderer, *_descriptor_set_layout, _framebuffers))
, _tone_mapping_enabled(renderer.gbuffer().avg_log_luminance.is_some())
, _bloom_enabled(renderer.gbuffer().bloom.is_some()) {}
......@@ -100,7 +103,8 @@ namespace mirrage::renderer {
std::size_t swapchain_image) {
_render_pass.execute(command_buffer, _framebuffers.at(swapchain_image), [&] {
auto descriptor_sets = std::array<vk::DescriptorSet, 2>{global_uniform_set, *_descriptor_set};
auto descriptor_sets =
std::array<vk::DescriptorSet, 2>{global_uniform_set, *_descriptor_set};
_render_pass.bind_descriptor_sets(0, descriptor_sets);
glm::vec4 settings;
......@@ -119,7 +123,8 @@ namespace mirrage::renderer {
ecs::Entity_manager& entities,
util::maybe<Meta_system&> meta_system,
bool& write_first_pp_buffer) -> std::unique_ptr<Pass> {
auto& color_src = !write_first_pp_buffer ? renderer.gbuffer().colorA : renderer.gbuffer().colorB;
auto& color_src =
!write_first_pp_buffer ? renderer.gbuffer().colorA : renderer.gbuffer().colorB;
return std::make_unique<Blit_pass>(renderer, entities, meta_system, color_src);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment