Kaynağa Gözat

Many fixes to SSAO, should be good now.

Juan Linietsky 7 yıl önce
ebeveyn
işleme
b4f0f59d9f

+ 46 - 0
core/command_queue_mt.h

@@ -227,6 +227,27 @@ class CommandQueueMT {
 		virtual void call() { (instance->*method)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); }
 	};
 
+	template <class T, class M, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>
+	struct Command12 : public CommandBase {
+
+		T *instance;
+		M method;
+		typename GetSimpleTypeT<P1>::type_t p1;
+		typename GetSimpleTypeT<P2>::type_t p2;
+		typename GetSimpleTypeT<P3>::type_t p3;
+		typename GetSimpleTypeT<P4>::type_t p4;
+		typename GetSimpleTypeT<P5>::type_t p5;
+		typename GetSimpleTypeT<P6>::type_t p6;
+		typename GetSimpleTypeT<P7>::type_t p7;
+		typename GetSimpleTypeT<P8>::type_t p8;
+		typename GetSimpleTypeT<P9>::type_t p9;
+		typename GetSimpleTypeT<P10>::type_t p10;
+		typename GetSimpleTypeT<P11>::type_t p11;
+		typename GetSimpleTypeT<P12>::type_t p12;
+
+		virtual void call() { (instance->*method)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); }
+	};
+
 	/* comands that return */
 
 	template <class T, class M, class R>
@@ -906,6 +927,31 @@ public:
 		if (sync) sync->post();
 	}
 
+	template <class T, class M, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>
+	void push(T *p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12) {
+
+		Command12<T, M, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12> *cmd = allocate_and_lock<Command12<T, M, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12> >();
+
+		cmd->instance = p_instance;
+		cmd->method = p_method;
+		cmd->p1 = p1;
+		cmd->p2 = p2;
+		cmd->p3 = p3;
+		cmd->p4 = p4;
+		cmd->p5 = p5;
+		cmd->p6 = p6;
+		cmd->p7 = p7;
+		cmd->p8 = p8;
+		cmd->p9 = p9;
+		cmd->p10 = p10;
+		cmd->p11 = p11;
+		cmd->p12 = p12;
+
+		unlock();
+
+		if (sync) sync->post();
+	}
+
 	/*** PUSH AND RET COMMANDS ***/
 
 	template <class T, class M, class R>

+ 19 - 7
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -895,7 +895,7 @@ void RasterizerSceneGLES3::environment_set_ssr(RID p_env, bool p_enable, int p_m
 	env->ssr_roughness = p_roughness;
 }
 
-void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, bool p_blur) {
+void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
 
 	Environment *env = environment_owner.getornull(p_env);
 	ERR_FAIL_COND(!env);
@@ -909,6 +909,8 @@ void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float
 	env->ssao_light_affect = p_light_affect;
 	env->ssao_color = p_color;
 	env->ssao_filter = p_blur;
+	env->ssao_quality = p_quality;
+	env->ssao_bilateral_sharpness = p_bilateral_sharpness;
 }
 
 void RasterizerSceneGLES3::environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
@@ -3186,6 +3188,15 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_
 	glDisable(GL_CULL_FACE);
 	glDisable(GL_BLEND);
 
+	if (env->ssao_enabled || env->ssr_enabled) {
+
+		//copy normal and roughness to effect buffer
+		glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
+		glReadBuffer(GL_COLOR_ATTACHMENT2);
+		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->buffers.effect_fbo);
+		glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+	}
+
 	if (env->ssao_enabled) {
 		//copy diffuse to front buffer
 		glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
@@ -3235,6 +3246,8 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_
 		// do SSAO!
 		state.ssao_shader.set_conditional(SsaoShaderGLES3::ENABLE_RADIUS2, env->ssao_radius2 > 0.001);
 		state.ssao_shader.set_conditional(SsaoShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal());
+		state.ssao_shader.set_conditional(SsaoShaderGLES3::SSAO_QUALITY_LOW, env->ssao_quality == VS::ENV_SSAO_QUALITY_LOW);
+		state.ssao_shader.set_conditional(SsaoShaderGLES3::SSAO_QUALITY_HIGH, env->ssao_quality == VS::ENV_SSAO_QUALITY_HIGH);
 		state.ssao_shader.bind();
 		state.ssao_shader.set_uniform(SsaoShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far());
 		state.ssao_shader.set_uniform(SsaoShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near());
@@ -3287,6 +3300,9 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_
 
 				state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far());
 				state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near());
