Implemented raster versions of bokeh shaders to replace broken gaussian implementation

This commit is contained in:
Bastiaan Olij 2021-07-29 17:43:17 +10:00
parent a98589a449
commit 07fd559478
9 changed files with 643 additions and 293 deletions

View File

@ -928,7 +928,7 @@ void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_
}
}
void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
void EffectsRD::bokeh_dof(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of BOKEH DOF with the mobile renderer.");
bokeh.push_constant.blur_far_active = p_dof_far;
@ -957,22 +957,22 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
// The alpha channel of the source color texture is filled with the expected circle size
// If used for DOF far, the size is positive, if used for near, its negative.
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BLUR_SIZE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BLUR_SIZE]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_texture), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.depth_texture), 1);
bokeh.push_constant.size[0] = p_base_texture_size.x;
bokeh.push_constant.size[1] = p_base_texture_size.y;
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
//second pass
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
static const int quality_samples[4] = { 6, 12, 12, 24 };
@ -981,18 +981,18 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
bokeh.push_constant.blur_size *= 0.5;
} else {
//medium and high quality use full size
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.secondary_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@ -1004,11 +1004,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
bokeh.push_constant.second_pass = true;
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture2), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[1]), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1);
} else {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.secondary_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@ -1019,25 +1019,25 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
//forth pass, upscale for low quality
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture2), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[1]), 1);
bokeh.push_constant.size[0] = p_base_texture_size.x;
bokeh.push_constant.size[1] = p_base_texture_size.y;
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
bokeh.push_constant.half_size = false;
bokeh.push_constant.second_pass = false;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
} else {
//circle
//second pass
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
@ -1046,11 +1046,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
//circle always runs in half size, otherwise too expensive
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@ -1062,95 +1062,197 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
// upscale
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1);
bokeh.push_constant.size[0] = p_base_texture_size.x;
bokeh.push_constant.size[1] = p_base_texture_size.y;
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
bokeh.push_constant.half_size = false;
bokeh.push_constant.second_pass = false;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
RD::get_singleton()->compute_list_end();
}
void EffectsRD::blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
void EffectsRD::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use blur DOF with the clustered renderer.");
memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
BlurRasterMode blur_mode;
int qsteps[4] = { 4, 4, 10, 20 };
uint32_t base_flags = p_cam_orthogonal ? BLUR_FLAG_USE_ORTHOGONAL_PROJECTION : 0;
bokeh.push_constant.orthogonal = p_cam_orthogonal;
bokeh.push_constant.size[0] = p_buffers.base_texture_size.width;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.height;
bokeh.push_constant.z_far = p_cam_zfar;
bokeh.push_constant.z_near = p_cam_znear;
Vector2 pixel_size = Vector2(1.0 / p_base_texture_size.width, 1.0 / p_base_texture_size.height);
blur_raster.push_constant.dof_radius = (p_dof_blur_amount * p_dof_blur_amount) / qsteps[p_quality];
blur_raster.push_constant.pixel_size[0] = pixel_size.x;
blur_raster.push_constant.pixel_size[1] = pixel_size.y;
blur_raster.push_constant.camera_z_far = p_cam_zfar;
blur_raster.push_constant.camera_z_near = p_cam_znear;
bokeh.push_constant.second_pass = false;
bokeh.push_constant.half_size = false;
bokeh.push_constant.blur_size = p_dof_blur_amount;
if (p_dof_far || p_dof_near) {
if (p_quality == RS::DOF_BLUR_QUALITY_HIGH) {
blur_mode = BLUR_MODE_DOF_HIGH;
} else if (p_quality == RS::DOF_BLUR_QUALITY_MEDIUM) {
blur_mode = BLUR_MODE_DOF_MEDIUM;
} else { // for LOW or VERYLOW we use LOW
blur_mode = BLUR_MODE_DOF_LOW;
}
if (p_dof_far) {
base_flags |= BLUR_FLAG_DOF_FAR;
blur_raster.push_constant.dof_far_begin = p_dof_far_begin;
blur_raster.push_constant.dof_far_end = p_dof_far_begin + p_dof_far_size;
bokeh.push_constant.blur_far_active = true;
bokeh.push_constant.blur_far_begin = p_dof_far_begin;
bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
}
if (p_dof_near) {
base_flags |= BLUR_FLAG_DOF_NEAR;
blur_raster.push_constant.dof_near_begin = p_dof_near_begin;
blur_raster.push_constant.dof_near_end = p_dof_near_begin - p_dof_near_size;
bokeh.push_constant.blur_near_active = true;
bokeh.push_constant.blur_near_begin = p_dof_near_begin;
bokeh.push_constant.blur_near_end = p_dof_near_begin - p_dof_near_size;
}
//HORIZONTAL
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_secondary_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_secondary_fb)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1);
{
// generate our depth data
RID framebuffer = p_buffers.base_weight_fb;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.depth_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL;
blur_raster.push_constant.dof_dir[0] = 1.0;
blur_raster.push_constant.dof_dir[1] = 0.0;
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
}
if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
// double pass approach
BokehMode mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
bokeh.push_constant.blur_size *= 0.5;
}
static const int quality_samples[4] = { 6, 12, 12, 24 };
bokeh.push_constant.blur_scale = 0.5;
bokeh.push_constant.steps = quality_samples[p_quality];
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
// Pass 1
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
//VERTICAL
draw_list = RD::get_singleton()->draw_list_begin(p_base_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_base_fb)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1);
// Pass 2
if (!bokeh.push_constant.half_size) {
// do not output weight, we're writing back into our base buffer
mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT;
}
bokeh.push_constant.second_pass = true;
framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[1] : p_buffers.base_fb;
RID texture = bokeh.push_constant.half_size ? p_buffers.half_texture[0] : p_buffers.secondary_texture;
RID weight = bokeh.push_constant.half_size ? p_buffers.weight_texture[2] : p_buffers.weight_texture[1];
draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(weight), 1);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
blur_raster.push_constant.flags = base_flags;
blur_raster.push_constant.dof_dir[0] = 0.0;
blur_raster.push_constant.dof_dir[1] = 1.0;
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
if (bokeh.push_constant.half_size) {
// Compose pass
mode = BOKEH_COMPOSITE;
framebuffer = p_buffers.base_fb;
draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[1]), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[3]), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
}
} else {
// circular is a single pass approach
BokehMode mode = BOKEH_GEN_BOKEH_CIRCULAR;
{
// circle always runs in half size, otherwise too expensive (though the code below does support making this optional)
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
// bokeh.push_constant.blur_size *= 0.5;
}
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
bokeh.push_constant.blur_scale = quality_scale[p_quality];
bokeh.push_constant.steps = 0.0;
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
if (bokeh.push_constant.half_size) {
// Compose
mode = BOKEH_COMPOSITE;
framebuffer = p_buffers.base_fb;
draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[0]), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[2]), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
} else {
// Just copy it back (we use our blur raster shader here)..
draw_list = RD::get_singleton()->draw_list_begin(p_buffers.base_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[BLUR_MODE_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_buffers.base_fb)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.secondary_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
}
}
}
}
void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) {
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
@ -1774,9 +1876,7 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); // BLUR_MODE_GAUSSIAN_BLUR
blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); // BLUR_MODE_GAUSSIAN_GLOW
blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); // BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE
blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_LOW\n"); // BLUR_MODE_DOF_LOW
blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_MEDIUM\n"); // BLUR_MODE_DOF_MEDIUM
blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_HIGH\n"); // BLUR_MODE_DOF_HIGH
blur_modes.push_back("\n#define MODE_COPY\n"); // BLUR_MODE_COPY
blur_raster.shader.initialize(blur_modes);
memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
@ -1956,23 +2056,40 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0);
}
if (prefer_raster_effects) {
// not supported
} else {
// Initialize bokeh
Vector<String> bokeh_modes;
bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n#define OUTPUT_WEIGHT\n");
bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n#define OUTPUT_WEIGHT\n");
bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n");
bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n#define OUTPUT_WEIGHT\n");
bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
if (prefer_raster_effects) {
bokeh.raster_shader.initialize(bokeh_modes);
bokeh.shader.initialize(bokeh_modes);
bokeh.shader_version = bokeh.raster_shader.version_create();
bokeh.shader_version = bokeh.shader.version_create();
const int att_count[BOKEH_MAX] = { 1, 2, 1, 2, 1, 2, 1 };
for (int i = 0; i < BOKEH_MAX; i++) {
RD::PipelineColorBlendState blend_state = (i == BOKEH_COMPOSITE) ? RD::PipelineColorBlendState::create_blend(att_count[i]) : RD::PipelineColorBlendState::create_disabled(att_count[i]);
bokeh.raster_pipelines[i].setup(bokeh.raster_shader.version_get_shader(bokeh.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
}
} else {
bokeh.compute_shader.initialize(bokeh_modes);
bokeh.shader_version = bokeh.compute_shader.version_create();
bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_BOX_NOWEIGHT, false);
bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT, false);
for (int i = 0; i < BOKEH_MAX; i++) {
bokeh.pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.shader.version_get_shader(bokeh.shader_version, i));
if (bokeh.compute_shader.is_variant_enabled(i)) {
bokeh.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.compute_shader.version_get_shader(bokeh.shader_version, i));
}
}
for (int i = 0; i < BOKEH_MAX; i++) {
bokeh.raster_pipelines[i].clear();
}
}
@ -2173,12 +2290,13 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
if (prefer_raster_effects) {
filter.raster_shader.initialize(cubemap_filter_modes);
filter.shader_version = filter.raster_shader.version_create();
// array variants are not supported in raster
filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false);
filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false);
filter.shader_version = filter.raster_shader.version_create();
for (int i = 0; i < FILTER_MODE_MAX; i++) {
if (filter.raster_shader.is_variant_enabled(i)) {
filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
@ -2390,12 +2508,13 @@ EffectsRD::~EffectsRD() {
if (prefer_raster_effects) {
blur_raster.shader.version_free(blur_raster.shader_version);
bokeh.raster_shader.version_free(blur_raster.shader_version);
luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
roughness.raster_shader.version_free(roughness.shader_version);
cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
filter.raster_shader.version_free(filter.shader_version);
} else {
bokeh.shader.version_free(bokeh.shader_version);
bokeh.compute_shader.version_free(bokeh.shader_version);
luminance_reduce.shader.version_free(luminance_reduce.shader_version);
roughness.compute_shader.version_free(roughness.shader_version);
cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version);

View File

@ -35,6 +35,7 @@
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/blur_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h"
@ -72,10 +73,7 @@ private:
BLUR_MODE_GAUSSIAN_BLUR,
BLUR_MODE_GAUSSIAN_GLOW,
BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
BLUR_MODE_DOF_LOW,
BLUR_MODE_DOF_MEDIUM,
BLUR_MODE_DOF_HIGH,
BLUR_MODE_COPY,
BLUR_MODE_MAX
};
@ -84,8 +82,6 @@ private:
BLUR_FLAG_HORIZONTAL = (1 << 0),
BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 1),
BLUR_FLAG_GLOW_FIRST_PASS = (1 << 2),
BLUR_FLAG_DOF_FAR = (1 << 3),
BLUR_FLAG_DOF_NEAR = (1 << 4),
};
struct BlurRasterPushConstant {
@ -103,19 +99,6 @@ private:
float glow_white;
float glow_luminance_cap;
float glow_auto_exposure_grey;
//dof
float dof_far_begin;
float dof_far_end;
float dof_near_begin;
float dof_near_end;
float dof_radius;
float dof_pad[3];
float dof_dir[2];
float camera_z_far;
float camera_z_near;
};
struct BlurRaster {
@ -252,29 +235,29 @@ private:
};
struct TonemapPushConstant {
float bcs[3];
uint32_t use_bcs;
float bcs[3]; // 12 - 12
uint32_t use_bcs; // 4 - 16
uint32_t use_glow;
uint32_t use_auto_exposure;
uint32_t use_color_correction;
uint32_t tonemapper;
uint32_t use_glow; // 4 - 20
uint32_t use_auto_exposure; // 4 - 24
uint32_t use_color_correction; // 4 - 28
uint32_t tonemapper; // 4 - 32
uint32_t glow_texture_size[2];
float glow_intensity;
uint32_t pad3;
uint32_t glow_texture_size[2]; // 8 - 40
float glow_intensity; // 4 - 44
uint32_t pad3; // 4 - 48
uint32_t glow_mode;
float glow_levels[7];
uint32_t glow_mode; // 4 - 52
float glow_levels[7]; // 28 - 80
float exposure;
float white;
float auto_exposure_grey;
uint32_t pad2;
float exposure; // 4 - 84
float white; // 4 - 88
float auto_exposure_grey; // 4 - 92
uint32_t pad2; // 4 - 96
float pixel_size[2];
uint32_t use_fxaa;
uint32_t use_debanding;
float pixel_size[2]; // 8 - 104
uint32_t use_fxaa; // 4 - 108
uint32_t use_debanding; // 4 - 112
};
/* tonemap actually writes to a framebuffer, which is
@ -375,7 +358,9 @@ private:
enum BokehMode {
BOKEH_GEN_BLUR_SIZE,
BOKEH_GEN_BOKEH_BOX,
BOKEH_GEN_BOKEH_BOX_NOWEIGHT,
BOKEH_GEN_BOKEH_HEXAGONAL,
BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT,
BOKEH_GEN_BOKEH_CIRCULAR,
BOKEH_COMPOSITE,
BOKEH_MAX
@ -383,9 +368,11 @@ private:
struct Bokeh {
BokehPushConstant push_constant;
BokehDofShaderRD shader;
BokehDofShaderRD compute_shader;
BokehDofRasterShaderRD raster_shader;
RID shader_version;
RID pipelines[BOKEH_MAX];
RID compute_pipelines[BOKEH_MAX];
PipelineCacheRD raster_pipelines[BOKEH_MAX];
} bokeh;
enum SSAOMode {
@ -784,8 +771,26 @@ public:
void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
void blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
struct BokehBuffers {
// bokeh buffers
// textures
Size2i base_texture_size;
RID base_texture;
RID depth_texture;
RID secondary_texture;
RID half_texture[2];
// raster only
RID base_fb;
RID secondary_fb; // with weights
RID half_fb[2]; // with weights
RID base_weight_fb;
RID weight_texture[4];
};
void bokeh_dof(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
void bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
struct TonemapSettings {
bool use_glow = false;

View File

@ -1464,6 +1464,53 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
base_width = MAX(1, base_width >> 1);
base_height = MAX(1, base_height >> 1);
}
if (!_render_buffers_can_be_storage()) {
// create 4 weight textures, 2 full size, 2 half size
tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
tf.width = rb->width;
tf.height = rb->height;
tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
tf.array_layers = rb->view_count;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
tf.mipmaps = 1;
for (uint32_t i = 0; i < 4; i++) {
// associated blur texture
RID texture;
if (i == 0) {
texture = rb->texture;
} else if (i == 1) {
texture = rb->blur[0].mipmaps[0].texture;
} else if (i == 2) {
texture = rb->blur[1].mipmaps[0].texture;
} else if (i == 3) {
texture = rb->blur[0].mipmaps[1].texture;
}
// create weight texture
rb->weight_buffers[i].weight = RD::get_singleton()->texture_create(tf, RD::TextureView());
// create frame buffer
Vector<RID> fb;
fb.push_back(texture);
fb.push_back(rb->weight_buffers[i].weight);
rb->weight_buffers[i].fb = RD::get_singleton()->framebuffer_create(fb);
if (i == 1) {
// next 2 are half size
tf.width = MAX(1, tf.width >> 1);
tf.height = MAX(1, tf.height >> 1);
}
}
{
// and finally an FB for just our base weights
Vector<RID> fb;
fb.push_back(rb->weight_buffers[0].weight);
rb->base_weight_fb = RD::get_singleton()->framebuffer_create(fb);
}
}
}
void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
@ -1851,11 +1898,34 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
_allocate_blur_textures(rb);
}
if (can_use_storage) {
EffectsRD::BokehBuffers buffers;
// textures we use
buffers.base_texture_size = Size2i(rb->width, rb->height);
buffers.base_texture = rb->texture;
buffers.depth_texture = rb->depth_texture;
buffers.secondary_texture = rb->blur[0].mipmaps[0].texture;
buffers.half_texture[0] = rb->blur[1].mipmaps[0].texture;
buffers.half_texture[1] = rb->blur[0].mipmaps[1].texture;
float bokeh_size = camfx->dof_blur_amount * 64.0;
storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
if (can_use_storage) {
storage->get_effects()->bokeh_dof(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
} else {
storage->get_effects()->blur_dof_raster(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->texture_fb, rb->blur[0].mipmaps[0].texture, rb->blur[0].mipmaps[0].fb, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, camfx->dof_blur_amount, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
// set framebuffers
buffers.base_fb = rb->texture_fb;
buffers.secondary_fb = rb->weight_buffers[1].fb;
buffers.half_fb[0] = rb->weight_buffers[2].fb;
buffers.half_fb[1] = rb->weight_buffers[3].fb;
buffers.weight_texture[0] = rb->weight_buffers[0].weight;
buffers.weight_texture[1] = rb->weight_buffers[1].weight;
buffers.weight_texture[2] = rb->weight_buffers[2].weight;
buffers.weight_texture[3] = rb->weight_buffers[3].weight;
// set weight buffers
buffers.base_weight_fb = rb->base_weight_fb;
storage->get_effects()->bokeh_dof_raster(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
}
RD::get_singleton()->draw_command_end_label();
}

View File

@ -483,6 +483,15 @@ private:
Blur blur[2]; //the second one starts from the first mipmap
struct WeightBuffers {
RID weight;
RID fb; // FB with both texture and weight
};
// 2 full size, 2 half size
WeightBuffers weight_buffers[4]; // Only used in raster
RID base_weight_fb; // base buffer for weight
struct Luminance {
Vector<RID> reduce;
RID current;

View File

@ -37,32 +37,6 @@ layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(location = 0) out vec4 frag_color;
//DOF
#ifdef MODE_DOF_BLUR
layout(set = 1, binding = 0) uniform sampler2D dof_source_depth;
#ifdef DOF_QUALITY_LOW
const int dof_kernel_size = 5;
const int dof_kernel_from = 2;
const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388);
#endif
#ifdef DOF_QUALITY_MEDIUM
const int dof_kernel_size = 11;
const int dof_kernel_from = 5;
const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037);
#endif
#ifdef DOF_QUALITY_HIGH
const int dof_kernel_size = 21;
const int dof_kernel_from = 10;
const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174);
#endif
#endif
void main() {
#ifdef MODE_MIPMAP
@ -155,74 +129,8 @@ void main() {
#endif
#ifdef MODE_DOF_BLUR
vec4 color_accum = vec4(0.0);
float depth = texture(dof_source_depth, uv_interp, 0.0).r;
depth = depth * 2.0 - 1.0;
if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
} else {
depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near));
}
// mix near and far blur amount
float amount = 1.0;
if (bool(blur.flags & FLAG_DOF_FAR)) {
amount *= 1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, depth);
}
if (bool(blur.flags & FLAG_DOF_NEAR)) {
amount *= smoothstep(blur.dof_near_end, blur.dof_near_begin, depth);
}
amount = 1.0 - amount;
if (amount > 0.0) {
float k_accum = 0.0;
for (int i = 0; i < dof_kernel_size; i++) {
int int_ofs = i - dof_kernel_from;
vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius;
float tap_k = dof_kernel[i];
float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
} else {
tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near));
}
// mix near and far blur amount
float tap_amount = 1.0;
if (bool(blur.flags & FLAG_DOF_FAR)) {
tap_amount *= mix(1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, tap_depth), 0.0, int_ofs == 0);
}
if (bool(blur.flags & FLAG_DOF_NEAR)) {
tap_amount *= mix(smoothstep(blur.dof_near_end, blur.dof_near_begin, tap_depth), 0.0, int_ofs == 0);
}
tap_amount = 1.0 - tap_amount;
tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k;
k_accum += tap_k * tap_amount;
color_accum += tap_color * tap_amount;
}
if (k_accum > 0.0) {
color_accum /= k_accum;
}
frag_color = color_accum; ///k_accum;
} else {
// we are in focus, don't waste time
frag_color = texture(source_color, uv_interp, 0.0);
}
#ifdef MODE_COPY
vec4 color = textureLod(source_color, uv_interp, 0.0);
frag_color = color;
#endif
}

View File

@ -1,8 +1,6 @@
#define FLAG_HORIZONTAL (1 << 0)
#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1)
#define FLAG_GLOW_FIRST_PASS (1 << 2)
#define FLAG_DOF_FAR (1 << 3)
#define FLAG_DOF_NEAR (1 << 4)
layout(push_constant, binding = 1, std430) uniform Blur {
vec2 pixel_size;
@ -19,18 +17,5 @@ layout(push_constant, binding = 1, std430) uniform Blur {
float glow_white;
float glow_luminance_cap;
float glow_auto_exposure_grey;
// DOF.
float dof_far_begin;
float dof_far_end;
float dof_near_begin;
float dof_near_end;
float dof_radius;
float dof_pad[3];
vec2 dof_dir;
float camera_z_far;
float camera_z_near;
}
blur;

View File

@ -25,34 +25,7 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
// based on https://www.shadertoy.com/view/Xd3GDl
layout(push_constant, binding = 1, std430) uniform Params {
ivec2 size;
float z_far;
float z_near;
bool orthogonal;
float blur_size;
float blur_scale;
int blur_steps;
bool blur_near_active;
float blur_near_begin;
float blur_near_end;
bool blur_far_active;
float blur_far_begin;
float blur_far_end;
bool second_pass;
bool half_size;
bool use_jitter;
float jitter_seed;
uint pad[2];
}
params;
//used to work around downsampling filter
#define DEPTH_GAP 0.0
#include "bokeh_dof_inc.glsl"
#ifdef MODE_GEN_BLUR_SIZE
@ -80,15 +53,6 @@ float get_blur_size(float depth) {
#endif
const float GOLDEN_ANGLE = 2.39996323;
//note: uniform pdf rand [0;1[
float hash12n(vec2 p) {
p = fract(p * vec2(5.3987, 5.4421));
p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
return fract(p.x * p.y * 95.4307);
}
#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {

View File

@ -0,0 +1,37 @@
layout(push_constant, binding = 1, std430) uniform Params {
ivec2 size;
float z_far;
float z_near;
bool orthogonal;
float blur_size;
float blur_scale;
int blur_steps;
bool blur_near_active;
float blur_near_begin;
float blur_near_end;
bool blur_far_active;
float blur_far_begin;
float blur_far_end;
bool second_pass;
bool half_size;
bool use_jitter;
float jitter_seed;
uint pad[2];
}
params;
//used to work around downsampling filter
#define DEPTH_GAP 0.0
const float GOLDEN_ANGLE = 2.39996323;
//note: uniform pdf rand [0;1[
float hash12n(vec2 p) {
p = fract(p * vec2(5.3987, 5.4421));
p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
return fract(p.x * p.y * 95.4307);
}

View File

@ -0,0 +1,253 @@
/* clang-format off */
#[vertex]
#version 450
#VERSION_DEFINES
#include "bokeh_dof_inc.glsl"
layout(location = 0) out vec2 uv_interp;
/* clang-format on */
void main() {
vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
uv_interp = base_arr[gl_VertexIndex];
gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
}
/* clang-format off */
#[fragment]
#version 450
#VERSION_DEFINES
#include "bokeh_dof_inc.glsl"
layout(location = 0) in vec2 uv_interp;
/* clang-format on */
#ifdef MODE_GEN_BLUR_SIZE
layout(location = 0) out float weight;
layout(set = 0, binding = 0) uniform sampler2D source_depth;
#else
layout(location = 0) out vec4 frag_color;
#ifdef OUTPUT_WEIGHT
layout(location = 1) out float weight;
#endif
layout(set = 0, binding = 0) uniform sampler2D source_color;
layout(set = 1, binding = 0) uniform sampler2D source_weight;
#ifdef MODE_COMPOSITE_BOKEH
layout(set = 2, binding = 0) uniform sampler2D original_weight;
#endif
#endif
//DOF
// Bokeh single pass implementation based on http://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html
#ifdef MODE_GEN_BLUR_SIZE
float get_depth_at_pos(vec2 uv) {
float depth = textureLod(source_depth, uv, 0.0).x;
if (params.orthogonal) {
depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
} else {
depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
}
return depth;
}
float get_blur_size(float depth) {
if (params.blur_near_active && depth < params.blur_near_begin) {
return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative
}
if (params.blur_far_active && depth > params.blur_far_begin) {
return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
}
return 0.0;
}
#endif
#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
dir *= pixel_size;
vec4 color = texture(source_color, uv);
color.a = texture(source_weight, uv).r;
vec4 accum = color;
float total = 1.0;
float blur_scale = params.blur_size / float(params.blur_steps);
if (params.use_jitter) {
uv += dir * (hash12n(uv + params.jitter_seed) - 0.5);
}
for (int i = -params.blur_steps; i <= params.blur_steps; i++) {
if (i == 0) {
continue;
}
float radius = float(i) * blur_scale;
vec2 suv = uv + dir * radius;
radius = abs(radius);
vec4 sample_color = texture(source_color, suv);
sample_color.a = texture(source_weight, suv).r;
float limit;
if (sample_color.a < color.a) {
limit = abs(sample_color.a);
} else {
limit = abs(color.a);
}
limit -= DEPTH_GAP;
float m = smoothstep(radius - 0.5, radius + 0.5, limit);
accum += mix(color, sample_color, m);
total += 1.0;
}
return accum / total;
}
#endif
void main() {
vec2 pixel_size = 1.0 / vec2(params.size);
vec2 uv = uv_interp;
#ifdef MODE_GEN_BLUR_SIZE
uv += pixel_size * 0.5;
float center_depth = get_depth_at_pos(uv);
weight = get_blur_size(center_depth);
#endif
#ifdef MODE_BOKEH_BOX
//pixel_size*=0.5; //resolution is doubled
if (params.second_pass || !params.half_size) {
uv += pixel_size * 0.5; //half pixel to read centers
} else {
uv += pixel_size * 0.25; //half pixel to read centers from full res
}
float alpha = texture(source_color, uv).a; // retain this
vec2 dir = (params.second_pass ? vec2(0.0, 1.0) : vec2(1.0, 0.0));
vec4 color = weighted_filter_dir(dir, uv, pixel_size);
frag_color = color;
frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
#ifdef OUTPUT_WEIGHT
weight = color.a;
#endif
#endif
#ifdef MODE_BOKEH_HEXAGONAL
//pixel_size*=0.5; //resolution is doubled
if (params.second_pass || !params.half_size) {
uv += pixel_size * 0.5; //half pixel to read centers
} else {
uv += pixel_size * 0.25; //half pixel to read centers from full res
}
float alpha = texture(source_color, uv).a; // retain this
vec2 dir = (params.second_pass ? normalize(vec2(1.0, 0.577350269189626)) : vec2(0.0, 1.0));
vec4 color = weighted_filter_dir(dir, uv, pixel_size);
if (params.second_pass) {
dir = normalize(vec2(-1.0, 0.577350269189626));
vec4 color2 = weighted_filter_dir(dir, uv, pixel_size);
color.rgb = min(color.rgb, color2.rgb);
color.a = (color.a + color2.a) * 0.5;
}
frag_color = color;
frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
#ifdef OUTPUT_WEIGHT
weight = color.a;
#endif
#endif
#ifdef MODE_BOKEH_CIRCULAR
if (params.half_size) {
pixel_size *= 0.5; //resolution is doubled
}
uv += pixel_size * 0.5; //half pixel to read centers
vec4 color = texture(source_color, uv);
float alpha = color.a; // retain this
color.a = texture(source_weight, uv).r;
vec4 color_accum = color;
float accum = 1.0;
float radius = params.blur_scale;
for (float ang = 0.0; radius < params.blur_size; ang += GOLDEN_ANGLE) {
vec2 uv_adj = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
vec4 sample_color = texture(source_color, uv_adj);
sample_color.a = texture(source_weight, uv_adj).r;
float limit;
if (sample_color.a < color.a) {
limit = abs(sample_color.a);
} else {
limit = abs(color.a);
}
limit -= DEPTH_GAP;
float m = smoothstep(radius - 0.5, radius + 0.5, limit);
color_accum += mix(color_accum / accum, sample_color, m);
accum += 1.0;
radius += params.blur_scale / radius;
}
color_accum = color_accum / accum;
frag_color.rgb = color_accum.rgb;
frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
#ifdef OUTPUT_WEIGHT
weight = color_accum.a;
#endif
#endif
#ifdef MODE_COMPOSITE_BOKEH
frag_color.rgb = texture(source_color, uv).rgb;
float center_weigth = texture(source_weight, uv).r;
float sample_weight = texture(original_weight, uv).r;
float mix_amount;
if (sample_weight < center_weigth) {
mix_amount = min(1.0, max(0.0, max(abs(center_weigth), abs(sample_weight)) - DEPTH_GAP));
} else {
mix_amount = min(1.0, max(0.0, abs(center_weigth) - DEPTH_GAP));
}
// let alpha blending take care of mixing
frag_color.a = mix_amount;
#endif
}