diff options
author | Juan Linietsky <reduzio@gmail.com> | 2020-01-15 21:23:21 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 12:15:26 +0100 |
commit | f8b5c5f0631ac629c00795b5f3f8775c32a0368b (patch) | |
tree | f58d19c2a3480497ff37fe657dfcc76c45d556da /servers | |
parent | c05da81268ca754493e59f359ba08a60ec7092bf (diff) |
DOF fully implemented, can be edited on the fly.
Diffstat (limited to 'servers')
-rw-r--r-- | servers/visual/rasterizer.h | 5 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp | 145 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_effects_rd.h | 16 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp | 21 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_scene_rd.h | 11 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl | 155 | ||||
-rw-r--r-- | servers/visual/visual_server_raster.h | 5 | ||||
-rw-r--r-- | servers/visual/visual_server_wrap_mt.h | 5 | ||||
-rw-r--r-- | servers/visual_server.cpp | 10 | ||||
-rw-r--r-- | servers/visual_server.h | 13 |
10 files changed, 328 insertions, 58 deletions
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 04643354ca..0bfd323ec0 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -95,7 +95,10 @@ public: virtual RID camera_effects_create() = 0; - virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount, VS::DOFBlurQuality p_quality) = 0; + virtual void camera_effects_set_dof_blur_quality(VS::DOFBlurQuality p_quality, bool p_use_jitter) = 0; + virtual void camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape p_shape) = 0; + + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; struct InstanceBase; diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp index ff3f6f294b..111ad06f5b 100644 --- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "rasterizer_effects_rd.h" +#include "core/os/os.h" static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) { p_array[0] = p_basis.elements[0][0]; @@ -406,7 +407,7 @@ void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_bokeh_texture, 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, VS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { +void RasterizerEffectsRD::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, VisualServer::DOFBokehShape p_bokeh_shape, VS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { bokeh.push_constant.blur_far_active = p_dof_far; bokeh.push_constant.blur_far_begin = p_dof_far_begin; @@ -415,15 +416,25 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con bokeh.push_constant.blur_near_active = p_dof_near; bokeh.push_constant.blur_near_begin = p_dof_near_begin; bokeh.push_constant.blur_near_end = MAX(0, p_dof_near_begin - p_dof_near_size); + bokeh.push_constant.use_jitter = p_use_jitter; + bokeh.push_constant.jitter_seed = Math::randf() * 1000.0; bokeh.push_constant.z_near = p_cam_znear; bokeh.push_constant.z_far = p_cam_zfar; bokeh.push_constant.orthogonal = p_cam_orthogonal; bokeh.push_constant.blur_size = p_bokeh_size; + + bokeh.push_constant.second_pass = false; + bokeh.push_constant.half_size = false; + bokeh.push_constant.blur_scale = 0.5; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + /* FIRST PASS */ + // 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_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); @@ -439,36 +450,122 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH]); + if (p_bokeh_shape == VS::DOF_BOKEH_BOX || p_bokeh_shape == VS::DOF_BOKEH_HEXAGON) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_bokeh_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_compute_uniform_set_from_texture(p_base_texture), 2); + //second pass + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[p_bokeh_shape == VS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]); - x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1; - y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 1; - bokeh.push_constant.size[0] = p_base_texture_size.x >> 1; - bokeh.push_constant.size[1] = p_base_texture_size.y >> 1; + static const int quality_samples[4] = { 6, 12, 12, 24 }; - RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + bokeh.push_constant.steps = quality_samples[p_quality]; - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); + if (p_quality == VS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == VS::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_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]); + 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_base_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_bokeh_texture), 1); + x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1; + y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 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.half_size = true; + bokeh.push_constant.blur_size *= 0.5; - x_groups = (p_base_texture_size.x - 1) / 8 + 1; - y_groups = (p_base_texture_size.y - 1) / 8 + 1; - bokeh.push_constant.size[0] = p_base_texture_size.x; - bokeh.push_constant.size[1] = p_base_texture_size.y; + } 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_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + //third pass + bokeh.push_constant.second_pass = true; + + if (p_quality == VS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == VS::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); + } 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_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + if (p_quality == VS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == VS::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_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); + + x_groups = (p_base_texture_size.x - 1) / 8 + 1; + y_groups = (p_base_texture_size.y - 1) / 8 + 1; + bokeh.push_constant.size[0] = p_base_texture_size.x; + bokeh.push_constant.size[1] = p_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(compute_list, x_groups, y_groups, 1); + } + } else { + //circle + + //second pass + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH_CIRCULAR]); + + static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 }; + + bokeh.push_constant.steps = 0; + bokeh.push_constant.blur_scale = quality_scale[p_quality]; + + //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); + + x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1; + y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 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.half_size = true; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + //circle is just one pass, then upscale + + // upscale + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.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); + + x_groups = (p_base_texture_size.x - 1) / 8 + 1; + y_groups = (p_base_texture_size.y - 1) / 8 + 1; + bokeh.push_constant.size[0] = p_base_texture_size.x; + bokeh.push_constant.size[1] = p_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(compute_list, x_groups, y_groups, 1); + } RD::get_singleton()->compute_list_end(); } @@ -582,7 +679,9 @@ RasterizerEffectsRD::RasterizerEffectsRD() { // Initialize bokeh Vector<String> bokeh_modes; bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n"); - bokeh_modes.push_back("\n#define MODE_GEN_BOKEH\n"); + bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\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_COMPOSITE_BOKEH\n"); bokeh.shader.initialize(bokeh_modes); diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h index f050e298a9..77779f2c84 100644 --- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h @@ -231,20 +231,28 @@ class RasterizerEffectsRD { uint32_t orthogonal; float blur_size; float blur_scale; - uint32_t pad; + uint32_t steps; uint32_t blur_near_active; float blur_near_begin; float blur_near_end; uint32_t blur_far_active; + float blur_far_begin; float blur_far_end; - uint32_t pad2[2]; + uint32_t second_pass; + uint32_t half_size; + + uint32_t use_jitter; + float jitter_seed; + uint32_t pad[2]; }; enum BokehMode { BOKEH_GEN_BLUR_SIZE, - BOKEH_GEN_BOKEH, + BOKEH_GEN_BOKEH_BOX, + BOKEH_GEN_BOKEH_HEXAGONAL, + BOKEH_GEN_BOKEH_CIRCULAR, BOKEH_COMPOSITE, BOKEH_MAX }; @@ -284,7 +292,7 @@ public: void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size); void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); 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 bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_bokeh_texture, 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, VS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); + 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, VS::DOFBokehShape p_bokeh_shape, VS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); struct TonemapSettings { diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index e5b199261f..c9f3f696eb 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -1122,7 +1122,18 @@ RID RasterizerSceneRD::camera_effects_create() { return camera_effects_owner.make_rid(CameraEffects()); } -void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount, VS::DOFBlurQuality p_quality) { +void RasterizerSceneRD::camera_effects_set_dof_blur_quality(VS::DOFBlurQuality p_quality, bool p_use_jitter) { + + dof_blur_quality = p_quality; + dof_blur_use_jitter = p_use_jitter; +} + +void RasterizerSceneRD::camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape p_shape) { + + dof_blur_bokeh_shape = p_shape; +} + +void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); ERR_FAIL_COND(!camfx); @@ -1134,7 +1145,6 @@ void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p camfx->dof_blur_near_distance = p_near_distance; camfx->dof_blur_near_transition = p_near_transition; - camfx->dof_blur_quality = p_quality; camfx->dof_blur_amount = p_amount; } @@ -2332,8 +2342,8 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu _allocate_blur_textures(rb); } - float bokeh_size = camfx->dof_blur_amount * 20.0; - storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[1].mipmaps[0].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, camfx->dof_blur_quality, p_projection.get_z_near(), p_projection.get_z_far(), p_projection.is_orthogonal()); + 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_projection.get_z_near(), p_projection.get_z_far(), p_projection.is_orthogonal()); } if (can_use_effects && env && env->auto_exposure) { @@ -2908,6 +2918,9 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); } } + + camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_shape")))); + camera_effects_set_dof_blur_quality(VS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/filters/depth_of_field_use_jitter")); } RasterizerSceneRD::~RasterizerSceneRD() { diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h index cfd11e9a38..c6d13e4d34 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h @@ -501,12 +501,14 @@ private: float dof_blur_amount = 0.1; - VS::DOFBlurQuality dof_blur_quality = VS::DOF_BLUR_QUALITY_MEDIUM; - bool override_exposure_enabled = false; float override_exposure = 1; }; + VS::DOFBlurQuality dof_blur_quality = VS::DOF_BLUR_QUALITY_MEDIUM; + VS::DOFBokehShape dof_blur_bokeh_shape = VS::DOF_BOKEH_HEXAGON; + bool dof_blur_use_jitter = false; + mutable RID_Owner<CameraEffects> camera_effects_owner; /* RENDER BUFFERS */ @@ -649,7 +651,10 @@ public: virtual RID camera_effects_create(); - virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount, VS::DOFBlurQuality p_quality); + virtual void camera_effects_set_dof_blur_quality(VS::DOFBlurQuality p_quality, bool p_use_jitter); + virtual void camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape p_shape); + + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount); virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure); RID light_instance_create(RID p_light); diff --git a/servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl b/servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl index 83e77a19fc..e4508d3c8c 100644 --- a/servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl +++ b/servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl @@ -15,9 +15,8 @@ layout(rgba16f, set = 0, binding = 0) uniform restrict image2D color_image; layout(set = 1, binding = 0) uniform sampler2D source_depth; #endif -#ifdef MODE_GEN_BOKEH -layout(set = 2, binding = 0) uniform sampler2D color_texture; -layout(set = 1, binding = 0) uniform sampler2D source_depth; +#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL) || defined(MODE_BOKEH_CIRCULAR) +layout(set = 1, binding = 0) uniform sampler2D color_texture; layout(rgba16f, set = 0, binding = 0) uniform restrict writeonly image2D bokeh_image; #endif @@ -26,7 +25,7 @@ layout(rgba16f, set = 0, binding = 0) uniform restrict image2D color_image; layout(set = 1, binding = 0) uniform sampler2D source_bokeh; #endif - +// based on https://www.shadertoy.com/view/Xd3GDl layout(push_constant, binding = 1, std430) uniform Params { @@ -37,19 +36,27 @@ layout(push_constant, binding = 1, std430) uniform Params { bool orthogonal; float blur_size; float blur_scale; - uint pad; + 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; - uint pad2[2]; + bool second_pass; + bool half_size; + bool use_jitter; + float jitter_seed; + uint pad[2]; } params; -#ifndef MODE_COMPOSITE_BOKEH +//used to work around downsampling filter +#define DEPTH_GAP 0.0 + +#ifdef MODE_GEN_BLUR_SIZE float get_depth_at_pos(vec2 uv) { float depth = textureLod(source_depth,uv,0.0).x; @@ -61,14 +68,15 @@ float get_depth_at_pos(vec2 uv) { 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; + 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; + return smoothstep(params.blur_far_begin,params.blur_far_end,depth) * params.blur_size + DEPTH_GAP; } return 0.0; @@ -78,6 +86,63 @@ float get_blur_size(float depth) { 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) { + + dir *= pixel_size; + vec4 color = texture(color_texture,uv); + + 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(color_texture, suv); + 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() { ivec2 pos = ivec2(gl_GlobalInvocationID.xy); @@ -100,14 +165,61 @@ void main() { imageStore(color_image,pos,color); #endif -#ifdef MODE_GEN_BOKEH +#ifdef MODE_BOKEH_BOX - pixel_size*=0.5; //resolution is doubled + //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 + } + + vec2 dir = (params.second_pass ? vec2(0.0,1.0) : vec2(1.0,0.0)); + + vec4 color = weighted_filter_dir(dir,uv,pixel_size); + + imageStore(bokeh_image,pos,color); + +#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 + } + + 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; + } + + imageStore(bokeh_image,pos,color); + + + +#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 - float depth = get_depth_at_pos(uv); - float size = get_blur_size(depth); vec4 color = texture(color_texture,uv); float accum = 1.0; float radius = params.blur_scale; @@ -116,12 +228,12 @@ void main() { vec2 suv = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius; vec4 sample_color = texture(color_texture, suv); - float sample_depth = get_depth_at_pos(suv); - if (sample_depth > depth) { - sample_color.a = clamp(sample_color.a, 0.0, size*2.0); + float sample_size = abs(sample_color.a); + if (sample_color.a > color.a) { + sample_size = clamp(sample_size, 0.0, abs(color.a)*2.0); } - float m = smoothstep(radius-0.5, radius+0.5, sample_color.a); + float m = smoothstep(radius-0.5, radius+0.5, sample_size); color += mix(color/accum, sample_color, m); accum += 1.0; radius += params.blur_scale/radius; @@ -138,7 +250,14 @@ void main() { vec4 color = imageLoad(color_image,pos); vec4 bokeh = texture(source_bokeh,uv); - color.rgb = mix(color.rgb,bokeh.rgb,min(1.0,max(color.a,bokeh.a))); //blend between hires and lowres + float mix_amount; + if (bokeh.a < color.a) { + mix_amount = min(1.0,max(0.0,max(abs(color.a),abs(bokeh.a))-DEPTH_GAP)); + } else { + mix_amount = min(1.0,max(0.0,abs(color.a)-DEPTH_GAP)); + } + + color.rgb = mix(color.rgb,bokeh.rgb,mix_amount); //blend between hires and lowres color.a=0; //reset alpha imageStore(color_image,pos,color); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index f0811f5b54..51ce440320 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -541,7 +541,10 @@ public: BIND0R(RID, camera_effects_create) - BIND9(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float, DOFBlurQuality) + BIND2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool) + BIND1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape) + + BIND8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) BIND3(camera_effects_set_custom_exposure, RID, bool, float) /* SCENARIO API */ diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 0d40a4e1ea..ddb0f8e76c 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -453,7 +453,10 @@ public: FUNCRID(camera_effects) - FUNC9(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float, DOFBlurQuality) + FUNC2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool) + FUNC1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape) + + FUNC8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) FUNC3(camera_effects_set_custom_exposure, RID, bool, float) FUNCRID(scenario) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 9a9775508f..60ea292d8f 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2287,7 +2287,7 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1); GLOBAL_DEF("rendering/quality/shadows/filter_mode.mobile", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/filter_mode", PropertyInfo(Variant::INT, "rendering/quality/shadows/filter_mode", PROPERTY_HINT_ENUM, "Disabled,PCF5,PCF13")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/filter_mode", PropertyInfo(Variant::INT, "rendering/quality/shadows/filter_mode", PROPERTY_HINT_ENUM, "Disabled (Fastest),PCF5,PCF13 (Slowest)")); GLOBAL_DEF("rendering/quality/reflections/roughness_layers", 6); GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true); @@ -2302,7 +2302,7 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/gi_probes/anisotropic", false); GLOBAL_DEF("rendering/quality/gi_probes/quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/quality/gi_probes/quality", PROPERTY_HINT_ENUM, "Ultra-Low (1 cone),Medium (4 cones), High (6 cones)")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/quality/gi_probes/quality", PROPERTY_HINT_ENUM, "Ultra-Low (1 cone, fastest),Medium (4 cones), High (6 cones, slowest)")); GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false); GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true); @@ -2316,6 +2316,12 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/filters/use_nearest_mipmap_filter", false); GLOBAL_DEF("rendering/quality/filters/max_anisotropy", 4); + + GLOBAL_DEF("rendering/quality/filters/depth_of_field_bokeh_shape", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/quality/filters/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fastest),Hexagon,Circle (Slowest)")); + GLOBAL_DEF("rendering/quality/filters/depth_of_field_bokeh_quality", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/quality/filters/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fast),Low,Medium,High (Slow)")); + GLOBAL_DEF("rendering/quality/filters/depth_of_field_use_jitter", false); } VisualServer::~VisualServer() { diff --git a/servers/visual_server.h b/servers/visual_server.h index c61e984007..dde8025eb2 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -769,12 +769,23 @@ public: virtual RID camera_effects_create() = 0; enum DOFBlurQuality { + DOF_BLUR_QUALITY_VERY_LOW, DOF_BLUR_QUALITY_LOW, DOF_BLUR_QUALITY_MEDIUM, DOF_BLUR_QUALITY_HIGH, }; - virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount, DOFBlurQuality p_quality) = 0; + virtual void camera_effects_set_dof_blur_quality(DOFBlurQuality p_quality, bool p_use_jitter) = 0; + + enum DOFBokehShape { + DOF_BOKEH_BOX, + DOF_BOKEH_HEXAGON, + DOF_BOKEH_CIRCLE + }; + + virtual void camera_effects_set_dof_blur_bokeh_shape(DOFBokehShape p_shape) = 0; + + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; /* SCENARIO API */ |