Răsfoiți Sursa

DOF fully implemented, can be edited on the fly.

Juan Linietsky 5 ani în urmă
părinte
comite
f8b5c5f063

+ 7 - 1
editor/editor_node.cpp

@@ -343,7 +343,7 @@ void EditorNode::_notification(int p_what) {
 
 
 			scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")));
 			scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")));
 
 
-			{
+			{ //TODO should only happen on settings changed
 				int current_filter = GLOBAL_GET("rendering/canvas_textures/default_texture_filter");
 				int current_filter = GLOBAL_GET("rendering/canvas_textures/default_texture_filter");
 				if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
 				if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
 					Viewport::DefaultCanvasItemTextureFilter tf = (Viewport::DefaultCanvasItemTextureFilter)current_filter;
 					Viewport::DefaultCanvasItemTextureFilter tf = (Viewport::DefaultCanvasItemTextureFilter)current_filter;
@@ -354,6 +354,12 @@ void EditorNode::_notification(int p_what) {
 					Viewport::DefaultCanvasItemTextureRepeat tr = (Viewport::DefaultCanvasItemTextureRepeat)current_repeat;
 					Viewport::DefaultCanvasItemTextureRepeat tr = (Viewport::DefaultCanvasItemTextureRepeat)current_repeat;
 					scene_root->set_default_canvas_item_texture_repeat(tr);
 					scene_root->set_default_canvas_item_texture_repeat(tr);
 				}
 				}
+
+				VS::DOFBokehShape dof_shape = VS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_shape")));
+				VS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
+				VS::DOFBlurQuality dof_quality = VS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_quality")));
+				bool dof_jitter = GLOBAL_GET("rendering/quality/filters/depth_of_field_use_jitter");
+				VS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter);
 			}
 			}
 
 
 			ResourceImporterTexture::get_singleton()->update_imports();
 			ResourceImporterTexture::get_singleton()->update_imports();

+ 8 - 29
scene/resources/environment.cpp

