-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshadow_manager.cpp
More file actions
179 lines (150 loc) · 7.21 KB
/
shadow_manager.cpp
File metadata and controls
179 lines (150 loc) · 7.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "shadow_manager.h"
ShadowManager::ShadowManager(
const std::string& shadow_shader_path,
const std::string& culling_shader_path,
otcv::Image* shadowmap,
const SceneGraph& scene,
const SceneGraphFlatRefs& scene_refs,
std::shared_ptr<BindlessDataManager> bindless_data,
uint32_t in_flight_frames) {
_shadowmap = shadowmap;
std::map<uint32_t, uint32_t> vs_indexing_limits = {
{otcv::pack(DescriptorSetRate::PerObject, 0), scene_refs.size()}
};
std::map<std::string, otcv::ShaderLoadHint> file_hints = {
{"cascaded_shadow.vert", {otcv::ShaderLoadHint::Hint::DescriptorIndexing, &vs_indexing_limits}}
};
_shader_blob = std::move(otcv::load_shaders_from_dir(shadow_shader_path, file_hints));
{
otcv::GraphicsPipelineBuilder pipeline_builder;
pipeline_builder.pipline_rendering()
.depth_stencil_attachment_format(shadowmap->builder._image_info.format)
.end()
.shader_vertex(_shader_blob["cascaded_shadow.vert"])
.cull_back_face(VK_FRONT_FACE_CLOCKWISE)
.depth_test();
{
otcv::VertexBufferBuilder vbb;
vbb.add_binding().add_attribute(0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(glm::vec3));
pipeline_builder.vertex_state(vbb); // bind position attribute only
}
pipeline_builder
.add_dynamic_state(VK_DYNAMIC_STATE_VIEWPORT)
.add_dynamic_state(VK_DYNAMIC_STATE_SCISSOR);
_pipeline_bins[PipelineVariant::BackFaceCulled] = pipeline_builder.build();
}
{
otcv::GraphicsPipelineBuilder pipeline_builder;
pipeline_builder.pipline_rendering()
.depth_stencil_attachment_format(shadowmap->builder._image_info.format)
.end()
.shader_vertex(_shader_blob["cascaded_shadow.vert"])
.depth_test();
{
otcv::VertexBufferBuilder vbb;
vbb.add_binding().add_attribute(0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(glm::vec3));
pipeline_builder.vertex_state(vbb); // bind position attribute only
}
pipeline_builder
.add_dynamic_state(VK_DYNAMIC_STATE_VIEWPORT)
.add_dynamic_state(VK_DYNAMIC_STATE_SCISSOR);
_pipeline_bins[PipelineVariant::DoubleSided] = pipeline_builder.build();
}
_desc_pool.reset(new NaiveExpandableDescriptorPool());
_frame_ctxs.resize(in_flight_frames);
uint32_t n_cascades = shadowmap->builder._image_info.arrayLayers;
for (FrameContext& frame : _frame_ctxs) {
frame.resize(n_cascades); // number of cascades
for (CascadeContext& cascade : frame) {
cascade.desc_set = _desc_pool->allocate(_pipeline_bins.begin()->second->desc_set_layouts[DescriptorSetRate::PerFrame]);
Std140AlignmentType FrameUBO;
FrameUBO.add(Std140AlignmentType::InlineType::Mat4, "projectView");
cascade.ubo.reset(new StaticUBO(FrameUBO));
cascade.desc_set->bind_buffer(0, cascade.ubo->_buf);
// cascade.cascade_splits = { 0.0f, 0.0f };
}
}
_bindless_data = bindless_data;
_scene_cullings.resize(n_cascades);
_culling_out.resize(n_cascades);
for (uint32_t i = 0; i < n_cascades; ++i) {
_scene_cullings[i].reset(new SceneCulling(culling_shader_path, scene, scene_refs, in_flight_frames));
_culling_out[i] = _scene_cullings[i]->create_indirect_command_context((uint32_t)PipelineVariant::All, _bindless_data);
}
_culling_in = _scene_cullings[0]->create_object_buffer_context(scene, scene_refs, _bindless_data);
_n_obj = scene_refs.size();
}
ShadowManager::~ShadowManager() {
}
std::vector<CSM::CascadeContext> ShadowManager::update(glm::vec3 light_dir, PerspectiveCamera& camera, uint32_t frame_id, float blend_overlap) {
std::vector<CSM::CascadeContext> cascade_ctxs = CSM::csm_ortho_projections(
camera,
light_dir,
_shadowmap->builder._image_info.arrayLayers,
_shadowmap->builder._image_info.extent.width,
blend_overlap);
assert(cascade_ctxs.size() == _shadowmap->builder._image_info.arrayLayers);
StaticUBOAccess acc;
acc["projectView"];
FrameContext& frame_ctx = _frame_ctxs[frame_id];
for (uint32_t cascade = 0; cascade < frame_ctx.size(); ++cascade) {
// traverse and update cascades
glm::mat4 light_pv = cascade_ctxs[cascade].light_proj * cascade_ctxs[cascade].light_view;
frame_ctx[cascade].ubo->set(acc, &(light_pv));
// update culling
_scene_cullings[cascade]->update(cascade_ctxs[cascade].light_proj, cascade_ctxs[cascade].light_view, frame_id);
}
return cascade_ctxs;
}
void ShadowManager::commands(otcv::CommandBuffer* cmd_buf, uint32_t frame_id) {
// TODO: ensure an _shadowmap image is already transitioned to ResourceState::DepthStencilAttachment state
uint32_t width = _shadowmap->builder._image_info.extent.width;
uint32_t height = _shadowmap->builder._image_info.extent.height;
for (uint32_t cascade = 0; cascade < _shadowmap->builder._image_info.arrayLayers; ++cascade) {
// cull frustum
_scene_cullings[cascade]->commands(cmd_buf, _culling_in, _culling_out[cascade], frame_id);
VkImageSubresourceRange subrange{};
subrange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
subrange.baseMipLevel = 0;
subrange.levelCount = 1;
subrange.baseArrayLayer = cascade;
subrange.layerCount = 1;
otcv::RenderingBegin pass_begin;
pass_begin
.area(width, height)
.depth_stencil_attachment()
.image_view(_shadowmap->view_of_subresource(subrange))
.image_layout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
.load_store(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE)
.clear_value(1.0f, 0)
.end();
cmd_buf->cmd_begin_rendering(pass_begin);
cmd_buf->cmd_set_viewport(width, height);
cmd_buf->cmd_set_scissor(width, height);
cmd_buf->cmd_bind_vertex_buffer(_bindless_data->_vb);
cmd_buf->cmd_bind_index_buffer(_bindless_data->_ib, VK_INDEX_TYPE_UINT16);
// TODO: issuing a draw call for each pipeline variant is not really necessary
// as shadow pipeline do not differentiate materials
// this can be solve by writing another version of frustum_cull.comp shader that puts all indirect commands in one place
for (uint32_t pipeline_variant = 0; pipeline_variant < (uint32_t)PipelineVariant::All; ++pipeline_variant) {
assert(_pipeline_bins.find((PipelineVariant)pipeline_variant) != _pipeline_bins.end());
otcv::GraphicsPipeline* pipeline = _pipeline_bins[(PipelineVariant)pipeline_variant];
cmd_buf->cmd_bind_graphics_pipeline(pipeline);
cmd_buf->cmd_bind_descriptor_set(pipeline, _frame_ctxs[frame_id][cascade].desc_set, DescriptorSetRate::PerFrame);
cmd_buf->cmd_bind_descriptor_set(pipeline, _bindless_data->_bindless_object_desc_set, DescriptorSetRate::PerObject);
Std430AlignmentType::Range command_range = _culling_out[cascade].ssbo_commands->range_of(pipeline_variant * _n_obj, SSBOAccess());
Std430AlignmentType::Range count_range = _culling_out[cascade].ssbo_draw_count->range_of(pipeline_variant, SSBOAccess());
cmd_buf->cmd_draw_indexed_indirect_count(
_culling_out[cascade].ssbo_commands->_buf,
command_range.offset,
_culling_out[cascade].ssbo_draw_count->_buf,
count_range.offset,
_n_obj,
command_range.stride);
}
cmd_buf->cmd_end_rendering();
cmd_buf->cmd_buffer_memory_barrier(_culling_out[cascade].ssbo_commands->_buf, otcv::ResourceState::IndirectRead, otcv::ResourceState::ComputeSSBOWrite);
cmd_buf->cmd_buffer_memory_barrier(_culling_out[cascade].ssbo_draw_count->_buf, otcv::ResourceState::IndirectRead, otcv::ResourceState::ComputeSSBOWrite);
}
cmd_buf->cmd_image_memory_barrier(_shadowmap, otcv::ResourceState::DepthStencilAttachment, otcv::ResourceState::FragSample);
}