You've already forked godot
							
							
				mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-03 11:50:27 +00:00 
			
		
		
		
	Implemented a very simple SSAO in GLES3.
This commit is contained in:
		@@ -87,7 +87,11 @@ void PostEffects::_draw_screen_triangle() {
 | 
			
		||||
	glBindVertexArray(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, float p_srgb_white, uint32_t p_view, bool p_use_multiview, uint64_t p_spec_constants) {
 | 
			
		||||
void PostEffects::post_copy(
 | 
			
		||||
		GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color,
 | 
			
		||||
		GLuint p_source_depth, bool p_ssao_enabled, int p_ssao_quality_level, float p_ssao_strength, float p_ssao_radius,
 | 
			
		||||
		Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity,
 | 
			
		||||
		float p_srgb_white, uint32_t p_view, bool p_use_multiview, uint64_t p_spec_constants) {
 | 
			
		||||
	glDisable(GL_DEPTH_TEST);
 | 
			
		||||
	glDepthMask(GL_FALSE);
 | 
			
		||||
	glDisable(GL_BLEND);
 | 
			
		||||
@@ -103,6 +107,19 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin
 | 
			
		||||
	if (p_glow_buffers != nullptr) {
 | 
			
		||||
		flags |= PostShaderGLES3::USE_GLOW;
 | 
			
		||||
	}
 | 
			
		||||
	if (p_ssao_enabled) {
 | 
			
		||||
		if (p_ssao_quality_level == RS::ENV_SSAO_QUALITY_VERY_LOW) {
 | 
			
		||||
			flags |= PostShaderGLES3::USE_SSAO_ABYSS;
 | 
			
		||||
		} else if (p_ssao_quality_level == RS::ENV_SSAO_QUALITY_LOW) {
 | 
			
		||||
			flags |= PostShaderGLES3::USE_SSAO_LOW;
 | 
			
		||||
		} else if (p_ssao_quality_level == RS::ENV_SSAO_QUALITY_HIGH) {
 | 
			
		||||
			flags |= PostShaderGLES3::USE_SSAO_HIGH;
 | 
			
		||||
		} else if (p_ssao_quality_level == RS::ENV_SSAO_QUALITY_ULTRA) {
 | 
			
		||||
			flags |= PostShaderGLES3::USE_SSAO_MEGA;
 | 
			
		||||
		} else {
 | 
			
		||||
			flags |= PostShaderGLES3::USE_SSAO_MED;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (p_luminance_multiplier != 1.0) {
 | 
			
		||||
		flags |= PostShaderGLES3::USE_LUMINANCE_MULTIPLIER;
 | 
			
		||||
	}
 | 
			
		||||
@@ -118,6 +135,20 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin
 | 
			
		||||
	glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
			
		||||
	glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
			
		||||
 | 
			
		||||
	if (p_ssao_enabled) {
 | 
			
		||||
		glActiveTexture(GL_TEXTURE3);
 | 
			
		||||
		glBindTexture(texture_target, p_source_depth);
 | 
			
		||||
		glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Thanks to mrjustaguy!
 | 
			
		||||
		glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
			
		||||
 | 
			
		||||
		post.shader.version_set_uniform(PostShaderGLES3::SSAO_INTENSITY, p_ssao_strength, post.shader_version, mode, flags);
 | 
			
		||||
		post.shader.version_set_uniform(PostShaderGLES3::SSAO_RADIUS_FRAC, p_ssao_radius, post.shader_version, mode, flags);
 | 
			
		||||
		post.shader.version_set_uniform(PostShaderGLES3::SSAO_PRN_UV, // This converts the UV coordinate into a pseudo-random number.
 | 
			
		||||
				p_source_size.x * 1.087f * ((1.0f + sqrt(5.0f)) / 2.0f),
 | 
			
		||||
				p_source_size.y * 1.087f * ((9.0f + sqrt(221.0f)) / 10.0f),
 | 
			
		||||
				post.shader_version, mode, flags);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (p_glow_buffers != nullptr) {
 | 
			
		||||
		glActiveTexture(GL_TEXTURE1);
 | 
			
		||||
		glBindTexture(GL_TEXTURE_2D, p_glow_buffers[0].color);
 | 
			
		||||
@@ -137,6 +168,10 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin
 | 
			
		||||
		glActiveTexture(GL_TEXTURE1);
 | 
			
		||||
		glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
	}
 | 
			
		||||
	if (p_ssao_enabled) {
 | 
			
		||||
		glActiveTexture(GL_TEXTURE3);
 | 
			
		||||
		glBindTexture(texture_target, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Return back to nearest
 | 
			
		||||
	glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,10 @@ public:
 | 
			
		||||
	PostEffects();
 | 
			
		||||
	~PostEffects();
 | 
			
		||||
 | 
			
		||||
	void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, float p_srgb_white, uint32_t p_view = 0, bool p_use_multiview = false, uint64_t p_spec_constants = 0);
 | 
			
		||||
	void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color,
 | 
			
		||||
			GLuint p_source_depth, bool p_ssao_enabled, int p_ssao_quality_level, float p_ssao_strength, float p_ssao_radius,
 | 
			
		||||
			Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity,
 | 
			
		||||
			float p_srgb_white, uint32_t p_view = 0, bool p_use_multiview = false, uint64_t p_spec_constants = 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} //namespace GLES3
 | 
			
		||||
 
 | 
			
		||||
@@ -1114,6 +1114,7 @@ void RasterizerSceneGLES3::environment_set_ssr_roughness_quality(RS::Environment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerSceneGLES3::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
 | 
			
		||||
	ssao_quality = p_quality;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerSceneGLES3::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
 | 
			
		||||
@@ -2275,6 +2276,15 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool ssao_enabled = false;
 | 
			
		||||
	if (p_environment.is_valid()) {
 | 
			
		||||
		ssao_enabled = environment_get_ssao_enabled(p_environment);
 | 
			
		||||
		if (ssao_enabled) {
 | 
			
		||||
			// If SSAO is enabled, we apply tonemapping etc. in post, so disable it during rendering
 | 
			
		||||
			apply_color_adjustments_in_post = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Assign render data
 | 
			
		||||
	// Use the format from rendererRD
 | 
			
		||||
	RenderDataGLES3 render_data;
 | 
			
		||||
@@ -2552,6 +2562,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 | 
			
		||||
	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 | 
			
		||||
	glViewport(0, 0, rb->internal_size.x, rb->internal_size.y);
 | 
			
		||||
 | 
			
		||||
	// If SSAO is enabled, we definitely need the depth buffer.
 | 
			
		||||
	if (ssao_enabled) {
 | 
			
		||||
		scene_state.used_depth_texture = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Do depth prepass if it's explicitly enabled
 | 
			
		||||
	bool use_depth_prepass = config->use_depth_prepass;
 | 
			
		||||
 | 
			
		||||
@@ -2835,6 +2850,18 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
 | 
			
		||||
		rb->check_glow_buffers();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if we want and can have SSAO.
 | 
			
		||||
	bool ssao_enabled = false;
 | 
			
		||||
	float ssao_strength = 4.0;
 | 
			
		||||
	float ssao_radius = 0.5;
 | 
			
		||||
	if (p_render_data->environment.is_valid()) {
 | 
			
		||||
		ssao_enabled = environment_get_ssao_enabled(p_render_data->environment);
 | 
			
		||||
		// This SSAO is not implemented the same way, but uses the intensity and radius
 | 
			
		||||
		// in a similar way.  The parameters are scaled so the SSAO defaults look ok.
 | 
			
		||||
		ssao_strength = environment_get_ssao_intensity(p_render_data->environment) * 2.0;
 | 
			
		||||
		ssao_radius = environment_get_ssao_radius(p_render_data->environment) * 0.5;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint64_t bcs_spec_constants = 0;
 | 
			
		||||
	if (p_render_data->environment.is_valid()) {
 | 
			
		||||
		bool use_bcs = environment_get_adjustments_enabled(p_render_data->environment);
 | 
			
		||||
@@ -2882,6 +2909,10 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
 | 
			
		||||
		if (fbo_int != 0) {
 | 
			
		||||
			// Apply glow/bloom if requested? then populate our glow buffers
 | 
			
		||||
			GLuint color = fbo_int != 0 ? rb->get_internal_color() : texture_storage->render_target_get_color(render_target);
 | 
			
		||||
 | 
			
		||||
			// We need to pass this in for SSAO.
 | 
			
		||||
			GLuint depth_buffer = fbo_int != 0 ? rb->get_internal_depth() : texture_storage->render_target_get_depth(render_target);
 | 
			
		||||
 | 
			
		||||
			const GLES3::Glow::GLOWLEVEL *glow_buffers = nullptr;
 | 
			
		||||
			if (glow_enabled) {
 | 
			
		||||
				glow_buffers = rb->get_glow_buffers();
 | 
			
		||||
@@ -2898,7 +2929,10 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Copy color buffer
 | 
			
		||||
			post_effects->post_copy(fbo_rt, target_size, color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, srgb_white, 0, false, bcs_spec_constants);
 | 
			
		||||
			post_effects->post_copy(fbo_rt, target_size, color,
 | 
			
		||||
					depth_buffer, ssao_enabled, ssao_quality, ssao_strength, ssao_radius,
 | 
			
		||||
					internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity,
 | 
			
		||||
					srgb_white, 0, false, bcs_spec_constants);
 | 
			
		||||
 | 
			
		||||
			// Copy depth buffer
 | 
			
		||||
			glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_int);
 | 
			
		||||
@@ -2945,6 +2979,9 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
 | 
			
		||||
			const GLES3::Glow::GLOWLEVEL *glow_buffers = nullptr;
 | 
			
		||||
			GLuint source_color = fbo_int != 0 ? rb->get_internal_color() : texture_storage->render_target_get_color(render_target);
 | 
			
		||||
 | 
			
		||||
			// Moved this up so SSAO could use it too.
 | 
			
		||||
			GLuint read_depth = rb->get_internal_depth();
 | 
			
		||||
 | 
			
		||||
			if (glow_enabled) {
 | 
			
		||||
				glow_buffers = rb->get_glow_buffers();
 | 
			
		||||
 | 
			
		||||
@@ -2966,11 +3003,13 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
 | 
			
		||||
 | 
			
		||||
				glBindFramebuffer(GL_FRAMEBUFFER, fbos[2]);
 | 
			
		||||
				glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
 | 
			
		||||
				post_effects->post_copy(fbos[2], target_size, source_color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, srgb_white, v, true, bcs_spec_constants);
 | 
			
		||||
				post_effects->post_copy(fbos[2], target_size, source_color,
 | 
			
		||||
						read_depth, ssao_enabled, ssao_quality, ssao_strength, ssao_radius,
 | 
			
		||||
						internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity,
 | 
			
		||||
						srgb_white, v, true, bcs_spec_constants);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Copy depth
 | 
			
		||||
			GLuint read_depth = rb->get_internal_depth();
 | 
			
		||||
			GLuint write_depth = texture_storage->render_target_get_depth(render_target);
 | 
			
		||||
 | 
			
		||||
			glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,11 @@ USE_LUMINANCE_MULTIPLIER = false
 | 
			
		||||
USE_BCS = false
 | 
			
		||||
USE_COLOR_CORRECTION = false
 | 
			
		||||
USE_1D_LUT = false
 | 
			
		||||
USE_SSAO_ABYSS = false
 | 
			
		||||
USE_SSAO_LOW = false
 | 
			
		||||
USE_SSAO_MED = false
 | 
			
		||||
USE_SSAO_HIGH = false
 | 
			
		||||
USE_SSAO_MEGA = false
 | 
			
		||||
 | 
			
		||||
#[vertex]
 | 
			
		||||
layout(location = 0) in vec2 vertex_attrib;
 | 
			
		||||
@@ -86,6 +91,29 @@ vec3 apply_color_correction(vec3 color) {
 | 
			
		||||
#endif // USE_1D_LUT
 | 
			
		||||
#endif // USE_COLOR_CORRECTION
 | 
			
		||||
 | 
			
		||||
#if defined(USE_SSAO_ABYSS) || defined(USE_SSAO_LOW) || defined(USE_SSAO_MED) || defined(USE_SSAO_HIGH) || defined(USE_SSAO_MEGA)
 | 
			
		||||
#define USE_SOME_SSAO
 | 
			
		||||
uniform float ssao_intensity;
 | 
			
		||||
uniform float ssao_radius_frac;
 | 
			
		||||
uniform vec2 ssao_prn_UV;
 | 
			
		||||
#ifdef USE_MULTIVIEW
 | 
			
		||||
// VR will have 2 depth buffers.
 | 
			
		||||
uniform sampler2DArray depth_buffer_array; // texunit:3
 | 
			
		||||
#else
 | 
			
		||||
uniform sampler2D depth_buffer; // texunit:3
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(USE_SSAO_ABYSS)
 | 
			
		||||
// Use the tiny 2-sample version.
 | 
			
		||||
#include "../s4ao_micro_inc.glsl"
 | 
			
		||||
#elif defined(USE_SSAO_HIGH) || defined(USE_SSAO_MEGA)
 | 
			
		||||
// Use the rings version for the higher qualities.
 | 
			
		||||
#include "../s4ao_mega_inc.glsl"
 | 
			
		||||
#else
 | 
			
		||||
// Use the more generic NxN grid version.
 | 
			
		||||
#include "../s4ao_inc.glsl"
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
in vec2 uv_interp;
 | 
			
		||||
 | 
			
		||||
layout(location = 0) out vec4 frag_color;
 | 
			
		||||
@@ -131,6 +159,11 @@ void main() {
 | 
			
		||||
 | 
			
		||||
	color.rgb = srgb_to_linear(color.rgb);
 | 
			
		||||
 | 
			
		||||
#if defined(USE_SOME_SSAO)
 | 
			
		||||
	// Putting SSAO after the conversion to linear color, though it might be better before the glow.
 | 
			
		||||
	color.rgb *= s4ao(uv_interp); // The USE_SSAO_X controls the number of samples.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	color.rgb = apply_tonemapping(color.rgb, white);
 | 
			
		||||
 | 
			
		||||
#ifdef USE_BCS
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								drivers/gles3/shaders/s4ao_inc.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								drivers/gles3/shaders/s4ao_inc.glsl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
// S4AO (Stupid Simple Screen Space Ambient Occlusion) - Jonathan Dummer (O1S)
 | 
			
		||||
 | 
			
		||||
// The sample_width should be even, else the midpoint is at UV.
 | 
			
		||||
// Takes sample_width^2 samples in a grid, with the corners notched.
 | 
			
		||||
#if defined(USE_SSAO_LOW)
 | 
			
		||||
const int sample_width = 2;
 | 
			
		||||
#elif defined(USE_SSAO_HIGH)
 | 
			
		||||
const int sample_width = 6;
 | 
			
		||||
#else
 | 
			
		||||
const int sample_width = 4;
 | 
			
		||||
#endif
 | 
			
		||||
const int notch_01 = int(sample_width > 3); // Set to 1 to skip the corner samples, 0 to include them.
 | 
			
		||||
const float sample_mid = (float(sample_width) - 1.0) * 0.50001; // Can't be exactly 0.5 in case sample_width is odd.
 | 
			
		||||
#if defined(USE_SSAO_LOW)
 | 
			
		||||
const float inv_half_width = 1.0 / sample_mid; // The 2x2 sampling looks wider as all samples are at radius.
 | 
			
		||||
#else
 | 
			
		||||
const float inv_half_width = 1.7 / sample_mid; // Bake in the 1.7 scale for the random rotation.
 | 
			
		||||
#endif
 | 
			
		||||
const float average_samples = 1.0 / float(sample_width * sample_width - 4 * notch_01); //  1 / number_of_samples
 | 
			
		||||
const float ssao_falloff_frac = 0.25;
 | 
			
		||||
// Perform the SSAO.
 | 
			
		||||
float s4ao(vec2 UV) {
 | 
			
		||||
#ifdef USE_MULTIVIEW
 | 
			
		||||
	float depth = texture(depth_buffer_array, vec3(UV, view)).r;
 | 
			
		||||
#else
 | 
			
		||||
	float depth = texture(depth_buffer, UV).r;
 | 
			
		||||
#endif
 | 
			
		||||
	float radius = max(1e-4f, depth * ssao_radius_frac);
 | 
			
		||||
	float inv_falloff = 1.0f / max(1e-4f, depth * ssao_falloff_frac);
 | 
			
		||||
	// Random 2D rotation per pixel (+/-45 deg, with 0 having a lower probability).
 | 
			
		||||
	// The random cosine vector is vec2( 0.5, -0.5 to +0.5 ) and *1.7 makes the average length ~ 1.
 | 
			
		||||
	vec2 rcos = (inv_half_width * radius) * vec2(0.5f, fract(dot(UV, ssao_prn_UV)) - 0.5f);
 | 
			
		||||
	vec2 rsin = rcos.yx * vec2(-1, 1); // Perpendicular to the random cosine vector.
 | 
			
		||||
	// Grab the samples and determine the occlusion.
 | 
			
		||||
	float occlusion = 0.0f;
 | 
			
		||||
	vec2 base_duv = -sample_mid * rsin;
 | 
			
		||||
	for (int j = sample_width; --j >= 0;) {
 | 
			
		||||
#if defined(USE_SSAO_LOW)
 | 
			
		||||
		// Low quality uses 2x2 samples, no notching.
 | 
			
		||||
		vec2 duv = -sample_mid * rcos + base_duv;
 | 
			
		||||
		for (int i = sample_width; --i >= 0;) {
 | 
			
		||||
#else
 | 
			
		||||
		//	Will uses 4x4 or 6x6 samples, with the corners notched out.
 | 
			
		||||
		int o = /*notch_01 &*/ int((j <= 0) || (j >= (sample_width - 1))); // Notch corners of the grid.
 | 
			
		||||
		vec2 duv = (float(o) - sample_mid) * rcos + base_duv;
 | 
			
		||||
		for (int i = sample_width - o - o; --i >= 0;) {
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_MULTIVIEW
 | 
			
		||||
			float dz = texture(depth_buffer_array, vec3(UV + duv, view)).r - depth;
 | 
			
		||||
#else
 | 
			
		||||
			float dz = texture(depth_buffer, UV + duv).r - depth;
 | 
			
		||||
#endif
 | 
			
		||||
			float validity = smoothstep(1.0f, 0.0f, dz * inv_falloff);
 | 
			
		||||
			occlusion += normalize(vec3(duv, dz)).z * validity; // How 'directly overhead' is it?
 | 
			
		||||
			duv += rcos; // March along the rcos direction with i.
 | 
			
		||||
		}
 | 
			
		||||
		base_duv += rsin; // March along the rsin direction with j.
 | 
			
		||||
	}
 | 
			
		||||
	// Adjust the occlusion for intensity, and # samples.
 | 
			
		||||
	occlusion *= ssao_intensity * average_samples;
 | 
			
		||||
	occlusion = clamp(1.0f - occlusion, 0.0f, 1.0f);
 | 
			
		||||
	return occlusion * occlusion;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								drivers/gles3/shaders/s4ao_mega_inc.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								drivers/gles3/shaders/s4ao_mega_inc.glsl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
// S4AO (Stupid Simple Screen Space Ambient Occlusion) - Jonathan Dummer (O1S)
 | 
			
		||||
// The mega version uses N concentric rings of samples.
 | 
			
		||||
 | 
			
		||||
#if defined(USE_SSAO_MEGA)
 | 
			
		||||
const int rings = 4; // Start with the outer ring.
 | 
			
		||||
const int samps[] = int[](24, 18, 12, 6); // ( 9, 6, 3 ) is a minimum, but I want better.
 | 
			
		||||
#else
 | 
			
		||||
const int rings = 3; // Start with the outer ring.
 | 
			
		||||
const int samps[] = int[](15, 10, 5, 1); // ( 9, 6, 3 ) is a minimum, but I want better.
 | 
			
		||||
#endif
 | 
			
		||||
const float average_samples = 1.0 / float(samps[0] + samps[1] * int(rings > 1) + samps[2] * int(rings > 2) + samps[3] * int(rings > 3));
 | 
			
		||||
const float ssao_falloff_frac = 0.25;
 | 
			
		||||
// Perform the SSAO.
 | 
			
		||||
float s4ao(vec2 UV) {
 | 
			
		||||
#ifdef USE_MULTIVIEW
 | 
			
		||||
	float depth = texture(depth_buffer_array, vec3(UV, view)).r;
 | 
			
		||||
#else
 | 
			
		||||
	float depth = texture(depth_buffer, UV).r;
 | 
			
		||||
#endif
 | 
			
		||||
	float inv_falloff = 1.0f / max(1e-4f, depth * ssao_falloff_frac);
 | 
			
		||||
	// Random 2D rotation per pixel (0..1 -> parabola approximating a 180 deg arc)
 | 
			
		||||
	float r01 = fract(dot(UV, ssao_prn_UV));
 | 
			
		||||
	vec2 rcos = vec2(r01 - 0.5f, 2.0f * (r01 - r01 * r01)) * (2.0f * depth * ssao_radius_frac); // 180 degrees.
 | 
			
		||||
	vec2 rsin = rcos.yx * vec2(-1, 1); // Perpendicular to the random cosine vector.
 | 
			
		||||
	// Grab the samples and determine the occlusion.
 | 
			
		||||
	float occlusion = 0.0f;
 | 
			
		||||
	float ring_shrink = 0.75f; // Shrink every ring.
 | 
			
		||||
	for (int r = 0; r < rings; ++r) {
 | 
			
		||||
		float dt = (6.283185307f) / float(samps[r]);
 | 
			
		||||
		float t = float(r & 1) * 0.5f * dt;
 | 
			
		||||
		for (int s = 0; s < samps[r]; ++s) {
 | 
			
		||||
			vec2 duv = cos(t) * rcos + sin(t) * rsin;
 | 
			
		||||
#ifdef USE_MULTIVIEW
 | 
			
		||||
			float dz = texture(depth_buffer_array, vec3(UV + duv, view)).r - depth;
 | 
			
		||||
#else
 | 
			
		||||
			float dz = texture(depth_buffer, UV + duv).r - depth;
 | 
			
		||||
#endif
 | 
			
		||||
			// How 'directly overhead' is it?  Factor in the falloff depth.
 | 
			
		||||
			occlusion += normalize(vec3(duv, dz)).z * smoothstep(1.0f, 0.0f, dz * inv_falloff);
 | 
			
		||||
			t += dt;
 | 
			
		||||
		}
 | 
			
		||||
		// The next ring will be smaller.
 | 
			
		||||
		rcos *= ring_shrink;
 | 
			
		||||
		rsin *= ring_shrink;
 | 
			
		||||
	}
 | 
			
		||||
	// Adjust the occlusion for intensity, and # samples.
 | 
			
		||||
	occlusion *= ssao_intensity * average_samples;
 | 
			
		||||
	occlusion = 1.0f - clamp(occlusion, 0.0f, 1.0f);
 | 
			
		||||
	return occlusion * occlusion;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								drivers/gles3/shaders/s4ao_micro_inc.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								drivers/gles3/shaders/s4ao_micro_inc.glsl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
// S4AO (Stupid Simple Screen Space Ambient Occlusion) - Jonathan Dummer (O1S)
 | 
			
		||||
// This micro version uses only 3 depth samples, the midpoint and a randomly-rotated, balanced pair.
 | 
			
		||||
 | 
			
		||||
const mediump float ssao_falloff_frac = 0.25;
 | 
			
		||||
// Perform the SSAO.
 | 
			
		||||
float s4ao(vec2 UV) {
 | 
			
		||||
#ifdef USE_MULTIVIEW
 | 
			
		||||
	mediump float depth = texture(depth_buffer_array, vec3(UV, view)).r;
 | 
			
		||||
#else
 | 
			
		||||
	mediump float depth = texture(depth_buffer, UV).r;
 | 
			
		||||
#endif
 | 
			
		||||
	mediump float inv_falloff = 1.0f / max(1e-4f, depth * ssao_falloff_frac);
 | 
			
		||||
	// Random 2D rotation per pixel (0..1 -> parabola approximating a 180 deg arc)
 | 
			
		||||
	mediump float r01 = fract(dot(UV, ssao_prn_UV));
 | 
			
		||||
	mediump vec2 duv = vec2(r01 - 0.5f, 2.0f * (r01 - r01 * r01)) * (2.0f * depth * ssao_radius_frac); // 180 degrees.
 | 
			
		||||
	// Grab the samples and determine the occlusion.
 | 
			
		||||
	mediump float occlusion = 0.0f;
 | 
			
		||||
	for (int s = 0; s < 2; ++s) {
 | 
			
		||||
#ifdef USE_MULTIVIEW
 | 
			
		||||
		mediump float dz = texture(depth_buffer_array, vec3(UV + duv, view)).r - depth;
 | 
			
		||||
#else
 | 
			
		||||
		mediump float dz = texture(depth_buffer, UV + duv).r - depth;
 | 
			
		||||
#endif
 | 
			
		||||
		// How 'directly overhead' is it?  Factor in the falloff depth.
 | 
			
		||||
		occlusion += normalize(vec3(duv, dz)).z * mix(1.0f, 0.0f, dz * inv_falloff);
 | 
			
		||||
		// Mirror the next sample.
 | 
			
		||||
		duv = -duv;
 | 
			
		||||
	}
 | 
			
		||||
	// Adjust the occlusion for intensity, and # samples.
 | 
			
		||||
	occlusion = 1.0f - clamp(occlusion * 0.5f * ssao_intensity, 0.0f, 1.0f);
 | 
			
		||||
	return occlusion * occlusion;
 | 
			
		||||
}
 | 
			
		||||
@@ -1135,6 +1135,15 @@ void Environment::_validate_property(PropertyInfo &p_property) const {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (OS::get_singleton()->get_current_rendering_method() != "forward_plus") {
 | 
			
		||||
		// Hide SSAO properties that only work in Forward+.
 | 
			
		||||
		if (p_property.name.begins_with("ssao_")) {
 | 
			
		||||
			if ((p_property.name != "ssao_enabled") && (p_property.name != "ssao_radius") && (p_property.name != "ssao_intensity")) {
 | 
			
		||||
				p_property.usage = PROPERTY_USAGE_NO_EDITOR;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (p_property.name == "background_color") {
 | 
			
		||||
		if (bg_mode != BG_COLOR && ambient_source != AMBIENT_SOURCE_COLOR) {
 | 
			
		||||
			p_property.usage = PROPERTY_USAGE_NO_EDITOR;
 | 
			
		||||
 
 | 
			
		||||
@@ -588,8 +588,8 @@ void RendererEnvironmentStorage::environment_set_ssao(RID p_env, bool p_enable,
 | 
			
		||||
	Environment *env = environment_owner.get_or_null(p_env);
 | 
			
		||||
	ERR_FAIL_NULL(env);
 | 
			
		||||
#ifdef DEBUG_ENABLED
 | 
			
		||||
	if (OS::get_singleton()->get_current_rendering_method() != "forward_plus" && p_enable) {
 | 
			
		||||
		WARN_PRINT_ONCE_ED("Screen-space ambient occlusion (SSAO) can only be enabled when using the Forward+ renderer.");
 | 
			
		||||
	if (OS::get_singleton()->get_current_rendering_method() == "mobile" && p_enable) {
 | 
			
		||||
		WARN_PRINT_ONCE_ED("Screen-space ambient occlusion (SSAO) can only be enabled when using the Forward+ or Compatibility renderers.");
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	env->ssao_enabled = p_enable;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user