+				state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::EDGE_SHARPNESS, env->ssao_bilateral_sharpness);
+				state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::FILTER_SCALE, int(env->ssao_filter));
+
 				GLint axis[2] = { i, 1 - i };
 				glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::AXIS), 1, axis);
 				glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::SCREEN_SIZE), 1, ss);
@@ -3295,6 +3311,8 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_
 				glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.blur_red[i]);
 				glActiveTexture(GL_TEXTURE1);
 				glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth);
+				glActiveTexture(GL_TEXTURE2);
+				glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.effect);
 				glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.blur_fbo[1 - i]);
 				if (i == 0) {
 					glClearBufferfv(GL_COLOR, 0, white.components); // specular
@@ -3386,12 +3404,6 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_
 
 	if (env->ssr_enabled) {
 
-		//copy normal and roughness to effect buffer
-		glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
-		glReadBuffer(GL_COLOR_ATTACHMENT2);
-		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->buffers.effect_fbo);
-		glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
-
 		//blur diffuse into effect mipmaps using separatable convolution
 		//storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true);
 		_blur_effect_buffer();

+ 7 - 3
drivers/gles3/rasterizer_scene_gles3.h

@@ -379,7 +379,9 @@ public:
 		float ssao_bias;
 		float ssao_light_affect;
 		Color ssao_color;
-		bool ssao_filter;
+		VS::EnvironmentSSAOQuality ssao_quality;
+		float ssao_bilateral_sharpness;
+		VS::EnvironmentSSAOBlur ssao_filter;
 
 		bool glow_enabled;
 		int glow_levels;
@@ -456,7 +458,9 @@ public:
 			ssao_radius2 = 0.0;
 			ssao_bias = 0.01;
 			ssao_light_affect = 0;
-			ssao_filter = true;
+			ssao_filter = VS::ENV_SSAO_BLUR_3x3;
+			ssao_quality = VS::ENV_SSAO_QUALITY_LOW;
+			ssao_bilateral_sharpness = 4;
 
 			tone_mapper = VS::ENV_TONE_MAPPER_LINEAR;
 			tone_mapper_exposure = 1.0;
@@ -532,7 +536,7 @@ public:
 	virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture);
 
 	virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness);
-	virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, bool p_blur);
+	virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
 
 	virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
 

+ 20 - 4
drivers/gles3/shaders/ssao.glsl

