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

deferred decals (fixes #19)

parent 817a8848
......@@ -4,4 +4,5 @@ blueprint:cornell = blueprints/cornell.json
blueprint:sun = blueprints/sun.json
blueprint:cube = blueprints/cube.json
blueprint:billboard = blueprints/billboard.json
blueprint:decal = blueprints/decal.json
{
"Transform":{
},
"Decal": {
"decals": [
{
"size": {"w":1, "h":1},
"material_aid": "mat:decal_material.msf",
"clip_rect": {"x":0, "y":0, "z":1, "w":1},
"thickness": 0.2,
"color": {"a":0.25}
}
]
}
}
{
"albedo_aid": "billboard.ktx",
"normal_aid": "sponza_bricks_normal.ktx"
}
......@@ -103,6 +103,9 @@ namespace mirrage {
transform.orientation = glm::quatLookAt(glm::vec3{-1, 0, 0}, glm::vec3{0, 1, 0});
});
auto decal = _meta_system.entities().emplace("decal");
decal.get<Transform_comp>().process([](auto& transform) { transform.position = {-8, 0, -0.5f}; });
_sun = _meta_system.entities().emplace("sun");
_set_preset(1);
......
......@@ -35,7 +35,8 @@ namespace mirrage::graphic {
Queue_tag default_draw_queue,
Queue_family_mapping queue_mapping,
Swapchain_create_infos,
bool dedicated_alloc_supported);
bool dedicated_alloc_supported,
const vk::PhysicalDeviceFeatures& features);
~Device();
auto get_queue(Queue_tag) -> vk::Queue;
......@@ -111,6 +112,7 @@ namespace mirrage::graphic {
auto physical_device() const noexcept { return _gpu; }
auto physical_device_properties() const noexcept { return _gpu_properties; }
auto physical_device_features() const noexcept { return _features; }
auto transfer() -> auto& { return _transfer_manager; }
......@@ -156,6 +158,7 @@ namespace mirrage::graphic {
vk::UniqueDevice _device;
vk::PhysicalDevice _gpu;
vk::PhysicalDeviceFeatures _features;
asset::Asset_manager& _assets;
vk::PhysicalDeviceProperties _gpu_properties;
std::unordered_map<std::string, Swapchain> _swapchains;
......
......@@ -673,7 +673,8 @@ namespace mirrage::graphic {
draw_queue_tag.get_or_throw("No draw or compute queue! That doesn't seem right."),
std::move(queue_mapping),
std::move(swapchains),
dedicated_alloc_supported);
dedicated_alloc_supported,
create_info.features);
}
void Context::vkCmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer,
......
......@@ -46,18 +46,28 @@ namespace mirrage::graphic {
}
};
Device::Device(Context& context,
asset::Asset_manager& assets,
vk::UniqueDevice device,
vk::PhysicalDevice gpu,
Queue_tag transfer_queue,
Queue_tag default_draw_queue,
Queue_family_mapping queue_mapping,
Swapchain_create_infos swapchains,
bool dedicated_alloc_supported)
namespace {
const auto default_image_usage =
vk::FormatFeatureFlagBits::eBlitDst | vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear
| vk::FormatFeatureFlagBits::eColorAttachmentBlend
| vk::FormatFeatureFlagBits::eColorAttachment | vk::FormatFeatureFlagBits::eTransferSrc
| vk::FormatFeatureFlagBits::eTransferDst | vk::FormatFeatureFlagBits::eSampledImage;
}
Device::Device(Context& context,
asset::Asset_manager& assets,
vk::UniqueDevice device,
vk::PhysicalDevice gpu,
Queue_tag transfer_queue,
Queue_tag default_draw_queue,
Queue_family_mapping queue_mapping,
Swapchain_create_infos swapchains,
bool dedicated_alloc_supported,
const vk::PhysicalDeviceFeatures& features)
: util::Registered<Device, Context>(context)
, _device(std::move(device))
, _gpu(gpu)
, _features(features)
, _assets(assets)
, _gpu_properties(gpu.getProperties())
, _pipeline_cache(load_main_pipeline_cache(*this, assets))
......@@ -82,47 +92,23 @@ namespace mirrage::graphic {
.get_or_throw("No depth-stencil format "
"supported by device"))
, _r_format(get_supported_format({vk::Format::eR8Unorm},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _rg_format(get_supported_format({vk::Format::eR8G8Unorm},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _rgb_format(get_supported_format({vk::Format::eR8G8B8Unorm},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _rgba_format(get_supported_format({vk::Format::eR8G8B8A8Unorm},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _sr_format(get_supported_format({vk::Format::eR8Srgb},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _srg_format(get_supported_format({vk::Format::eR8G8Srgb},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _srgb_format(get_supported_format({vk::Format::eR8G8B8Srgb},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _srgba_format(get_supported_format({vk::Format::eR8G8B8A8Srgb},
vk::FormatFeatureFlagBits::eBlitDst
| vk::FormatFeatureFlagBits::eBlitSrc
| vk::FormatFeatureFlagBits::eSampledImageFilterLinear,
Format_usage::image_optimal))
, _r_format(get_supported_format(
{vk::Format::eR8Unorm}, default_image_usage, Format_usage::image_optimal))
, _rg_format(get_supported_format(
{vk::Format::eR8G8Unorm}, default_image_usage, Format_usage::image_optimal))
, _rgb_format(get_supported_format(
{vk::Format::eR8G8B8Unorm}, default_image_usage, Format_usage::image_optimal))
, _rgba_format(get_supported_format(
{vk::Format::eR8G8B8A8Unorm}, default_image_usage, Format_usage::image_optimal))
, _sr_format(
get_supported_format({vk::Format::eR8Srgb}, default_image_usage, Format_usage::image_optimal))
, _srg_format(get_supported_format(
{vk::Format::eR8G8Srgb}, default_image_usage, Format_usage::image_optimal))
, _srgb_format(get_supported_format(
{vk::Format::eR8G8B8Srgb}, default_image_usage, Format_usage::image_optimal))
, _srgba_format(get_supported_format(
{vk::Format::eR8G8B8A8Srgb}, default_image_usage, Format_usage::image_optimal))
, _device_specific_asset_loaders(std::make_unique<Asset_loaders>(assets, *this, default_draw_queue))
{
......
......@@ -129,10 +129,10 @@ namespace mirrage::graphic {
const auto default_viewport = vk::Viewport{};
const auto default_viewport_state = vk::PipelineViewportStateCreateInfo{
vk::PipelineViewportStateCreateFlags{}, 1, nullptr, 1, nullptr};
const vk::DynamicState default_dynamic_states[]{vk::DynamicState::eScissor,
vk::DynamicState::eViewport};
const auto default_dynamic_state = vk::PipelineDynamicStateCreateInfo{
vk::PipelineDynamicStateCreateFlags{}, 2, default_dynamic_states};
const vk::DynamicState default_dynamic_states[]{
vk::DynamicState::eScissor, vk::DynamicState::eViewport, vk::DynamicState::eBlendConstants};
const auto default_dynamic_state = vk::PipelineDynamicStateCreateInfo{
vk::PipelineDynamicStateCreateFlags{}, 3, default_dynamic_states};
} // namespace
void Pipeline_description::build_create_info(const vk::Device& device,
vk::GraphicsPipelineCreateInfo& cinfo,
......
......@@ -63,6 +63,7 @@ add_library(mirrage_renderer STATIC
src/billboard.cpp
src/camera_comp.cpp
src/debug_ui.hpp
src/decal.cpp
src/deferred_renderer.cpp
src/gbuffer.cpp
src/light_comp.cpp
......
......@@ -10,6 +10,9 @@ frag_shader:blit = shader/blit.frag.spv
vert_shader:debug_draw = shader/debug_draw.vert.spv
frag_shader:debug_draw = shader/debug_draw.frag.spv
vert_shader:decal = shader/decal.vert.spv
frag_shader:decal = shader/decal.frag.spv
vert_shader:depth_of_field = shader/fullscreen.vert.spv
frag_shader:depth_of_field_apply = shader/depth_of_field_apply.frag.spv
frag_shader:depth_of_field_coc = shader/depth_of_field_coc.frag.spv
......
......@@ -65,7 +65,7 @@ namespace mirrage::renderer {
glm::vec4 clip_rect;
glm::vec4 color;
glm::vec4 emissive_color;
glm::vec4 placeholder[2];
glm::vec4 placeholder[3];
};
extern auto construct_push_constants(const Billboard&, const glm::mat4& view, const glm::vec4& viewport)
-> Billboard_push_constants;
......
#pragma once
#include <mirrage/renderer/model.hpp>
#include <mirrage/ecs/component.hpp>
#include <mirrage/utils/sf2_glm.hpp>
#include <mirrage/utils/small_vector.hpp>
namespace mirrage::renderer {
struct Decal_data {
glm::vec3 offset{0, 0, 0};
glm::quat rotation{0.707f, -0.707f, 0.f, 0.f};
glm::vec2 size{1, 1};
glm::vec4 clip_rect{0, 0, 1, 1}; // x,y,w,h
util::Rgba color{1, 1, 1, 1};
util::Rgba emissive_color{1, 1, 1, 1000};
float normal_alpha = 1.f;
float roughness_alpha = 1.f;
float metallic_alpha = 1.f;
float thickness = 0.1f;
bool active = true;
std::string material_aid;
};
#ifdef sf2_structDef
sf2_structDef(Decal_data,
offset,
rotation,
size,
clip_rect,
color,
emissive_color,
normal_alpha,
roughness_alpha,
metallic_alpha,
thickness,
active,
material_aid);
#endif
struct Decal : Decal_data {
Material_ptr material;
Decal() = default;
Decal(Decal_data&& data, Material_ptr m) : Decal_data(std::move(data)), material(std::move(m)) {}
};
class Decal_comp : public ecs::Component<Decal_comp> {
public:
static constexpr const char* name() { return "Decal"; }
friend void load_component(ecs::Deserializer& state, Decal_comp&);
friend void save_component(ecs::Serializer& state, const Decal_comp&);
using Component::Component;
util::small_vector<Decal, 1> decals;
};
struct Decal_push_constants {
glm::mat4 model_view; // + packed clip_rect (vec4) and color (vec4)
glm::mat4 model_view_inv; // + emissive_color
};
extern auto construct_push_constants(const Decal&, const glm::mat4& model) -> Decal_push_constants;
} // namespace mirrage::renderer
namespace mirrage::asset {
template <>
struct Loader<renderer::Decal> {
public:
static auto load(istream in) -> async::task<renderer::Decal>;
void save(ostream, const renderer::Decal&) { MIRRAGE_FAIL("Save of decals is not supported!"); }
};
} // namespace mirrage::asset
......@@ -41,13 +41,19 @@ namespace mirrage::renderer {
graphic::Texture_ptr normal,
graphic::Texture_ptr brdf,
graphic::Texture_ptr emission,
bool emissive,
bool has_albedo,
bool has_normal,
bool has_brdf,
bool has_emission,
util::Str_id substance_id);
void bind(graphic::Render_pass& pass) const;
auto substance_id() const noexcept { return _substance_id; }
auto emissive() const noexcept { return _emissive; }
auto has_albedo() const noexcept { return _has_albedo; }
auto has_normal() const noexcept { return _has_normal; }
auto has_brdf() const noexcept { return _has_brdf; }
auto has_emission() const noexcept { return _has_emission; }
private:
graphic::DescriptorSet _descriptor_set;
......@@ -55,8 +61,11 @@ namespace mirrage::renderer {
graphic::Texture_ptr _normal;
graphic::Texture_ptr _brdf;
graphic::Texture_ptr _emission;
bool _emissive;
util::Str_id _substance_id;
bool _has_albedo;
bool _has_normal;
bool _has_brdf;
bool _has_emission;
};
using Material_ptr = asset::Ptr<Material>;
......
......@@ -32,6 +32,9 @@ namespace mirrage::renderer {
void configure_billboard_pipeline(Deferred_renderer&, graphic::Pipeline_description&);
void configure_billboard_subpass(Deferred_renderer&, graphic::Subpass_builder&);
void configure_decal_pipeline(Deferred_renderer&, graphic::Pipeline_description&);
void configure_decal_subpass(Deferred_renderer&, graphic::Subpass_builder&);
void update(util::Time dt);
void pre_draw(Frame_data&);
void draw(Frame_data&, graphic::Render_pass&);
......@@ -42,5 +45,8 @@ namespace mirrage::renderer {
util::iter_range<std::vector<Geometry>::iterator> _geometry_range;
util::iter_range<std::vector<Geometry>::iterator> _rigged_geometry_range;
vk::UniqueDescriptorSetLayout _decal_input_attachment_descriptor_set_layout;
graphic::DescriptorSet _decal_input_attachment_descriptor_set;
};
} // namespace mirrage::renderer
......@@ -15,6 +15,7 @@ namespace mirrage::renderer {
glm::vec4 light_color; //< for light-subpass; A=intensity
glm::vec4 light_data; //< for light-subpass; R=src_radius, GBA=direction
glm::vec4 light_data2; //< for light-subpass; R=shadowmapID
glm::vec4 placeholder;
};
static_assert(sizeof(Deferred_push_constants) <= 4096, "Too large for push constants!");
......
#pragma once
#include <mirrage/renderer/billboard.hpp>
#include <mirrage/renderer/decal.hpp>
#include <mirrage/ecs/entity_handle.hpp>
#include <mirrage/utils/maybe.hpp>
......@@ -117,10 +118,11 @@ namespace mirrage::renderer {
vk::DescriptorSet global_uniform_set;
std::size_t swapchain_image;
std::vector<Geometry> geometry_queue;
std::vector<Light> light_queue;
std::vector<Debug_geometry> debug_geometry_queue;
std::vector<Billboard> billboard_queue;
std::vector<Geometry> geometry_queue;
std::vector<Light> light_queue;
std::vector<Debug_geometry> debug_geometry_queue;
std::vector<Billboard> billboard_queue;
std::vector<std::tuple<Decal, glm::mat4>> decal_queue;
auto partition_geometry(std::uint32_t mask) -> util::vector_range<Geometry>;
};
......
......@@ -54,7 +54,7 @@ void main() {
albedo_mat_id_out = vec4(albedo.rgb, 0.0);
mat_data_out = vec4(encode_normal(N), roughness, metallic);
color_out = vec4(albedo.rgb * model_uniforms.emissive_color.rgb
* emissive_power * model_uniforms.emissive_color.a * albedo.a, 0.0);
* emissive_power * model_uniforms.emissive_color.a * albedo.a, 1.0);
color_diffuse_out = color_out;
}
......
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#include "global_uniforms.glsl"
#include "normal_encoding.glsl"
layout(location = 0) in vec3 view_pos;
layout(location = 1) in vec4 ndc_pos;
layout(location = 0) out vec4 albedo_mat_id_out;
layout(location = 1) out vec4 mat_data_out;
layout(location = 2) out vec4 color_out;
layout(location = 3) out vec4 color_diffuse_out;
layout(set=1, binding = 0) uniform sampler2D albedo_sampler;
layout(set=1, binding = 1) uniform sampler2D normal_sampler;
layout(set=1, binding = 2) uniform sampler2D brdf_sampler;
layout(set=1, binding = 3) uniform sampler2D emission_sampler;
layout(input_attachment_index = 0, set=2, binding = 0) uniform subpassInput depth_sampler;
layout(push_constant) uniform Per_model_uniforms {
mat4 model_to_view;
mat4 view_to_model;
} model_uniforms;
const float PI = 3.14159265359;
vec3 decode_tangent_normal(vec2 tn);
vec3 tangent_space_to_world(vec3 N, vec3 p_dx, vec3 p_dy, vec2 tc_dx, vec2 tc_dy);
void main() {
vec2 screen_tex_coords = ndc_pos.xy/ndc_pos.w /2.0 +0.5;
vec4 clip_rect = vec4(unpackSnorm2x16(floatBitsToUint(model_uniforms.model_to_view[0][3])),
unpackSnorm2x16(floatBitsToUint(model_uniforms.model_to_view[1][3])))*10.0;
vec4 color = vec4(unpackUnorm2x16(floatBitsToUint(model_uniforms.model_to_view[2][3])),
unpackUnorm2x16(floatBitsToUint(model_uniforms.model_to_view[3][3])));
vec4 emissive_color = vec4(model_uniforms.view_to_model[0][3], model_uniforms.view_to_model[1][3],
model_uniforms.view_to_model[2][3], model_uniforms.view_to_model[3][3]);
mat4 view_to_model = model_uniforms.view_to_model;
view_to_model[0][3] = 0;
view_to_model[1][3] = 0;
view_to_model[2][3] = 0;
view_to_model[3][3] = 1;
float depth = subpassLoad(depth_sampler).r;
vec3 position = position_from_ldepth(screen_tex_coords, depth);
vec4 decal_pos = view_to_model * vec4(position, 1.0);
decal_pos /= decal_pos.w;
decal_pos.xyz += 0.5;
vec2 tex_coords = clip_rect.xy + decal_pos.xy*clip_rect.zw;
tex_coords.y = 1.0-tex_coords.y;
vec3 p_dx = dFdx(position);
vec3 p_dy = dFdy(position);
vec2 tc_dx = dFdx(tex_coords);
vec2 tc_dy = dFdy(tex_coords);
if(decal_pos.x<0 || decal_pos.y<0 || decal_pos.z<0 || decal_pos.x>1 || decal_pos.y>1 || decal_pos.z>1) {
discard;
}
vec4 albedo = texture(albedo_sampler, tex_coords);
if(albedo.a<0.05)
discard;
albedo *= color;
albedo.rgb *= albedo.a;
vec3 N = tangent_space_to_world(decode_tangent_normal(texture(normal_sampler, tex_coords).rg), p_dx, p_dy, tc_dx, tc_dy);
vec4 brdf = texture(brdf_sampler, tex_coords);
float roughness = brdf.r;
float metallic = brdf.g;
roughness = mix(0.01, 0.99, roughness*roughness);
float emissive_power = texture(emission_sampler, tex_coords).r;
albedo_mat_id_out = albedo;
mat_data_out = vec4(encode_normal(N), roughness, metallic);
color_out = vec4(albedo.rgb * emissive_color.rgb
* emissive_power * emissive_color.a, albedo.a);
color_diffuse_out = color_out;
}
vec3 decode_tangent_normal(vec2 tn) {
if(dot(tn,tn)<0.00001)
return vec3(0,0,1);
vec3 N = vec3(tn*2-1, 0);
N.z = sqrt(1 - dot(N.xy, N.xy));
return N;
}
vec3 tangent_space_to_world(vec3 N, vec3 p_dx, vec3 p_dy, vec2 tc_dx, vec2 tc_dy) {
// calculate tangent
vec3 VN = -normalize(cross(p_dx, p_dy));
vec3 p_dy_N = cross(p_dy, VN);
vec3 p_dx_N = cross(VN, p_dx);
vec3 T = p_dy_N * tc_dx.x + p_dx_N * tc_dy.x;
vec3 B = p_dy_N * tc_dx.y + p_dx_N * tc_dy.y;
float inv_max = inversesqrt(max(dot(T,T), dot(B,B)));
mat3 TBN = mat3(T*inv_max, B*inv_max, VN);
return normalize(TBN * N);
}
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#include "global_uniforms.glsl"
layout(location = 0) out vec3 out_view_pos;
layout(location = 1) out vec4 out_ndc_pos;
layout(push_constant) uniform Per_model_uniforms {
mat4 model_to_view;
mat4 view_to_model;
} model_uniforms;
out gl_PerVertex {
vec4 gl_Position;
};
const vec3 vertex_positions[14] = vec3[](
vec3(-1.f, 1.f, 1.f),
vec3(1.f, 1.f, 1.f),
vec3(-1.f, -1.f, 1.f),
vec3(1.f, -1.f, 1.f),
vec3(1.f, -1.f, -1.f),
vec3(1.f, 1.f, 1.f),
vec3(1.f, 1.f, -1.f),
vec3(-1.f, 1.f, 1.f),
vec3(-1.f, 1.f, -1.f),
vec3(-1.f, -1.f, 1.f),
vec3(-1.f, -1.f, -1.f),
vec3(1.f, -1.f, -1.f),
vec3(-1.f, 1.f, -1.f),
vec3(1.f, 1.f, -1.f)
);
void main() {
vec3 p = vertex_positions[gl_VertexIndex];
mat4 model_to_view = model_uniforms.model_to_view;
model_to_view[0][3] = 0;
model_to_view[1][3] = 0;
model_to_view[2][3] = 0;
model_to_view[3][3] = 1;
vec4 view_pos = model_to_view * vec4(p*0.5, 1.0);
out_view_pos = view_pos.xyz / view_pos.w;
vec4 ndc_pos = global_uniforms.proj_mat * view_pos;
gl_Position = ndc_pos;
out_ndc_pos = ndc_pos;
}
#include <mirrage/renderer/decal.hpp>
#include <glm/gtc/packing.hpp>