@@ -1291,7 +1291,7 @@ Environment::~Environment() {
 void CameraEffects::set_dof_blur_far_enabled(bool p_enable) {
 void CameraEffects::set_dof_blur_far_enabled(bool p_enable) {
 
 
 	dof_blur_far_enabled = p_enable;
 	dof_blur_far_enabled = p_enable;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
+	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
 }
 }
 
 
 bool CameraEffects::is_dof_blur_far_enabled() const {
 bool CameraEffects::is_dof_blur_far_enabled() const {
@@ -1302,7 +1302,7 @@ bool CameraEffects::is_dof_blur_far_enabled() const {
 void CameraEffects::set_dof_blur_far_distance(float p_distance) {
 void CameraEffects::set_dof_blur_far_distance(float p_distance) {
 
 
 	dof_blur_far_distance = p_distance;
 	dof_blur_far_distance = p_distance;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
+	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
 }
 }
 float CameraEffects::get_dof_blur_far_distance() const {
 float CameraEffects::get_dof_blur_far_distance() const {
 
 
@@ -1312,7 +1312,7 @@ float CameraEffects::get_dof_blur_far_distance() const {
 void CameraEffects::set_dof_blur_far_transition(float p_distance) {
 void CameraEffects::set_dof_blur_far_transition(float p_distance) {
 
 
 	dof_blur_far_transition = p_distance;
 	dof_blur_far_transition = p_distance;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
+	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
 }
 }
 float CameraEffects::get_dof_blur_far_transition() const {
 float CameraEffects::get_dof_blur_far_transition() const {
 
 
@@ -1322,7 +1322,7 @@ float CameraEffects::get_dof_blur_far_transition() const {
 void CameraEffects::set_dof_blur_near_enabled(bool p_enable) {
 void CameraEffects::set_dof_blur_near_enabled(bool p_enable) {
 
 
 	dof_blur_near_enabled = p_enable;
 	dof_blur_near_enabled = p_enable;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
+	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
 	_change_notify();
 	_change_notify();
 }
 }
 
 
@@ -1334,7 +1334,7 @@ bool CameraEffects::is_dof_blur_near_enabled() const {
 void CameraEffects::set_dof_blur_near_distance(float p_distance) {
 void CameraEffects::set_dof_blur_near_distance(float p_distance) {
 
 
 	dof_blur_near_distance = p_distance;
 	dof_blur_near_distance = p_distance;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
+	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
 }
 }
 
 
 float CameraEffects::get_dof_blur_near_distance() const {
 float CameraEffects::get_dof_blur_near_distance() const {
@@ -1345,7 +1345,7 @@ float CameraEffects::get_dof_blur_near_distance() const {
 void CameraEffects::set_dof_blur_near_transition(float p_distance) {
 void CameraEffects::set_dof_blur_near_transition(float p_distance) {
 
 
 	dof_blur_near_transition = p_distance;
 	dof_blur_near_transition = p_distance;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
+	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
 }
 }
 
 
 float CameraEffects::get_dof_blur_near_transition() const {
 float CameraEffects::get_dof_blur_near_transition() const {
@@ -1356,24 +1356,13 @@ float CameraEffects::get_dof_blur_near_transition() const {
 void CameraEffects::set_dof_blur_amount(float p_amount) {
 void CameraEffects::set_dof_blur_amount(float p_amount) {
 
 
 	dof_blur_amount = p_amount;
 	dof_blur_amount = p_amount;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
+	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
 }
 }
 float CameraEffects::get_dof_blur_amount() const {
 float CameraEffects::get_dof_blur_amount() const {
 
 
 	return dof_blur_amount;
 	return dof_blur_amount;
 }
 }
 
 
-void CameraEffects::set_dof_blur_quality(DOFBlurQuality p_quality) {
-
-	dof_blur_quality = p_quality;
-	VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount, VS::DOFBlurQuality(dof_blur_quality));
-}
-
-CameraEffects::DOFBlurQuality CameraEffects::get_dof_blur_quality() const {
-
-	return dof_blur_quality;
-}
-
 void CameraEffects::set_override_exposure_enabled(bool p_enabled) {
 void CameraEffects::set_override_exposure_enabled(bool p_enabled) {
 	override_exposure_enabled = p_enabled;
 	override_exposure_enabled = p_enabled;
 	VS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure);
 	VS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure);
@@ -1419,9 +1408,6 @@ void CameraEffects::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "intensity"), &CameraEffects::set_dof_blur_amount);
 	ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "intensity"), &CameraEffects::set_dof_blur_amount);
 	ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount);
 	ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount);
 
 
-	ClassDB::bind_method(D_METHOD("set_dof_blur_quality", "level"), &CameraEffects::set_dof_blur_quality);
-	ClassDB::bind_method(D_METHOD("get_dof_blur_quality"), &CameraEffects::get_dof_blur_quality);
-
 	ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enable"), &CameraEffects::set_override_exposure);
 	ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enable"), &CameraEffects::set_override_exposure);
 	ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled);
 	ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled);
 
 
@@ -1436,14 +1422,9 @@ void CameraEffects::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "dof_blur_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_dof_blur_quality", "get_dof_blur_quality");
 	ADD_GROUP("Override Exposure", "override_");
 	ADD_GROUP("Override Exposure", "override_");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enable"), "set_override_exposure_enabled", "is_override_exposure_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enable"), "set_override_exposure_enabled", "is_override_exposure_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure");
-
-	BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_LOW);
-	BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_MEDIUM);
-	BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_HIGH);
 }
 }
 
 
 CameraEffects::CameraEffects() {
 CameraEffects::CameraEffects() {
@@ -1458,9 +1439,7 @@ CameraEffects::CameraEffects() {
 	dof_blur_near_distance = 2;
 	dof_blur_near_distance = 2;
 	dof_blur_near_transition = 1;
 	dof_blur_near_transition = 1;
 
 
-	dof_blur_amount = 0.1;
-
-	set_dof_blur_quality(DOF_BLUR_QUALITY_MEDIUM); //update server
+	set_dof_blur_amount(0.1);
 
 
 	override_exposure_enabled = false;
 	override_exposure_enabled = false;
 	set_override_exposure(1.0);
 	set_override_exposure(1.0);

+ 0 - 13
scene/resources/environment.h

@@ -398,13 +398,6 @@ class CameraEffects : public Resource {
 
 
 	GDCLASS(CameraEffects, Resource);
 	GDCLASS(CameraEffects, Resource);
 
 
-public:
-	enum DOFBlurQuality {
-		DOF_BLUR_QUALITY_LOW,
-		DOF_BLUR_QUALITY_MEDIUM,
-		DOF_BLUR_QUALITY_HIGH,
-	};
-
 private:
 private:
 	RID camera_effects;
 	RID camera_effects;
 
 
@@ -417,7 +410,6 @@ private:
 	float dof_blur_near_transition;
 	float dof_blur_near_transition;
 
 
 	float dof_blur_amount;
 	float dof_blur_amount;
-	DOFBlurQuality dof_blur_quality;
 
 
 	bool override_exposure_enabled;
 	bool override_exposure_enabled;
 	float override_exposure;
 	float override_exposure;
@@ -447,9 +439,6 @@ public:
 	void set_dof_blur_amount(float p_amount);
 	void set_dof_blur_amount(float p_amount);
 	float get_dof_blur_amount() const;
 	float get_dof_blur_amount() const;
 
 
-	void set_dof_blur_quality(DOFBlurQuality p_quality);
-	DOFBlurQuality get_dof_blur_quality() const;
-
 	void set_override_exposure_enabled(bool p_enabled);
 	void set_override_exposure_enabled(bool p_enabled);
 	bool is_override_exposure_enabled() const;
 	bool is_override_exposure_enabled() const;
 
 
@@ -462,6 +451,4 @@ public:
 	~CameraEffects();
 	~CameraEffects();
 };
 };
 
 
-VARIANT_ENUM_CAST(CameraEffects::DOFBlurQuality)
-
 #endif // ENVIRONMENT_H
 #endif // ENVIRONMENT_H

+ 4 - 1
servers/visual/rasterizer.h

@@ -95,7 +95,10 @@ public:
 
 
 	virtual RID camera_effects_create() = 0;
 	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;
 	virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
 
 
 	struct InstanceBase;
 	struct InstanceBase;

+ 122 - 23
servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp

@@ -29,6 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "rasterizer_effects_rd.h"
 #include "rasterizer_effects_rd.h"
+#include "core/os/os.h"
 
 
 static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
 static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
 	p_array[0] = p_basis.elements[0][0];
 	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();
 	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_active = p_dof_far;
 	bokeh.push_constant.blur_far_begin = p_dof_far_begin;
 	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_active = p_dof_near;
 	bokeh.push_constant.blur_near_begin = p_dof_near_begin;
 	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.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_near = p_cam_znear;
 	bokeh.push_constant.z_far = p_cam_zfar;
 	bokeh.push_constant.z_far = p_cam_zfar;
 	bokeh.push_constant.orthogonal = p_cam_orthogonal;
 	bokeh.push_constant.orthogonal = p_cam_orthogonal;
 	bokeh.push_constant.blur_size = p_bokeh_size;
 	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;
 	bokeh.push_constant.blur_scale = 0.5;
 
 
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
 	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_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);
 	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_dispatch(compute_list, x_groups, y_groups, 1);
 	RD::get_singleton()->compute_list_add_barrier(compute_list);
 	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();
 	RD::get_singleton()->compute_list_end();
 }
 }
@@ -582,7 +679,9 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
 		// Initialize bokeh
 		// Initialize bokeh
 		Vector<String> bokeh_modes;
 		Vector<String> bokeh_modes;
 		bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
 		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_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
 
 
 		bokeh.shader.initialize(bokeh_modes);
 		bokeh.shader.initialize(bokeh_modes);

+ 12 - 4
servers/visual/rasterizer_rd/rasterizer_effects_rd.h

@@ -231,20 +231,28 @@ class RasterizerEffectsRD {
 		uint32_t orthogonal;
 		uint32_t orthogonal;
 		float blur_size;
 		float blur_size;
 		float blur_scale;
 		float blur_scale;
-		uint32_t pad;
+		uint32_t steps;
 
 
 		uint32_t blur_near_active;
 		uint32_t blur_near_active;
 		float blur_near_begin;
 		float blur_near_begin;
 		float blur_near_end;
 		float blur_near_end;
 		uint32_t blur_far_active;
 		uint32_t blur_far_active;
+
 		float blur_far_begin;
 		float blur_far_begin;
 		float blur_far_end;
 		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 {
 	enum BokehMode {
 		BOKEH_GEN_BLUR_SIZE,
 		BOKEH_GEN_BLUR_SIZE,
-		BOKEH_GEN_BOKEH,
+		BOKEH_GEN_BOKEH_BOX,
+		BOKEH_GEN_BOKEH_HEXAGONAL,
+		BOKEH_GEN_BOKEH_CIRCULAR,
 		BOKEH_COMPOSITE,
 		BOKEH_COMPOSITE,
 		BOKEH_MAX
 		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 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 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 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 {
 	struct TonemapSettings {
 
 

+ 17 - 4
servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -1122,7 +1122,18 @@ RID RasterizerSceneRD::camera_effects_create() {
 	return camera_effects_owner.make_rid(CameraEffects());
 	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);
 	CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
 	ERR_FAIL_COND(!camfx);
 	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_distance = p_near_distance;
 	camfx->dof_blur_near_transition = p_near_transition;
 	camfx->dof_blur_near_transition = p_near_transition;
 
 
-	camfx->dof_blur_quality = p_quality;
 	camfx->dof_blur_amount = p_amount;
 	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);
 			_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) {
 	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);
 			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() {
 RasterizerSceneRD::~RasterizerSceneRD() {

+ 8 - 3
servers/visual/rasterizer_rd/rasterizer_scene_rd.h

@@ -501,12 +501,14 @@ private:
 
 
 		float dof_blur_amount = 0.1;
 		float dof_blur_amount = 0.1;
 
 
-		VS::DOFBlurQuality dof_blur_quality = VS::DOF_BLUR_QUALITY_MEDIUM;
-
 		bool override_exposure_enabled = false;
 		bool override_exposure_enabled = false;
 		float override_exposure = 1;
 		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;
 	mutable RID_Owner<CameraEffects> camera_effects_owner;
 
 
 	/* RENDER BUFFERS */
 	/* RENDER BUFFERS */
@@ -649,7 +651,10 @@ public:
 
 
 	virtual RID camera_effects_create();
 	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);
 	virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure);
 
 
 	RID light_instance_create(RID p_light);
 	RID light_instance_create(RID p_light);

+ 137 - 18
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;
 layout(set = 1, binding = 0) uniform sampler2D source_depth;
 #endif
 #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;
 layout(rgba16f, set = 0, binding = 0) uniform restrict writeonly image2D bokeh_image;
 #endif
 #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;
 layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
 #endif
 #endif
 
 
-
+// based on https://www.shadertoy.com/view/Xd3GDl
 
 
 
 
 layout(push_constant, binding = 1, std430) uniform Params {
 layout(push_constant, binding = 1, std430) uniform Params {
@@ -37,19 +36,27 @@ layout(push_constant, binding = 1, std430) uniform Params {
 	bool orthogonal;
 	bool orthogonal;
 	float blur_size;
 	float blur_size;
 	float blur_scale;
 	float blur_scale;
-	uint pad;
+	int blur_steps;
 
 
 	bool blur_near_active;
 	bool blur_near_active;
 	float blur_near_begin;
 	float blur_near_begin;
 	float blur_near_end;
 	float blur_near_end;
 	bool blur_far_active;
 	bool blur_far_active;
+
 	float blur_far_begin;
 	float blur_far_begin;
 	float blur_far_end;
 	float blur_far_end;
-	uint pad2[2];
+	bool second_pass;
+	bool half_size;
 
 
+	bool use_jitter;
+	float jitter_seed;
+	uint pad[2];
 } params;
 } 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 get_depth_at_pos(vec2 uv) {
 	float depth = textureLod(source_depth,uv,0.0).x;
 	float depth = textureLod(source_depth,uv,0.0).x;
@@ -61,14 +68,15 @@ float get_depth_at_pos(vec2 uv) {
 	return depth;
 	return depth;
 }
 }
 
 
+
 float get_blur_size(float depth) {
 float get_blur_size(float depth) {
 
 
 	if (params.blur_near_active && depth < params.blur_near_begin) {
 	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) {
 	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;
 	return 0.0;
@@ -78,6 +86,63 @@ float get_blur_size(float depth) {
 
 
 const float GOLDEN_ANGLE = 2.39996323;
 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() {
 void main() {
 
 
 	ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
 	ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
@@ -100,14 +165,61 @@ void main() {
 	imageStore(color_image,pos,color);
 	imageStore(color_image,pos,color);
 #endif
 #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
 	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);
 	vec4 color = texture(color_texture,uv);
 	float accum = 1.0;
 	float accum = 1.0;
 	float radius = params.blur_scale;
 	float radius = params.blur_scale;
@@ -116,12 +228,12 @@ void main() {
 
 
 		vec2 suv = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
 		vec2 suv = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
 		vec4 sample_color = texture(color_texture, suv);
 		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);
 		color += mix(color/accum, sample_color, m);
 		accum += 1.0;
 		accum += 1.0;
 		radius += params.blur_scale/radius;
 		radius += params.blur_scale/radius;
@@ -138,7 +250,14 @@ void main() {
 	vec4 color = imageLoad(color_image,pos);
 	vec4 color = imageLoad(color_image,pos);
 	vec4 bokeh = texture(source_bokeh,uv);
 	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
 	color.a=0; //reset alpha
 	imageStore(color_image,pos,color);
 	imageStore(color_image,pos,color);

+ 4 - 1
servers/visual/visual_server_raster.h

@@ -541,7 +541,10 @@ public:
 
 
 	BIND0R(RID, camera_effects_create)
 	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)
 	BIND3(camera_effects_set_custom_exposure, RID, bool, float)
 
 
 	/* SCENARIO API */
 	/* SCENARIO API */

+ 4 - 1
servers/visual/visual_server_wrap_mt.h

@@ -453,7 +453,10 @@ public:
 
 
 	FUNCRID(camera_effects)
 	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)
 	FUNC3(camera_effects_set_custom_exposure, RID, bool, float)
 
 
 	FUNCRID(scenario)
 	FUNCRID(scenario)

+ 8 - 2
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", 1);
 	GLOBAL_DEF("rendering/quality/shadows/filter_mode.mobile", 0);
 	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/roughness_layers", 6);
 	GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true);
 	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/anisotropic", false);
 	GLOBAL_DEF("rendering/quality/gi_probes/quality", 1);
 	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", false);
 	GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true);
 	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/use_nearest_mipmap_filter", false);
 	GLOBAL_DEF("rendering/quality/filters/max_anisotropy", 4);
 	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() {
 VisualServer::~VisualServer() {

+ 12 - 1
servers/visual_server.h

@@ -769,12 +769,23 @@ public:
 	virtual RID camera_effects_create() = 0;
 	virtual RID camera_effects_create() = 0;
 
 
 	enum DOFBlurQuality {
 	enum DOFBlurQuality {
+		DOF_BLUR_QUALITY_VERY_LOW,
 		DOF_BLUR_QUALITY_LOW,
 		DOF_BLUR_QUALITY_LOW,
 		DOF_BLUR_QUALITY_MEDIUM,
 		DOF_BLUR_QUALITY_MEDIUM,
 		DOF_BLUR_QUALITY_HIGH,
 		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;
 	virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
 
 
 	/* SCENARIO API */
 	/* SCENARIO API */