@@ -13,8 +13,24 @@ void main() {
 
 #define TWO_PI 6.283185307179586476925286766559
 
+#ifdef SSAO_QUALITY_HIGH
+
+#define NUM_SAMPLES (80)
+
+#endif
+
+#ifdef SSAO_QUALITY_LOW
+
 #define NUM_SAMPLES (15)
 
+#endif
+
+#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH)
+
+#define NUM_SAMPLES (40)
+
+#endif
+
 // If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower
 // miplevel to maintain reasonable spatial locality in the cache
 // If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing.
@@ -212,12 +228,12 @@ void main() {
 
 	//visibility=-C.z/camera_z_far;
 	//return;
-
-	//vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
-
+#if 0
+	vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
+#else
 	vec3 n_C = reconstructCSFaceNormal(C);
 	n_C = -n_C;
-
+#endif
 
 	// Hash function used in the HPG12 AlchemyAO paper
 	float randomPatternRotationAngle = mod(float((3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10), TWO_PI);

+ 13 - 7
drivers/gles3/shaders/ssao_blur.glsl

@@ -15,6 +15,7 @@ void main() {
 
 uniform sampler2D source_ssao; //texunit:0
 uniform sampler2D source_depth; //texunit:1
+uniform sampler2D source_normal; //texunit:3
 
 
 layout(location = 0) out float visibility;
@@ -24,7 +25,7 @@ layout(location = 0) out float visibility;
 // Tunable Parameters:
 
 /** Increase to make depth edges crisper. Decrease to reduce flicker. */
-#define EDGE_SHARPNESS     (4.0)
+uniform float edge_sharpness;
 
 /** Step in 2-pixel intervals since we already blurred against neighbors in the
     first AO pass.  This constant can be increased while R decreases to improve
@@ -34,7 +35,8 @@ layout(location = 0) out float visibility;
     unobjectionable after shading was applied but eliminated most temporal incoherence
     from using small numbers of sample taps.
     */
-#define SCALE               (3)
+
+uniform int filter_scale;
 
 /** Filter radius in pixels. This will be multiplied by SCALE. */
 #define R                   (4)
@@ -63,13 +65,14 @@ void main() {
 	ivec2 ssC = ivec2(gl_FragCoord.xy);
 
 	float depth = texelFetch(source_depth, ssC, 0).r;
+	//vec3 normal = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
 
 	depth = depth * 2.0 - 1.0;
 	depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
 
 	float depth_divide = 1.0 / camera_z_far;
 
-	depth*=depth_divide;
+//	depth*=depth_divide;
 
 	/*
 	if (depth > camera_z_far*0.999) {
@@ -92,20 +95,23 @@ void main() {
 		// so the IF statement has no runtime cost
 		if (r != 0) {
 
-			ivec2 ppos = ssC + axis * (r * SCALE);
+			ivec2 ppos = ssC + axis * (r * filter_scale);
 			float value = texelFetch(source_ssao, clamp(ppos,ivec2(0),clamp_limit), 0).r;
-			float temp_depth = texelFetch(source_depth, clamp(ssC,ivec2(0),clamp_limit), 0).r;
+			ivec2 rpos = clamp(ppos,ivec2(0),clamp_limit);
+			float temp_depth = texelFetch(source_depth, rpos, 0).r;
+			//vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0;
 
 			temp_depth = temp_depth * 2.0 - 1.0;
 			temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near));
-			temp_depth *= depth_divide;
+//			temp_depth *= depth_divide;
 
 			// spatial domain: offset gaussian tap
 			float weight = 0.3 + gaussian[abs(r)];
+			//weight *= max(0.0,dot(temp_normal,normal));
 
 			// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
 			weight *= max(0.0, 1.0
-				      - (EDGE_SHARPNESS * 2000.0) * abs(temp_depth - depth)
+				      - edge_sharpness * abs(temp_depth - depth)
 				      );
 
 			sum += value * weight;

+ 52 - 16
scene/resources/environment.cpp

@@ -377,7 +377,7 @@ bool Environment::is_ssr_rough() const {
 void Environment::set_ssao_enabled(bool p_enable) {
 
 	ssao_enabled = p_enable;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 	_change_notify();
 }
 
@@ -389,7 +389,7 @@ bool Environment::is_ssao_enabled() const {
 void Environment::set_ssao_radius(float p_radius) {
 
 	ssao_radius = p_radius;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
 float Environment::get_ssao_radius() const {
 
@@ -399,7 +399,7 @@ float Environment::get_ssao_radius() const {
 void Environment::set_ssao_intensity(float p_intensity) {
 
 	ssao_intensity = p_intensity;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
 
 float Environment::get_ssao_intensity() const {
@@ -410,7 +410,7 @@ float Environment::get_ssao_intensity() const {
 void Environment::set_ssao_radius2(float p_radius) {
 
 	ssao_radius2 = p_radius;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
 float Environment::get_ssao_radius2() const {
 
@@ -420,7 +420,7 @@ float Environment::get_ssao_radius2() const {
 void Environment::set_ssao_intensity2(float p_intensity) {
 
 	ssao_intensity2 = p_intensity;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
 float Environment::get_ssao_intensity2() const {
 
@@ -430,7 +430,7 @@ float Environment::get_ssao_intensity2() const {
 void Environment::set_ssao_bias(float p_bias) {
 
 	ssao_bias = p_bias;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
 float Environment::get_ssao_bias() const {
 
@@ -440,7 +440,7 @@ float Environment::get_ssao_bias() const {
 void Environment::set_ssao_direct_light_affect(float p_direct_light_affect) {
 
 	ssao_direct_light_affect = p_direct_light_affect;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
 float Environment::get_ssao_direct_light_affect() const {
 
@@ -450,7 +450,7 @@ float Environment::get_ssao_direct_light_affect() const {
 void Environment::set_ssao_color(const Color &p_color) {
 
 	ssao_color = p_color;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
 
 Color Environment::get_ssao_color() const {
@@ -458,16 +458,38 @@ Color Environment::get_ssao_color() const {
 	return ssao_color;
 }
 
-void Environment::set_ssao_blur(bool p_enable) {
+void Environment::set_ssao_blur(SSAOBlur p_blur) {
 
-	ssao_blur = p_enable;
-	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, ssao_blur);
+	ssao_blur = p_blur;
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
 }
-bool Environment::is_ssao_blur_enabled() const {
+Environment::SSAOBlur Environment::get_ssao_blur() const {
 
 	return ssao_blur;
 }
 
+void Environment::set_ssao_quality(SSAOQuality p_quality) {
+
+	ssao_quality = p_quality;
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+}
+
+Environment::SSAOQuality Environment::get_ssao_quality() const {
+
+	return ssao_quality;
+}
+
+void Environment::set_ssao_edge_sharpness(float p_edge_sharpness) {
+
+	ssao_edge_sharpness = p_edge_sharpness;
+	VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+}
+
+float Environment::get_ssao_edge_sharpness() const {
+
+	return ssao_edge_sharpness;
+}
+
 void Environment::set_glow_enabled(bool p_enabled) {
 
 	glow_enabled = p_enabled;
@@ -988,8 +1010,14 @@ void Environment::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_ssao_color", "color"), &Environment::set_ssao_color);
 	ClassDB::bind_method(D_METHOD("get_ssao_color"), &Environment::get_ssao_color);
 
-	ClassDB::bind_method(D_METHOD("set_ssao_blur", "enabled"), &Environment::set_ssao_blur);
-	ClassDB::bind_method(D_METHOD("is_ssao_blur_enabled"), &Environment::is_ssao_blur_enabled);
+	ClassDB::bind_method(D_METHOD("set_ssao_blur", "mode"), &Environment::set_ssao_blur);
+	ClassDB::bind_method(D_METHOD("get_ssao_blur"), &Environment::get_ssao_blur);
+
+	ClassDB::bind_method(D_METHOD("set_ssao_quality", "quality"), &Environment::set_ssao_quality);
+	ClassDB::bind_method(D_METHOD("get_ssao_quality"), &Environment::get_ssao_quality);
+
+	ClassDB::bind_method(D_METHOD("set_ssao_edge_sharpness", "edge_sharpness"), &Environment::set_ssao_edge_sharpness);
+	ClassDB::bind_method(D_METHOD("get_ssao_edge_sharpness"), &Environment::get_ssao_edge_sharpness);
 
 	ADD_GROUP("SSAO", "ssao_");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssao_enabled"), "set_ssao_enabled", "is_ssao_enabled");
@@ -1000,7 +1028,9 @@ void Environment::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_bias", PROPERTY_HINT_RANGE, "0.001,8,0.001"), "set_ssao_bias", "get_ssao_bias");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_light_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_direct_light_affect", "get_ssao_direct_light_affect");
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ssao_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ssao_color", "get_ssao_color");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssao_blur"), "set_ssao_blur", "is_ssao_blur_enabled");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "ssao_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_ssao_quality", "get_ssao_quality");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "ssao_blur", PROPERTY_HINT_ENUM, "Disabled,1x1,2x2,3x3"), "set_ssao_blur", "get_ssao_blur");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_edge_sharpness", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_ssao_edge_sharpness", "get_ssao_edge_sharpness");
 
 	ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &Environment::set_dof_blur_far_enabled);
 	ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &Environment::is_dof_blur_far_enabled);
@@ -1134,6 +1164,10 @@ void Environment::_bind_methods() {
 	BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_LOW);
 	BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_MEDIUM);
 	BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_HIGH);
+
+	BIND_ENUM_CONSTANT(SSAO_QUALITY_LOW);
+	BIND_ENUM_CONSTANT(SSAO_QUALITY_MEDIUM);
+	BIND_ENUM_CONSTANT(SSAO_QUALITY_HIGH);
 }
 
 Environment::Environment() {
@@ -1179,7 +1213,9 @@ Environment::Environment() {
 	ssao_intensity2 = 1;
 	ssao_bias = 0.01;
 	ssao_direct_light_affect = false;
-	ssao_blur = true;
+	ssao_blur = SSAO_BLUR_3x3;
+	set_ssao_edge_sharpness(4);
+	set_ssao_quality(SSAO_QUALITY_LOW);
 
 	glow_enabled = false;
 	glow_levels = (1 << 2) | (1 << 4);

+ 26 - 3
scene/resources/environment.h

@@ -71,6 +71,19 @@ public:
 		DOF_BLUR_QUALITY_HIGH,
 	};
 
+	enum SSAOBlur {
+		SSAO_BLUR_DISABLED,
+		SSAO_BLUR_1x1,
+		SSAO_BLUR_2x2,
+		SSAO_BLUR_3x3
+	};
+
+	enum SSAOQuality {
+		SSAO_QUALITY_LOW,
+		SSAO_QUALITY_MEDIUM,
+		SSAO_QUALITY_HIGH
+	};
+
 private:
 	RID environment;
 
@@ -114,7 +127,9 @@ private:
 	float ssao_bias;
 	float ssao_direct_light_affect;
 	Color ssao_color;
-	bool ssao_blur;
+	SSAOBlur ssao_blur;
+	float ssao_edge_sharpness;
+	SSAOQuality ssao_quality;
 
 	bool glow_enabled;
 	int glow_levels;
@@ -261,8 +276,14 @@ public:
 	void set_ssao_color(const Color &p_color);
 	Color get_ssao_color() const;
 
-	void set_ssao_blur(bool p_enable);
-	bool is_ssao_blur_enabled() const;
+	void set_ssao_blur(SSAOBlur p_blur);
+	SSAOBlur get_ssao_blur() const;
+
+	void set_ssao_quality(SSAOQuality p_quality);
+	SSAOQuality get_ssao_quality() const;
+
+	void set_ssao_edge_sharpness(float p_edge_sharpness);
+	float get_ssao_edge_sharpness() const;
 
 	void set_glow_enabled(bool p_enabled);
 	bool is_glow_enabled() const;
@@ -370,5 +391,7 @@ VARIANT_ENUM_CAST(Environment::BGMode)
 VARIANT_ENUM_CAST(Environment::ToneMapper)
 VARIANT_ENUM_CAST(Environment::GlowBlendMode)
 VARIANT_ENUM_CAST(Environment::DOFBlurQuality)
+VARIANT_ENUM_CAST(Environment::SSAOQuality)
+VARIANT_ENUM_CAST(Environment::SSAOBlur)
 
 #endif // ENVIRONMENT_H

+ 9 - 0
servers/server_wrap_mt_common.h

@@ -775,3 +775,12 @@
 			server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);                                                                         \
 		}                                                                                                                                              \
 	}
+
+#define FUNC12(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12)                                           \
+	virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12) { \
+		if (Thread::get_caller_id() != server_thread) {                                                                                                             \
+			command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12);                                                \
+		} else {                                                                                                                                                    \
+			server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12);                                                                                 \
+		}                                                                                                                                                           \
+	}

+ 1 - 1
servers/visual/rasterizer.h

@@ -65,7 +65,7 @@ public:
 	virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0;
 
 	virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) = 0;
-	virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, bool p_blur) = 0;
+	virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0;
 
 	virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0;
 

+ 3 - 1
servers/visual/visual_server_raster.h

@@ -652,6 +652,8 @@ public:
 	void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); }
 #define BIND11(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11) \
 	void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); }
+#define BIND12(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12) \
+	void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); }
 
 //from now on, calls forwarded to this singleton
 #define BINDBASE VSG::storage
@@ -974,7 +976,7 @@ public:
 	BIND2(environment_set_canvas_max_layer, RID, int)
 	BIND4(environment_set_ambient_light, RID, const Color &, float, float)
 	BIND7(environment_set_ssr, RID, bool, int, float, float, float, bool)
-	BIND10(environment_set_ssao, RID, bool, float, float, float, float, float, float, const Color &, bool)
+	BIND12(environment_set_ssao, RID, bool, float, float, float, float, float, float, const Color &, EnvironmentSSAOQuality, EnvironmentSSAOBlur, float)
 
 	BIND6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality)
 	BIND6(environment_set_dof_blur_far, RID, bool, float, float, float, EnvironmentDOFBlurQuality)

+ 1 - 1
servers/visual/visual_server_wrap_mt.h

@@ -387,7 +387,7 @@ public:
 	FUNC2(environment_set_canvas_max_layer, RID, int)
 	FUNC4(environment_set_ambient_light, RID, const Color &, float, float)
 	FUNC7(environment_set_ssr, RID, bool, int, float, float, float, bool)
-	FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, const Color &, bool)
+	FUNC12(environment_set_ssao, RID, bool, float, float, float, float, float, float, const Color &, EnvironmentSSAOQuality, EnvironmentSSAOBlur, float)
 
 	FUNC6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality)
 	FUNC6(environment_set_dof_blur_far, RID, bool, float, float, float, EnvironmentDOFBlurQuality)

+ 15 - 1
servers/visual_server.h

@@ -678,7 +678,21 @@ public:
 	virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
 
 	virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness) = 0;
-	virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, bool p_blur) = 0;
+
+	enum EnvironmentSSAOQuality {
+		ENV_SSAO_QUALITY_LOW,
+		ENV_SSAO_QUALITY_MEDIUM,
+		ENV_SSAO_QUALITY_HIGH,
+	};
+
+	enum EnvironmentSSAOBlur {
+		ENV_SSAO_BLUR_DISABLED,
+		ENV_SSAO_BLUR_1x1,
+		ENV_SSAO_BLUR_2x2,
+		ENV_SSAO_BLUR_3x3,
+	};
+
+	virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, EnvironmentSSAOQuality p_quality, EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0;
 
 	virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0;
 	virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0;