diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd')
37 files changed, 7324 insertions, 1532 deletions
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp index aad2be45c6..5d9e68f2b4 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -29,8 +29,8 @@  /*************************************************************************/  #include "rasterizer_canvas_rd.h" +#include "core/config/project_settings.h"  #include "core/math/math_funcs.h" -#include "core/project_settings.h"  #include "rasterizer_rd.h"  void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { @@ -92,152 +92,6 @@ void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform,  	p_mat4[15] = 1;  } -void RasterizerCanvasRD::_update_specular_shininess(const Color &p_transform, uint32_t *r_ss) { -	*r_ss = uint32_t(CLAMP(p_transform.a * 255.0, 0, 255)) << 24; -	*r_ss |= uint32_t(CLAMP(p_transform.b * 255.0, 0, 255)) << 16; -	*r_ss |= uint32_t(CLAMP(p_transform.g * 255.0, 0, 255)) << 8; -	*r_ss |= uint32_t(CLAMP(p_transform.r * 255.0, 0, 255)); -} - -RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { -	Vector<RD::Uniform> uniform_set; - -	{ // COLOR TEXTURE -		RD::Uniform u; -		u.type = RD::UNIFORM_TYPE_TEXTURE; -		u.binding = 1; -		RID texture = storage->texture_get_rd_texture(p_texture); -		if (!texture.is_valid()) { -			//use default white texture -			texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); -		} -		u.ids.push_back(texture); -		uniform_set.push_back(u); -	} - -	{ // NORMAL TEXTURE -		RD::Uniform u; -		u.type = RD::UNIFORM_TYPE_TEXTURE; -		u.binding = 2; -		RID texture = storage->texture_get_rd_texture(p_normalmap); -		if (!texture.is_valid()) { -			//use default normal texture -			texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL); -		} -		u.ids.push_back(texture); -		uniform_set.push_back(u); -	} - -	{ // SPECULAR TEXTURE -		RD::Uniform u; -		u.type = RD::UNIFORM_TYPE_TEXTURE; -		u.binding = 3; -		RID texture = storage->texture_get_rd_texture(p_specular); -		if (!texture.is_valid()) { -			//use default white texture -			texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); -		} -		u.ids.push_back(texture); -		uniform_set.push_back(u); -	} - -	{ // SAMPLER -		RD::Uniform u; -		u.type = RD::UNIFORM_TYPE_SAMPLER; -		u.binding = 4; -		RID sampler = storage->sampler_rd_get_default(p_filter, p_repeat); -		ERR_FAIL_COND_V(sampler.is_null(), RID()); -		u.ids.push_back(sampler); -		uniform_set.push_back(u); -	} - -	{ // MULTIMESH TEXTURE BUFFER -		RD::Uniform u; -		u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; -		u.binding = 5; -		u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER)); -		uniform_set.push_back(u); -	} - -	return RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0); -} - -RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { -	if (p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) { -		p_filter = default_samplers.default_filter; -	} - -	if (p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) { -		p_repeat = default_samplers.default_repeat; -	} - -	TextureBindingKey key; -	key.texture = p_texture; -	key.normalmap = p_normalmap; -	key.specular = p_specular; -	key.multimesh = p_multimesh; -	key.texture_filter = p_filter; -	key.texture_repeat = p_repeat; - -	TextureBinding *binding; -	TextureBindingID id; -	{ -		TextureBindingID *idptr = bindings.texture_key_bindings.getptr(key); - -		if (!idptr) { -			id = bindings.id_generator++; -			bindings.texture_key_bindings[key] = id; -			binding = memnew(TextureBinding); -			binding->key = key; -			binding->id = id; - -			bindings.texture_bindings[id] = binding; - -		} else { -			id = *idptr; -			binding = bindings.texture_bindings[id]; -		} -	} - -	binding->reference_count++; - -	if (binding->to_dispose.in_list()) { -		//was queued for disposal previously, but ended up reused. -		bindings.to_dispose_list.remove(&binding->to_dispose); -	} - -	if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { -		binding->uniform_set = _create_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh); -	} - -	return id; -} - -void RasterizerCanvasRD::free_texture_binding(TextureBindingID p_binding) { -	TextureBinding **binding_ptr = bindings.texture_bindings.getptr(p_binding); -	ERR_FAIL_COND(!binding_ptr); -	TextureBinding *binding = *binding_ptr; -	ERR_FAIL_COND(binding->reference_count == 0); -	binding->reference_count--; -	if (binding->reference_count == 0) { -		bindings.to_dispose_list.add(&binding->to_dispose); -	} -} - -void RasterizerCanvasRD::_dispose_bindings() { -	while (bindings.to_dispose_list.first()) { -		TextureBinding *binding = bindings.to_dispose_list.first()->self(); -		if (binding->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { -			RD::get_singleton()->free(binding->uniform_set); -		} - -		bindings.texture_key_bindings.erase(binding->key); -		bindings.texture_bindings.erase(binding->id); -		bindings.to_dispose_list.remove(&binding->to_dispose); -		memdelete(binding); -	} -} -  RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) {  	// Care must be taken to generate array formats  	// in ways where they could be reused, so we will @@ -457,36 +311,72 @@ void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) {  	polygon_buffers.polygons.erase(p_polygon);  } -Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list, uint32_t &flags) { -	TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(p_binding); -	ERR_FAIL_COND_V(!texture_binding_ptr, Size2i()); -	TextureBinding *texture_binding = *texture_binding_ptr; +//////////////////// -	if (texture_binding->key.normalmap.is_valid()) { -		flags |= FLAGS_DEFAULT_NORMAL_MAP_USED; +void RasterizerCanvasRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size) { +	if (p_texture == RID()) { +		p_texture = default_canvas_texture;  	} -	if (texture_binding->key.specular.is_valid()) { -		flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; + +	if (r_last_texture == p_texture) { +		return; //nothing to do, its the same  	} -	if (!RD::get_singleton()->uniform_set_is_valid(texture_binding->uniform_set)) { -		//texture may have changed (erased or replaced, see if we can fix) -		texture_binding->uniform_set = _create_texture_binding(texture_binding->key.texture, texture_binding->key.normalmap, texture_binding->key.specular, texture_binding->key.texture_filter, texture_binding->key.texture_repeat, texture_binding->key.multimesh); -		ERR_FAIL_COND_V(!texture_binding->uniform_set.is_valid(), Size2i(1, 1)); +	RID uniform_set; +	Color specular_shininess; +	Size2i size; +	bool use_normal; +	bool use_specular; + +	bool success = storage->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular); +	//something odd happened +	if (!success) { +		_bind_canvas_texture(p_draw_list, default_canvas_texture, p_base_filter, p_base_repeat, r_last_texture, push_constant, r_texpixel_size); +		return;  	} -	RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0); -	if (texture_binding->key.texture.is_valid()) { -		return storage->texture_2d_get_size(texture_binding->key.texture); +	RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, CANVAS_TEXTURE_UNIFORM_SET); + +	if (specular_shininess.a < 0.999) { +		push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; +	} else { +		push_constant.flags &= ~FLAGS_DEFAULT_SPECULAR_MAP_USED; +	} + +	if (use_normal) { +		push_constant.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;  	} else { -		return Size2i(1, 1); +		push_constant.flags &= ~FLAGS_DEFAULT_NORMAL_MAP_USED;  	} + +	push_constant.specular_shininess = uint32_t(CLAMP(specular_shininess.a * 255.0, 0, 255)) << 24; +	push_constant.specular_shininess |= uint32_t(CLAMP(specular_shininess.b * 255.0, 0, 255)) << 16; +	push_constant.specular_shininess |= uint32_t(CLAMP(specular_shininess.g * 255.0, 0, 255)) << 8; +	push_constant.specular_shininess |= uint32_t(CLAMP(specular_shininess.r * 255.0, 0, 255)); + +	r_texpixel_size.x = 1.0 / float(size.x); +	r_texpixel_size.y = 1.0 / float(size.y); + +	push_constant.color_texture_pixel_size[0] = r_texpixel_size.x; +	push_constant.color_texture_pixel_size[1] = r_texpixel_size.y; + +	r_last_texture = p_texture;  } -////////////////////  void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {  	//create an empty push constant +	RS::CanvasItemTextureFilter current_filter = default_filter; +	RS::CanvasItemTextureRepeat current_repeat = default_repeat; + +	if (p_item->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) { +		current_filter = p_item->texture_filter; +	} + +	if (p_item->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) { +		current_repeat = p_item->texture_repeat; +	} +  	PushConstant push_constant;  	Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;  	_update_transform_2d_to_mat2x3(base_transform, push_constant.world); @@ -513,16 +403,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  	uint32_t base_flags = 0; -	bool light_uniform_set_dirty = false; - -	if (!p_item->custom_data) { -		p_item->custom_data = memnew(ItemStateData); -		light_uniform_set_dirty = true; -	} - -	ItemStateData *state_data = (ItemStateData *)p_item->custom_data; - -	Light *light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM];  	uint16_t light_count = 0;  	PipelineLightMode light_mode; @@ -534,160 +414,30 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				uint32_t light_index = light->render_index_cache;  				push_constant.lights[light_count >> 2] |= light_index << ((light_count & 3) * 8); -				if (!light_uniform_set_dirty && (state_data->light_cache[light_count].light != light || state_data->light_cache[light_count].light_version != light->version)) { -					light_uniform_set_dirty = true; -				} - -				light_cache[light_count] = light; -  				light_count++; -				if (light->mode == RS::CANVAS_LIGHT_MODE_MASK) { -					base_flags |= FLAGS_USING_LIGHT_MASK; -				} -				if (light_count == state.max_lights_per_item) { + +				if (light_count == MAX_LIGHTS_PER_ITEM) {  					break;  				}  			}  			light = light->next_ptr;  		} -		if (light_count != state_data->light_cache_count) { -			light_uniform_set_dirty = true; -		}  		base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;  	} -	{ -		RID &canvas_item_state = light_count ? state_data->state_uniform_set_with_light : state_data->state_uniform_set; - -		bool invalid_uniform = canvas_item_state.is_valid() && !RD::get_singleton()->uniform_set_is_valid(canvas_item_state); - -		if (canvas_item_state.is_null() || invalid_uniform || (light_count > 0 && light_uniform_set_dirty)) { -			//re create canvas state -			Vector<RD::Uniform> uniforms; - -			if (state_data->state_uniform_set_with_light.is_valid() && !invalid_uniform) { -				RD::get_singleton()->free(canvas_item_state); -			} - -			{ -				RD::Uniform u; -				u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -				u.binding = 0; -				u.ids.push_back(state.canvas_state_buffer); -				uniforms.push_back(u); -			} - -			if (false && p_item->skeleton.is_valid()) { -				//bind skeleton stuff -			} else { -				//bind default - -				{ -					RD::Uniform u; -					u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; -					u.binding = 1; -					u.ids.push_back(shader.default_skeleton_texture_buffer); -					uniforms.push_back(u); -				} - -				{ -					RD::Uniform u; -					u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -					u.binding = 2; -					u.ids.push_back(shader.default_skeleton_uniform_buffer); -					uniforms.push_back(u); -				} -			} - -			{ -				RD::Uniform u; -				u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -				u.binding = 7; -				u.ids.push_back(storage->global_variables_get_storage_buffer()); -				uniforms.push_back(u); -			} - -			//validate and update lighs if they are being used - -			if (light_count > 0) { -				//recreate uniform set - -				{ -					RD::Uniform u; -					u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -					u.binding = 3; -					u.ids.push_back(state.lights_uniform_buffer); -					uniforms.push_back(u); -				} - -				{ -					RD::Uniform u_lights; -					u_lights.type = RD::UNIFORM_TYPE_TEXTURE; -					u_lights.binding = 4; - -					RD::Uniform u_shadows; -					u_shadows.type = RD::UNIFORM_TYPE_TEXTURE; -					u_shadows.binding = 5; - -					//lights -					for (uint32_t i = 0; i < state.max_lights_per_item; i++) { -						if (i < light_count) { -							CanvasLight *cl = canvas_light_owner.getornull(light_cache[i]->light_internal); -							ERR_CONTINUE(!cl); - -							RID rd_texture; - -							if (cl->texture.is_valid()) { -								rd_texture = storage->texture_get_rd_texture(cl->texture); -							} -							if (rd_texture.is_valid()) { -								u_lights.ids.push_back(rd_texture); -							} else { -								u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); -							} -							if (cl->shadow.texture.is_valid()) { -								u_shadows.ids.push_back(cl->shadow.texture); -							} else { -								u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); -							} -						} else { -							u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); -							u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); -						} -					} - -					uniforms.push_back(u_lights); -					uniforms.push_back(u_shadows); -				} - -				{ -					RD::Uniform u; -					u.type = RD::UNIFORM_TYPE_SAMPLER; -					u.binding = 6; -					u.ids.push_back(state.shadow_sampler); -					uniforms.push_back(u); -				} - -				canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader_light, 2); -			} else { -				canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 2); -			} -		} - -		RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, canvas_item_state, 2); -	} - -	light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED; +	light_mode = (light_count > 0 || using_directional_lights) ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;  	PipelineVariants *pipeline_variants = p_pipeline_variants;  	bool reclip = false; +	RID last_texture; +	Size2 texpixel_size; +  	const Item::Command *c = p_item->commands;  	while (c) { -		push_constant.flags = base_flags; //reset on each command for sanity -		push_constant.specular_shininess = 0xFFFFFFFF; +		push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config  		switch (c->type) {  			case Item::Command::TYPE_RECT: { @@ -701,26 +451,12 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				//bind textures -				Size2 texpixel_size; -				{ -					texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list, push_constant.flags); -					texpixel_size.x = 1.0 / texpixel_size.x; -					texpixel_size.y = 1.0 / texpixel_size.y; -				} - -				if (rect->specular_shininess.a < 0.999) { -					push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; -				} - -				_update_specular_shininess(rect->specular_shininess, &push_constant.specular_shininess); +				_bind_canvas_texture(p_draw_list, rect->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);  				Rect2 src_rect;  				Rect2 dst_rect; -				if (texpixel_size != Vector2()) { -					push_constant.color_texture_pixel_size[0] = texpixel_size.x; -					push_constant.color_texture_pixel_size[1] = texpixel_size.y; - +				if (rect->texture != RID()) {  					src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);  					dst_rect = Rect2(rect->rect.position, rect->rect.size); @@ -762,7 +498,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  					}  					src_rect = Rect2(0, 0, 1, 1); -					texpixel_size = Vector2(1, 1);  				}  				push_constant.modulation[0] = rect->modulate.r * base_color.r; @@ -780,9 +515,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				push_constant.dst_rect[2] = dst_rect.size.width;  				push_constant.dst_rect[3] = dst_rect.size.height; -				push_constant.color_texture_pixel_size[0] = texpixel_size.x; -				push_constant.color_texture_pixel_size[1] = texpixel_size.y; -  				RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));  				RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);  				RD::get_singleton()->draw_list_draw(p_draw_list, true); @@ -800,30 +532,21 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				//bind textures -				Size2 texpixel_size; -				{ -					texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list, push_constant.flags); -					texpixel_size.x = 1.0 / texpixel_size.x; -					texpixel_size.y = 1.0 / texpixel_size.y; -				} - -				if (np->specular_shininess.a < 0.999) { -					push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; -				} - -				_update_specular_shininess(np->specular_shininess, &push_constant.specular_shininess); +				_bind_canvas_texture(p_draw_list, np->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);  				Rect2 src_rect;  				Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y); -				if (texpixel_size == Size2()) { +				if (np->texture == RID()) {  					texpixel_size = Size2(1, 1);  					src_rect = Rect2(0, 0, 1, 1);  				} else {  					if (np->source != Rect2()) {  						src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height); -						texpixel_size = Size2(1.0 / np->source.size.width, 1.0 / np->source.size.height); +						push_constant.color_texture_pixel_size[0] = 1.0 / np->source.size.width; +						push_constant.color_texture_pixel_size[1] = 1.0 / np->source.size.height; +  					} else {  						src_rect = Rect2(0, 0, 1, 1);  					} @@ -844,9 +567,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				push_constant.dst_rect[2] = dst_rect.size.width;  				push_constant.dst_rect[3] = dst_rect.size.height; -				push_constant.color_texture_pixel_size[0] = texpixel_size.x; -				push_constant.color_texture_pixel_size[1] = texpixel_size.y; -  				push_constant.flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;  				push_constant.flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT; @@ -863,6 +583,10 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);  				RD::get_singleton()->draw_list_draw(p_draw_list, true); +				//restore if overrided +				push_constant.color_texture_pixel_size[0] = texpixel_size.x; +				push_constant.color_texture_pixel_size[1] = texpixel_size.y; +  			} break;  			case Item::Command::TYPE_POLYGON: {  				const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); @@ -884,18 +608,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				//bind textures -				Size2 texpixel_size; -				{ -					texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list, push_constant.flags); -					texpixel_size.x = 1.0 / texpixel_size.x; -					texpixel_size.y = 1.0 / texpixel_size.y; -				} - -				if (polygon->specular_shininess.a < 0.999) { -					push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; -				} - -				_update_specular_shininess(polygon->specular_shininess, &push_constant.specular_shininess); +				_bind_canvas_texture(p_draw_list, polygon->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);  				push_constant.modulation[0] = base_color.r;  				push_constant.modulation[1] = base_color.g; @@ -908,9 +621,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  					push_constant.ninepatch_margins[j] = 0;  				} -				push_constant.color_texture_pixel_size[0] = texpixel_size.x; -				push_constant.color_texture_pixel_size[1] = texpixel_size.y; -  				RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));  				RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);  				if (pb->indices.is_valid()) { @@ -932,15 +642,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  				//bind textures -				{ -					_bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list, push_constant.flags); -				} - -				if (primitive->specular_shininess.a < 0.999) { -					push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED; -				} - -				_update_specular_shininess(primitive->specular_shininess, &push_constant.specular_shininess); +				_bind_canvas_texture(p_draw_list, RID(), current_filter, current_repeat, last_texture, push_constant, texpixel_size);  				RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3, primitive->point_count) - 1]); @@ -1295,31 +997,146 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_  	}  } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set) { +RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_backbuffer) { +	//re create canvas state +	Vector<RD::Uniform> uniforms; + +	{ +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +		u.binding = 1; +		u.ids.push_back(state.canvas_state_buffer); +		uniforms.push_back(u); +	} + +	{ +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +		u.binding = 2; +		u.ids.push_back(state.lights_uniform_buffer); +		uniforms.push_back(u); +	} + +	{ +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_TEXTURE; +		u.binding = 3; +		u.ids.push_back(storage->decal_atlas_get_texture()); +		uniforms.push_back(u); +	} + +	{ +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_TEXTURE; +		u.binding = 4; +		u.ids.push_back(state.shadow_texture); +		uniforms.push_back(u); +	} + +	{ +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_SAMPLER; +		u.binding = 5; +		u.ids.push_back(state.shadow_sampler); +		uniforms.push_back(u); +	} + +	{ +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_TEXTURE; +		u.binding = 6; +		RID screen; +		if (p_backbuffer) { +			screen = storage->render_target_get_rd_texture(p_to_render_target); +		} else { +			screen = storage->render_target_get_rd_backbuffer(p_to_render_target); +			if (screen.is_null()) { //unallocated backbuffer +				screen = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); +			} +		} +		u.ids.push_back(screen); +		uniforms.push_back(u); +	} + +	{ +		//needs samplers for the material (uses custom textures) create them +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_SAMPLER; +		u.binding = 7; +		u.ids.resize(12); +		RID *ids_ptr = u.ids.ptrw(); +		ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +		ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +		ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +		ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +		ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +		ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +		ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +		ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +		ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +		ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +		ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +		ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +		uniforms.push_back(u); +	} + +	{ +		RD::Uniform u; +		u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +		u.binding = 8; +		u.ids.push_back(storage->global_variables_get_storage_buffer()); +		uniforms.push_back(u); +	} + +	RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, BASE_UNIFORM_SET); +	if (p_backbuffer) { +		storage->render_target_set_backbuffer_uniform_set(p_to_render_target, uniform_set); +	} else { +		storage->render_target_set_framebuffer_uniform_set(p_to_render_target, uniform_set); +	} + +	return uniform_set; +} + +void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) {  	Item *current_clip = nullptr;  	Transform2D canvas_transform_inverse = p_canvas_transform_inverse; -	RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); - -	Vector<Color> clear_colors; +	RID framebuffer; +	RID fb_uniform_set;  	bool clear = false; -	if (storage->render_target_is_clear_requested(p_to_render_target)) { -		clear = true; -		clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); -		storage->render_target_disable_clear_request(p_to_render_target); -	} +	Vector<Color> clear_colors; + +	if (p_to_backbuffer) { +		framebuffer = storage->render_target_get_rd_backbuffer_framebuffer(p_to_render_target); +		fb_uniform_set = storage->render_target_get_backbuffer_uniform_set(p_to_render_target); +	} else { +		framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); + +		if (storage->render_target_is_clear_requested(p_to_render_target)) { +			clear = true; +			clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); +			storage->render_target_disable_clear_request(p_to_render_target); +		}  #ifndef _MSC_VER  #warning TODO obtain from framebuffer format eventually when this is implemented  #endif +		fb_uniform_set = storage->render_target_get_framebuffer_uniform_set(p_to_render_target); +	} + +	if (fb_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fb_uniform_set)) { +		fb_uniform_set = _create_base_uniform_set(p_to_render_target, p_to_backbuffer); +	} +  	RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);  	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors); -	if (p_screen_uniform_set.is_valid()) { -		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_screen_uniform_set, 3); -	} +	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET); +	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET); +  	RID prev_material;  	PipelineVariants *pipeline_variants = &shader.pipeline_variants; @@ -1339,17 +1156,23 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,  			}  		} -		if (ci->material != prev_material) { +		RID material = ci->material; + +		if (material.is_null() && ci->canvas_group != nullptr) { +			material = default_canvas_group_material; +		} + +		if (material != prev_material) {  			MaterialData *material_data = nullptr; -			if (ci->material.is_valid()) { -				material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); +			if (material.is_valid()) { +				material_data = (MaterialData *)storage->material_get_data(material, RasterizerStorageRD::SHADER_TYPE_2D);  			}  			if (material_data) {  				if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {  					pipeline_variants = &material_data->shader_data->pipeline_variants;  					if (material_data->uniform_set.is_valid()) { -						RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, 1); +						RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET);  					}  				} else {  					pipeline_variants = &shader.pipeline_variants; @@ -1361,55 +1184,89 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,  		_render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants); -		prev_material = ci->material; +		prev_material = material;  	}  	RD::get_singleton()->draw_list_end();  } -void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) { +void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) {  	int item_count = 0;  	//setup canvas state uniforms if needed  	Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse(); +	//setup directional lights if exist + +	uint32_t light_count = 0; +	uint32_t directional_light_count = 0;  	{ -		//update canvas state uniform buffer -		State::Buffer state_buffer; +		Light *l = p_directional_light_list; +		uint32_t index = 0; -		Size2i ssize = storage->render_target_get_size(p_to_render_target); +		while (l) { +			if (index == state.max_lights_per_render) { +				l->render_index_cache = -1; +				l = l->next_ptr; +				continue; +			} -		Transform screen_transform; -		screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); -		screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); -		_update_transform_to_mat4(screen_transform, state_buffer.screen_transform); -		_update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform); +			CanvasLight *clight = canvas_light_owner.getornull(l->light_internal); +			if (!clight) { //unused or invalid texture +				l->render_index_cache = -1; +				l = l->next_ptr; +				ERR_CONTINUE(!clight); +			} -		Transform2D normal_transform = p_canvas_transform; -		normal_transform.elements[0].normalize(); -		normal_transform.elements[1].normalize(); -		normal_transform.elements[2] = Vector2(); -		_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform); +			Vector2 canvas_light_dir = l->xform_cache.elements[1].normalized(); -		state_buffer.canvas_modulate[0] = p_modulate.r; -		state_buffer.canvas_modulate[1] = p_modulate.g; -		state_buffer.canvas_modulate[2] = p_modulate.b; -		state_buffer.canvas_modulate[3] = p_modulate.a; +			state.light_uniforms[index].position[0] = -canvas_light_dir.x; +			state.light_uniforms[index].position[1] = -canvas_light_dir.y; -		Size2 render_target_size = storage->render_target_get_size(p_to_render_target); -		state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; -		state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; +			_update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix); -		state_buffer.time = state.time; -		RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); +			state.light_uniforms[index].height = l->height; //0..1 here + +			for (int i = 0; i < 4; i++) { +				state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255)); +				state.light_uniforms[index].color[i] = l->color[i]; +			} + +			state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate + +			if (state.shadow_fb.is_valid()) { +				state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth); +				state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far; +				state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset; +			} else { +				state.light_uniforms[index].shadow_pixel_size = 1.0; +				state.light_uniforms[index].shadow_z_far_inv = 1.0; +				state.light_uniforms[index].shadow_y_ofs = 0; +			} + +			state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT; +			state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT; +			if (clight->shadow.enabled) { +				state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW; +			} + +			l->render_index_cache = index; + +			index++; +			l = l->next_ptr; +		} + +		light_count = index; +		directional_light_count = light_count; +		using_directional_lights = directional_light_count > 0;  	}  	//setup lights if exist  	{  		Light *l = p_light_list; -		uint32_t index = 0; +		uint32_t index = light_count;  		while (l) {  			if (index == state.max_lights_per_render) { @@ -1435,33 +1292,93 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  			state.light_uniforms[index].height = l->height * (p_canvas_transform.elements[0].length() + p_canvas_transform.elements[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss  			for (int i = 0; i < 4; i++) { -				state.light_uniforms[index].shadow_color[i] = l->shadow_color[i]; +				state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255));  				state.light_uniforms[index].color[i] = l->color[i];  			}  			state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate -			if (clight->shadow.texture.is_valid()) { -				state.light_uniforms[index].shadow_pixel_size = (1.0 / clight->shadow.size) * (1.0 + l->shadow_smooth); +			if (state.shadow_fb.is_valid()) { +				state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth); +				state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far; +				state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset;  			} else {  				state.light_uniforms[index].shadow_pixel_size = 1.0; +				state.light_uniforms[index].shadow_z_far_inv = 1.0; +				state.light_uniforms[index].shadow_y_ofs = 0;  			} -			state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT; +			state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT;  			state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT; -			if (clight->shadow.texture.is_valid()) { +			if (clight->shadow.enabled) {  				state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;  			} +			if (clight->texture.is_valid()) { +				Rect2 atlas_rect = storage->decal_atlas_get_texture_rect(clight->texture); +				state.light_uniforms[index].atlas_rect[0] = atlas_rect.position.x; +				state.light_uniforms[index].atlas_rect[1] = atlas_rect.position.y; +				state.light_uniforms[index].atlas_rect[2] = atlas_rect.size.width; +				state.light_uniforms[index].atlas_rect[3] = atlas_rect.size.height; + +			} else { +				state.light_uniforms[index].atlas_rect[0] = 0; +				state.light_uniforms[index].atlas_rect[1] = 0; +				state.light_uniforms[index].atlas_rect[2] = 0; +				state.light_uniforms[index].atlas_rect[3] = 0; +			} +  			l->render_index_cache = index;  			index++;  			l = l->next_ptr;  		} -		if (index > 0) { -			RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * index, &state.light_uniforms[0], true); -		} +		light_count = index; +	} + +	if (light_count > 0) { +		RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0], true); +	} + +	{ +		//update canvas state uniform buffer +		State::Buffer state_buffer; + +		Size2i ssize = storage->render_target_get_size(p_to_render_target); + +		Transform screen_transform; +		screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); +		screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); +		_update_transform_to_mat4(screen_transform, state_buffer.screen_transform); +		_update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform); + +		Transform2D normal_transform = p_canvas_transform; +		normal_transform.elements[0].normalize(); +		normal_transform.elements[1].normalize(); +		normal_transform.elements[2] = Vector2(); +		_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform); + +		state_buffer.canvas_modulate[0] = p_modulate.r; +		state_buffer.canvas_modulate[1] = p_modulate.g; +		state_buffer.canvas_modulate[2] = p_modulate.b; +		state_buffer.canvas_modulate[3] = p_modulate.a; + +		Size2 render_target_size = storage->render_target_get_size(p_to_render_target); +		state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; +		state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; + +		state_buffer.time = state.time; +		state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel; + +		state_buffer.directional_light_count = directional_light_count; + +		RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); +	} + +	{ //default filter/repeat +		default_filter = p_default_filter; +		default_repeat = p_default_repeat;  	}  	//fill the list until rendering is possible. @@ -1469,10 +1386,11 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  	Item *ci = p_item_list;  	Rect2 back_buffer_rect;  	bool backbuffer_copy = false; -	RID screen_uniform_set; + +	Item *canvas_group_owner = nullptr;  	while (ci) { -		if (ci->copy_back_buffer) { +		if (ci->copy_back_buffer && canvas_group_owner == nullptr) {  			backbuffer_copy = true;  			if (ci->copy_back_buffer->full) { @@ -1485,15 +1403,11 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  		if (ci->material.is_valid()) {  			MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);  			if (md && md->shader_data->valid) { -				if (md->shader_data->uses_screen_texture) { +				if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {  					if (!material_screen_texture_found) {  						backbuffer_copy = true;  						back_buffer_rect = Rect2();  					} -					if (screen_uniform_set.is_null()) { -						RID backbuffer_shader = shader.canvas_shader.version_get_shader(md->shader_data->version, 0); //any version is fine -						screen_uniform_set = storage->render_target_get_back_buffer_uniform_set(p_to_render_target, backbuffer_shader); -					}  				}  				if (md->last_frame != RasterizerRD::singleton->get_frame_number()) { @@ -1507,12 +1421,44 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  			}  		} +		if (ci->canvas_group_owner != nullptr) { +			if (canvas_group_owner == nullptr) { +				//Canvas group begins here, render until before this item +				_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); +				item_count = 0; + +				Rect2i group_rect = ci->canvas_group_owner->global_rect_cache; + +				if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) { +					storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false); +				} else { +					storage->render_target_clear_back_buffer(p_to_render_target, group_rect, Color(0, 0, 0, 0)); +				} + +				backbuffer_copy = false; +				canvas_group_owner = ci->canvas_group_owner; //continue until owner found +			} + +			ci->canvas_group_owner = nullptr; //must be cleared +		} + +		if (ci == canvas_group_owner) { +			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true); +			item_count = 0; + +			if (ci->canvas_group->blur_mipmaps) { +				storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, ci->global_rect_cache); +			} + +			canvas_group_owner = nullptr; +		} +  		if (backbuffer_copy) {  			//render anything pending, including clearing if no items -			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set); +			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);  			item_count = 0; -			storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect); +			storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true);  			backbuffer_copy = false;  			material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies @@ -1521,7 +1467,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  		items[item_count++] = ci;  		if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) { -			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set); +			_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);  			//then reset  			item_count = 0;  		} @@ -1532,7 +1478,6 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite  RID RasterizerCanvasRD::light_create() {  	CanvasLight canvas_light; -	canvas_light.shadow.size = 0;  	return canvas_light_owner.make_rid(canvas_light);  } @@ -1542,71 +1487,74 @@ void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) {  	if (cl->texture == p_texture) {  		return;  	} - +	if (cl->texture.is_valid()) { +		storage->texture_remove_from_decal_atlas(cl->texture); +	}  	cl->texture = p_texture; + +	if (cl->texture.is_valid()) { +		storage->texture_add_to_decal_atlas(cl->texture); +	}  } -void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) { +void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable) {  	CanvasLight *cl = canvas_light_owner.getornull(p_rid);  	ERR_FAIL_COND(!cl); -	ERR_FAIL_COND(p_resolution < 64); -	if (cl->shadow.texture.is_valid() == p_enable && p_resolution == cl->shadow.size) { -		return; -	} -	if (cl->shadow.texture.is_valid()) { -		RD::get_singleton()->free(cl->shadow.fb); -		RD::get_singleton()->free(cl->shadow.depth); -		RD::get_singleton()->free(cl->shadow.texture); -		cl->shadow.fb = RID(); -		cl->shadow.texture = RID(); -		cl->shadow.depth = RID(); -	} +	cl->shadow.enabled = p_enable; +} + +void RasterizerCanvasRD::_update_shadow_atlas() { +	if (state.shadow_fb == RID()) { +		//ah, we lack the shadow texture.. +		RD::get_singleton()->free(state.shadow_texture); //erase placeholder -	if (p_enable) {  		Vector<RID> fb_textures;  		{ //texture  			RD::TextureFormat tf;  			tf.type = RD::TEXTURE_TYPE_2D; -			tf.width = p_resolution; -			tf.height = 1; +			tf.width = state.shadow_texture_size; +			tf.height = state.max_lights_per_render * 2;  			tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;  			tf.format = RD::DATA_FORMAT_R32_SFLOAT; -			cl->shadow.texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); -			fb_textures.push_back(cl->shadow.texture); +			state.shadow_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); +			fb_textures.push_back(state.shadow_texture);  		}  		{  			RD::TextureFormat tf;  			tf.type = RD::TEXTURE_TYPE_2D; -			tf.width = p_resolution; -			tf.height = 1; +			tf.width = state.shadow_texture_size; +			tf.height = state.max_lights_per_render * 2;  			tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; -			tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT; +			tf.format = RD::DATA_FORMAT_D32_SFLOAT;  			//chunks to write -			cl->shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); -			fb_textures.push_back(cl->shadow.depth); +			state.shadow_depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); +			fb_textures.push_back(state.shadow_depth_texture);  		} -		cl->shadow.fb = RD::get_singleton()->framebuffer_create(fb_textures); +		state.shadow_fb = RD::get_singleton()->framebuffer_create(fb_textures);  	} - -	cl->shadow.size = p_resolution;  } - -void RasterizerCanvasRD::light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { +void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {  	CanvasLight *cl = canvas_light_owner.getornull(p_rid); -	ERR_FAIL_COND(cl->shadow.texture.is_null()); +	ERR_FAIL_COND(!cl->shadow.enabled); + +	_update_shadow_atlas(); + +	cl->shadow.z_far = p_far; +	cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2); +	Vector<Color> cc; +	cc.push_back(Color(p_far, p_far, p_far, 1.0));  	for (int i = 0; i < 4; i++) {  		//make sure it remains orthogonal, makes easy to read angle later  		//light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); -		Vector<Color> cc; -		cc.push_back(Color(p_far, p_far, p_far, 1.0)); -		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, Rect2i((cl->shadow.size / 4) * i, 0, (cl->shadow.size / 4), 1)); +		Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2); +		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);  		CameraMatrix projection;  		{ @@ -1635,8 +1583,8 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, const Transform2D &p_lig  		static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };  		push_constant.direction[0] = directions[i].x;  		push_constant.direction[1] = directions[i].y; -		push_constant.pad[0] = 0; -		push_constant.pad[1] = 0; +		push_constant.z_far = p_far; +		push_constant.pad = 0;  		/*if (i == 0)  			*p_xform_cache = projection;*/ @@ -1667,6 +1615,86 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, const Transform2D &p_lig  	}  } +void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { +	CanvasLight *cl = canvas_light_owner.getornull(p_rid); +	ERR_FAIL_COND(!cl->shadow.enabled); + +	_update_shadow_atlas(); + +	Vector2 light_dir = p_light_xform.elements[1].normalized(); + +	Vector2 center = p_clip_rect.position + p_clip_rect.size * 0.5; + +	float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center)); + +	Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance); +	float distance = to_edge_distance * 2.0 + p_cull_distance; +	float half_size = p_clip_rect.size.length() * 0.5; //shadow length, must keep this no matter the angle + +	cl->shadow.z_far = distance; +	cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2); + +	Transform2D to_light_xform; + +	to_light_xform[2] = from_pos; +	to_light_xform[1] = light_dir; +	to_light_xform[0] = -light_dir.tangent(); + +	to_light_xform.invert(); + +	Vector<Color> cc; +	cc.push_back(Color(1, 1, 1, 1)); + +	Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2); +	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + +	CameraMatrix projection; +	projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance); +	projection = projection * CameraMatrix(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse()); + +	ShadowRenderPushConstant push_constant; +	for (int y = 0; y < 4; y++) { +		for (int x = 0; x < 4; x++) { +			push_constant.projection[y * 4 + x] = projection.matrix[y][x]; +		} +	} + +	push_constant.direction[0] = 0.0; +	push_constant.direction[1] = 1.0; +	push_constant.z_far = distance; +	push_constant.pad = 0; + +	LightOccluderInstance *instance = p_occluders; + +	while (instance) { +		OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + +		if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) { +			instance = instance->next; +			continue; +		} + +		_update_transform_2d_to_mat2x4(to_light_xform * instance->xform_cache, push_constant.modelview); + +		RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]); +		RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array); +		RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array); +		RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); + +		RD::get_singleton()->draw_list_draw(draw_list, true); + +		instance = instance->next; +	} + +	RD::get_singleton()->draw_list_end(); + +	Transform2D to_shadow; +	to_shadow.elements[0].x = 1.0 / -(half_size * 2.0); +	to_shadow.elements[2].x = 0.5; + +	cl->shadow.directional_xform = to_shadow * to_light_xform; +} +  RID RasterizerCanvasRD::occluder_polygon_create() {  	OccluderPolygon occluder;  	occluder.point_count = 0; @@ -1774,7 +1802,6 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {  	ubo_size = 0;  	uniforms.clear();  	uses_screen_texture = false; -	uses_material_samplers = false;  	if (code == String()) {  		return; //just invalid, but no error @@ -1812,10 +1839,6 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {  		version = canvas_singleton->shader.canvas_shader.version_create();  	} -	if (gen_code.texture_uniforms.size() || uses_screen_texture) { //requires the samplers -		gen_code.defines.push_back("\n#define USE_MATERIAL_SAMPLERS\n"); -		uses_material_samplers = true; -	}  #if 0  	print_line("**compiling shader:");  	print_line("**defines:\n"); @@ -1847,10 +1870,11 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {  		} break;  		case BLEND_MODE_MIX: {  			attachment.enable_blend = true; -			attachment.alpha_blend_op = RD::BLEND_OP_ADD;  			attachment.color_blend_op = RD::BLEND_OP_ADD;  			attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;  			attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + +			attachment.alpha_blend_op = RD::BLEND_OP_ADD;  			attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;  			attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -2022,7 +2046,6 @@ Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName &  RasterizerCanvasRD::ShaderData::ShaderData() {  	valid = false;  	uses_screen_texture = false; -	uses_material_samplers = false;  }  RasterizerCanvasRD::ShaderData::~ShaderData() { @@ -2085,7 +2108,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V  		update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), false);  	} -	if (shader_data->ubo_size == 0 && !shader_data->uses_material_samplers) { +	if (shader_data->ubo_size == 0) {  		// This material does not require an uniform set, so don't create it.  		return;  	} @@ -2098,32 +2121,10 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V  	Vector<RD::Uniform> uniforms;  	{ -		if (shader_data->uses_material_samplers) { -			//needs samplers for the material (uses custom textures) create them -			RD::Uniform u; -			u.type = RD::UNIFORM_TYPE_SAMPLER; -			u.binding = 0; -			u.ids.resize(12); -			RID *ids_ptr = u.ids.ptrw(); -			ids_ptr[0] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[1] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[2] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[3] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[4] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[5] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[6] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[7] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[8] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[9] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[10] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[11] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			uniforms.push_back(u); -		} -  		if (shader_data->ubo_size) {  			RD::Uniform u;  			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -			u.binding = 1; +			u.binding = 0;  			u.ids.push_back(uniform_buffer);  			uniforms.push_back(u);  		} @@ -2132,13 +2133,13 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V  		for (uint32_t i = 0; i < tex_uniform_count; i++) {  			RD::Uniform u;  			u.type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 2 + i; +			u.binding = 1 + i;  			u.ids.push_back(textures[i]);  			uniforms.push_back(u);  		}  	} -	uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), 1); +	uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET);  }  RasterizerCanvasRD::MaterialData::~MaterialData() { @@ -2164,7 +2165,6 @@ void RasterizerCanvasRD::set_time(double p_time) {  }  void RasterizerCanvasRD::update() { -	_dispose_bindings();  }  RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { @@ -2178,22 +2178,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  	{ //shader variants -		uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); -  		String global_defines; -		if (textures_per_stage <= 16) { -			//ARM pretty much, and very old Intel GPUs under Linux -			state.max_lights_per_item = 4; //sad -			global_defines += "#define MAX_LIGHT_TEXTURES 4\n"; -		} else if (textures_per_stage <= 32) { -			//Apple (Metal) -			state.max_lights_per_item = 8; //sad -			global_defines += "#define MAX_LIGHT_TEXTURES 8\n"; -		} else { -			//Anything else (16 lights per item) -			state.max_lights_per_item = DEFAULT_MAX_LIGHTS_PER_ITEM; -			global_defines += "#define MAX_LIGHT_TEXTURES " + itos(DEFAULT_MAX_LIGHTS_PER_ITEM) + "\n"; -		}  		uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);  		if (uniform_max_size < 65536) { @@ -2226,7 +2211,20 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  		shader.default_version = shader.canvas_shader.version_create();  		shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD); -		shader.default_version_rd_shader_light = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD_LIGHT); + +		RD::PipelineColorBlendState blend_state; +		RD::PipelineColorBlendState::Attachment blend_attachment; + +		blend_attachment.enable_blend = true; +		blend_attachment.color_blend_op = RD::BLEND_OP_ADD; +		blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; +		blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + +		blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; +		blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; +		blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + +		blend_state.attachments.push_back(blend_attachment);  		for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {  			for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) { @@ -2269,7 +2267,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  				};  				RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]); -				shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0); +				shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);  			}  		}  	} @@ -2327,8 +2325,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  		actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";  		actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture  		actions.sampler_array_name = "material_samplers"; -		actions.base_texture_binding_index = 2; -		actions.texture_layout_set = 1; +		actions.base_texture_binding_index = 1; +		actions.texture_layout_set = MATERIAL_UNIFORM_SET;  		actions.base_uniform_string = "material.";  		actions.default_filter = ShaderLanguage::FILTER_LINEAR;  		actions.default_repeat = ShaderLanguage::REPEAT_DISABLE; @@ -2354,7 +2352,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  			attachments.push_back(af_color);  			RD::AttachmentFormat af_depth; -			af_depth.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; +			af_depth.format = RD::DATA_FORMAT_D32_SFLOAT;  			af_depth.usage_flags = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;  			attachments.push_back(af_depth); @@ -2386,21 +2384,17 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  	}  	{ //bindings -		bindings.id_generator = 0; -		//generate for 0 -		bindings.default_empty = request_texture_binding(RID(), RID(), RID(), RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, RID()); - -		{ //state allocate -			state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer)); -			state.lights_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(LightUniform) * state.max_lights_per_render); - -			RD::SamplerState shadow_sampler_state; -			shadow_sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; -			shadow_sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; -			shadow_sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; //shadow wrap around -			shadow_sampler_state.compare_op = RD::COMPARE_OP_GREATER; -			state.shadow_sampler = RD::get_singleton()->sampler_create(shadow_sampler_state); -		} + +		state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer)); +		state.lights_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(LightUniform) * state.max_lights_per_render); + +		RD::SamplerState shadow_sampler_state; +		shadow_sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; +		shadow_sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; +		shadow_sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; //shadow wrap around +		shadow_sampler_state.compare_op = RD::COMPARE_OP_GREATER; +		shadow_sampler_state.enable_compare = true; +		state.shadow_sampler = RD::get_singleton()->sampler_create(shadow_sampler_state);  	}  	{ @@ -2443,6 +2437,35 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  		shader.default_skeleton_texture_buffer = RD::get_singleton()->texture_buffer_create(32, RD::DATA_FORMAT_R32G32B32A32_SFLOAT);  	} +	{ +		//default shadow texture to keep uniform set happy +		RD::TextureFormat tf; +		tf.type = RD::TEXTURE_TYPE_2D; +		tf.width = 4; +		tf.height = 4; +		tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; +		tf.format = RD::DATA_FORMAT_R32_SFLOAT; + +		state.shadow_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); +	} + +	{ +		Vector<RD::Uniform> uniforms; + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 0; +			u.ids.push_back(storage->get_default_rd_storage_buffer()); +			uniforms.push_back(u); +		} + +		state.default_transforms_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET); +	} + +	default_canvas_texture = storage->canvas_texture_create(); + +	state.shadow_texture_size = GLOBAL_GET("rendering/quality/2d_shadow_atlas/size");  	//create functions for shader and material  	storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_shader_funcs); @@ -2450,6 +2473,13 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {  	state.time = 0; +	{ +		default_canvas_group_shader = storage->shader_create(); +		storage->shader_set_code(default_canvas_group_shader, "shader_type canvas_item; \nvoid fragment() {\n\tvec4 c = textureLod(SCREEN_TEXTURE,SCREEN_UV,0.0); if (c.a > 0.0001) c.rgb/=c.a; COLOR *= c; \n}\n"); +		default_canvas_group_material = storage->material_create(); +		storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader); +	} +  	static_assert(sizeof(PushConstant) == 128);  } @@ -2457,7 +2487,7 @@ bool RasterizerCanvasRD::free(RID p_rid) {  	if (canvas_light_owner.owns(p_rid)) {  		CanvasLight *cl = canvas_light_owner.getornull(p_rid);  		ERR_FAIL_COND_V(!cl, false); -		light_set_use_shadow(p_rid, false, 64); +		light_set_use_shadow(p_rid, false);  		canvas_light_owner.free(p_rid);  	} else if (occluder_polygon_owner.owns(p_rid)) {  		occluder_polygon_set_shape_as_lines(p_rid, Vector<Vector2>()); @@ -2469,9 +2499,37 @@ bool RasterizerCanvasRD::free(RID p_rid) {  	return true;  } +void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { +	p_size = nearest_power_of_2_templated(p_size); +	if (p_size == state.shadow_texture_size) { +		return; +	} +	state.shadow_texture_size = p_size; +	if (state.shadow_fb.is_valid()) { +		RD::get_singleton()->free(state.shadow_texture); +		RD::get_singleton()->free(state.shadow_depth_texture); +		state.shadow_fb = RID(); + +		{ +			//create a default shadow texture to keep uniform set happy (and that it gets erased when a new one is created) +			RD::TextureFormat tf; +			tf.type = RD::TEXTURE_TYPE_2D; +			tf.width = 4; +			tf.height = 4; +			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; +			tf.format = RD::DATA_FORMAT_R32_SFLOAT; + +			state.shadow_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); +		} +	} +} +  RasterizerCanvasRD::~RasterizerCanvasRD() {  	//canvas state +	storage->free(default_canvas_group_material); +	storage->free(default_canvas_group_shader); +  	{  		if (state.canvas_state_buffer.is_valid()) {  			RD::get_singleton()->free(state.canvas_state_buffer); @@ -2490,24 +2548,6 @@ RasterizerCanvasRD::~RasterizerCanvasRD() {  		RD::get_singleton()->free(state.shadow_sampler);  	}  	//bindings -	{ -		free_texture_binding(bindings.default_empty); - -		//dispose pending -		_dispose_bindings(); -		//anything remains? -		if (bindings.texture_bindings.size()) { -			ERR_PRINT("Some texture bindings were not properly freed (leaked CanvasItems?)"); -			const TextureBindingID *key = nullptr; -			while ((key = bindings.texture_bindings.next(key))) { -				TextureBinding *tb = bindings.texture_bindings[*key]; -				tb->reference_count = 1; -				free_texture_binding(*key); -			} -			//dispose pending -			_dispose_bindings(); -		} -	}  	//shaders @@ -2520,5 +2560,11 @@ RasterizerCanvasRD::~RasterizerCanvasRD() {  		//primitives are erase by dependency  	} +	if (state.shadow_fb.is_valid()) { +		RD::get_singleton()->free(state.shadow_depth_texture); +	} +	RD::get_singleton()->free(state.shadow_texture); + +	storage->free(default_canvas_texture);  	//pipelines don't need freeing, they are all gone after shaders are gone  } diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h index bfe4e61f47..b516f63cbf 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h @@ -42,6 +42,13 @@  class RasterizerCanvasRD : public RasterizerCanvas {  	RasterizerStorageRD *storage; +	enum { +		BASE_UNIFORM_SET = 0, +		MATERIAL_UNIFORM_SET = 1, +		TRANSFORMS_UNIFORM_SET = 2, +		CANVAS_TEXTURE_UNIFORM_SET = 3, +	}; +  	enum ShaderVariant {  		SHADER_VARIANT_QUAD,  		SHADER_VARIANT_NINEPATCH, @@ -68,11 +75,9 @@ class RasterizerCanvasRD : public RasterizerCanvas {  		FLAGS_CLIP_RECT_UV = (1 << 9),  		FLAGS_TRANSPOSE_RECT = (1 << 10), -		FLAGS_USING_LIGHT_MASK = (1 << 11),  		FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),  		FLAGS_USING_PARTICLES = (1 << 13), -		FLAGS_USE_PIXEL_SNAP = (1 << 14),  		FLAGS_USE_SKELETON = (1 << 15),  		FLAGS_NINEPATCH_H_MODE_SHIFT = 16, @@ -100,7 +105,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	enum {  		MAX_RENDER_ITEMS = 256 * 1024,  		MAX_LIGHT_TEXTURES = 1024, -		DEFAULT_MAX_LIGHTS_PER_ITEM = 16, +		MAX_LIGHTS_PER_ITEM = 16,  		DEFAULT_MAX_LIGHTS_PER_RENDER = 256  	}; @@ -135,7 +140,6 @@ class RasterizerCanvasRD : public RasterizerCanvas {  		CanvasShaderRD canvas_shader;  		RID default_version;  		RID default_version_rd_shader; -		RID default_version_rd_shader_light;  		RID quad_index_buffer;  		RID quad_index_array;  		PipelineVariants pipeline_variants; @@ -178,7 +182,6 @@ class RasterizerCanvasRD : public RasterizerCanvas {  		Map<StringName, RID> default_texture_params;  		bool uses_screen_texture; -		bool uses_material_samplers;  		virtual void set_code(const String &p_Code);  		virtual void set_default_texture_param(const StringName &p_name, RID p_texture); @@ -218,60 +221,9 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	}  	/**************************/ -	/**** TEXTURE BINDINGS ****/ +	/**** CANVAS TEXTURES *****/  	/**************************/ -	// bindings used to render commands, -	// cached for performance. - -	struct TextureBindingKey { -		RID texture; -		RID normalmap; -		RID specular; -		RID multimesh; -		RS::CanvasItemTextureFilter texture_filter; -		RS::CanvasItemTextureRepeat texture_repeat; -		bool operator==(const TextureBindingKey &p_key) const { -			return texture == p_key.texture && normalmap == p_key.normalmap && specular == p_key.specular && multimesh == p_key.specular && texture_filter == p_key.texture_filter && texture_repeat == p_key.texture_repeat; -		} -	}; - -	struct TextureBindingKeyHasher { -		static _FORCE_INLINE_ uint32_t hash(const TextureBindingKey &p_key) { -			uint32_t hash = hash_djb2_one_64(p_key.texture.get_id()); -			hash = hash_djb2_one_64(p_key.normalmap.get_id(), hash); -			hash = hash_djb2_one_64(p_key.specular.get_id(), hash); -			hash = hash_djb2_one_64(p_key.multimesh.get_id(), hash); -			hash = hash_djb2_one_32(uint32_t(p_key.texture_filter) << 16 | uint32_t(p_key.texture_repeat), hash); -			return hash; -		} -	}; - -	struct TextureBinding { -		TextureBindingID id; -		TextureBindingKey key; -		SelfList<TextureBinding> to_dispose; -		uint32_t reference_count; -		RID uniform_set; -		TextureBinding() : -				to_dispose(this) { -			reference_count = 0; -		} -	}; - -	struct { -		SelfList<TextureBinding>::List to_dispose_list; - -		TextureBindingID id_generator; -		HashMap<TextureBindingKey, TextureBindingID, TextureBindingKeyHasher> texture_key_bindings; -		HashMap<TextureBindingID, TextureBinding *> texture_bindings; - -		TextureBindingID default_empty; -	} bindings; - -	RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh); -	void _dispose_bindings(); -  	struct {  		RS::CanvasItemTextureFilter default_filter;  		RS::CanvasItemTextureRepeat default_repeat; @@ -313,10 +265,10 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	struct CanvasLight {  		RID texture;  		struct { -			int size; -			RID texture; -			RID depth; -			RID fb; +			bool enabled = false; +			float z_far; +			float y_offset; +			Transform2D directional_xform;  		} shadow;  	}; @@ -326,7 +278,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {  		float projection[16];  		float modelview[8];  		float direction[2]; -		float pad[2]; +		float z_far; +		float pad;  	};  	struct OccluderPolygon { @@ -342,12 +295,17 @@ class RasterizerCanvasRD : public RasterizerCanvas {  		float matrix[8]; //light to texture coordinate matrix  		float shadow_matrix[8]; //light to shadow coordinate matrix  		float color[4]; -		float shadow_color[4]; -		float position[2]; + +		uint8_t shadow_color[4];  		uint32_t flags; //index to light texture -		float height;  		float shadow_pixel_size; -		float pad[3]; +		float height; + +		float position[2]; +		float shadow_z_far_inv; +		float shadow_y_ofs; + +		float atlas_rect[4];  	};  	RID_Owner<OccluderPolygon> occluder_polygon_owner; @@ -366,34 +324,6 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	//state that does not vary across rendering all items -	struct ItemStateData : public Item::CustomData { -		struct LightCache { -			uint64_t light_version; -			Light *light; -		}; - -		LightCache light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM]; -		uint32_t light_cache_count; -		RID state_uniform_set_with_light; -		RID state_uniform_set; -		ItemStateData() { -			for (int i = 0; i < DEFAULT_MAX_LIGHTS_PER_ITEM; i++) { -				light_cache[i].light_version = 0; -				light_cache[i].light = nullptr; -			} -			light_cache_count = 0xFFFFFFFF; -		} - -		~ItemStateData() { -			if (state_uniform_set_with_light.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set_with_light)) { -				RD::get_singleton()->free(state_uniform_set_with_light); -			} -			if (state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set)) { -				RD::get_singleton()->free(state_uniform_set); -			} -		} -	}; -  	struct State {  		//state buffer  		struct Buffer { @@ -401,12 +331,13 @@ class RasterizerCanvasRD : public RasterizerCanvas {  			float screen_transform[16];  			float canvas_normal_transform[16];  			float canvas_modulate[4]; +  			float screen_pixel_size[2];  			float time; -			float pad; +			uint32_t use_pixel_snap; -			//uint32_t light_count; -			//uint32_t pad[3]; +			uint32_t directional_light_count; +			uint32_t pad[3];  		};  		LightUniform *light_uniforms; @@ -414,11 +345,18 @@ class RasterizerCanvasRD : public RasterizerCanvas {  		RID lights_uniform_buffer;  		RID canvas_state_buffer;  		RID shadow_sampler; +		RID shadow_texture; +		RID shadow_depth_texture; +		RID shadow_fb; +		int shadow_texture_size = 2048; + +		RID default_transforms_uniform_set;  		uint32_t max_lights_per_render;  		uint32_t max_lights_per_item;  		double time; +  	} state;  	struct PushConstant { @@ -452,9 +390,20 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	Item *items[MAX_RENDER_ITEMS]; -	Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags); +	bool using_directional_lights = false; +	RID default_canvas_texture; + +	RID default_canvas_group_shader; +	RID default_canvas_group_material; + +	RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; +	RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; + +	RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer); + +	inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead.  	void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants); -	void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set); +	void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);  	_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);  	_FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); @@ -462,30 +411,30 @@ class RasterizerCanvasRD : public RasterizerCanvas {  	_FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4);  	_FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4); -	_FORCE_INLINE_ void _update_specular_shininess(const Color &p_transform, uint32_t *r_ss); +	void _update_shadow_atlas();  public: -	TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat, RID p_multimesh); -	void free_texture_binding(TextureBindingID p_binding); -  	PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>());  	void free_polygon(PolygonID p_polygon);  	RID light_create();  	void light_set_texture(RID p_rid, RID p_texture); -	void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution); -	void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders); +	void light_set_use_shadow(RID p_rid, bool p_enable); +	void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders); +	void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders);  	RID occluder_polygon_create();  	void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines);  	void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode); -	void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform); +	void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);  	void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {}  	void draw_window_margins(int *p_margins, RID *p_margin_textures) {} +	virtual void set_shadow_texture_size(int p_size); +  	void set_time(double p_time);  	void update();  	bool free(RID p_rid); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index e620ad954d..97c1e7ba70 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -30,8 +30,8 @@  #include "rasterizer_effects_rd.h" +#include "core/config/project_settings.h"  #include "core/os/os.h" -#include "core/project_settings.h"  #include "thirdparty/misc/cubemap_coeffs.h" @@ -246,7 +246,7 @@ void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_fr  	RD::get_singleton()->draw_list_end();  } -void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst) { +void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) {  	zeromem(©.push_constant, sizeof(CopyPushConstant));  	if (p_flip_y) {  		copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -260,6 +260,10 @@ void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_textu  		copy.push_constant.flags |= COPY_FLAG_ALL_SOURCE;  	} +	if (p_alpha_to_one) { +		copy.push_constant.flags |= COPY_FLAG_ALPHA_TO_ONE; +	} +  	copy.push_constant.section[0] = 0;  	copy.push_constant.section[1] = 0;  	copy.push_constant.section[2] = p_rect.size.width; @@ -354,6 +358,31 @@ void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest  	RD::get_singleton()->compute_list_end();  } +void RasterizerEffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { +	zeromem(©.push_constant, sizeof(CopyPushConstant)); + +	copy.push_constant.section[0] = 0; +	copy.push_constant.section[1] = 0; +	copy.push_constant.section[2] = p_region.size.width; +	copy.push_constant.section[3] = p_region.size.height; +	copy.push_constant.target[0] = p_region.position.x; +	copy.push_constant.target[1] = p_region.position.y; +	copy.push_constant.set_color[0] = p_color.r; +	copy.push_constant.set_color[1] = p_color.g; +	copy.push_constant.set_color[2] = p_color.b; +	copy.push_constant.set_color[3] = p_color.a; + +	int32_t x_groups = (p_region.size.width - 1) / 8 + 1; +	int32_t y_groups = (p_region.size.height - 1) / 8 + 1; + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_SET_COLOR_8BIT : COPY_MODE_SET_COLOR]); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); +	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); +	RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); +	RD::get_singleton()->compute_list_end(); +} +  void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) {  	zeromem(©.push_constant, sizeof(CopyPushConstant)); @@ -369,7 +398,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture,  	RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin();  	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]);  	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); -	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 0); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3);  	copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL;  	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); @@ -380,7 +409,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture,  	//VERTICAL  	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); -	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 0); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3);  	copy.push_constant.flags = base_flags;  	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); @@ -389,14 +418,14 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture,  	RD::get_singleton()->compute_list_end();  } -void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {  	zeromem(©.push_constant, sizeof(CopyPushConstant));  	CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW;  	uint32_t base_flags = 0; -	int32_t x_groups = (p_size.width - 1) / 8 + 1; -	int32_t y_groups = (p_size.height - 1) / 8 + 1; +	int32_t x_groups = (p_size.width + 7) / 8; +	int32_t y_groups = (p_size.height + 7) / 8;  	copy.push_constant.section[2] = p_size.x;  	copy.push_constant.section[3] = p_size.y; @@ -411,7 +440,6 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture,  	copy.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also -	//HORIZONTAL  	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();  	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]);  	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); @@ -420,20 +448,7 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture,  		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_auto_exposure), 1);  	} -	copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0); -	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - -	RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); -	RD::get_singleton()->compute_list_add_barrier(compute_list); - -	copy_mode = COPY_MODE_GAUSSIAN_GLOW; - -	//VERTICAL -	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]); -	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); -	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3); - -	copy.push_constant.flags = base_flags; +	copy.push_constant.flags = base_flags | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0) | (p_high_quality ? COPY_FLAG_HIGH_QUALITY_GLOW : 0);  	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant));  	RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); @@ -692,7 +707,13 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer,  	tonemap.push_constant.use_glow = p_settings.use_glow;  	tonemap.push_constant.glow_intensity = p_settings.glow_intensity; -	tonemap.push_constant.glow_level_flags = p_settings.glow_level_flags; +	tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something +	tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1]; +	tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2]; +	tonemap.push_constant.glow_levels[3] = p_settings.glow_levels[3]; +	tonemap.push_constant.glow_levels[4] = p_settings.glow_levels[4]; +	tonemap.push_constant.glow_levels[5] = p_settings.glow_levels[5]; +	tonemap.push_constant.glow_levels[6] = p_settings.glow_levels[6];  	tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x;  	tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y;  	tonemap.push_constant.glow_mode = p_settings.glow_mode; @@ -708,6 +729,7 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer,  	tonemap.push_constant.use_color_correction = p_settings.use_color_correction;  	tonemap.push_constant.use_fxaa = p_settings.use_fxaa; +	tonemap.push_constant.use_debanding = p_settings.use_debanding;  	tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x;  	tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; @@ -1171,7 +1193,7 @@ void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_des  	RD::get_singleton()->compute_list_end();  } -void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { +void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {  	SkyPushConstant sky_push_constant;  	zeromem(&sky_push_constant, sizeof(SkyPushConstant)); @@ -1198,7 +1220,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_  		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);  	}  	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2); -	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_lights, 3); +	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_fog, 3);  	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); @@ -1229,6 +1251,120 @@ void RasterizerEffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_rou  	RD::get_singleton()->compute_list_end();  } +void RasterizerEffectsRD::reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RD::ComputeListID compute_list) { +	uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, (uint32_t)p_shrink_limit, 0, 0, 0 }; + +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_REDUCE]); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_source_shadow, p_dest_shadow), 0); +	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8); + +	RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1); +} +void RasterizerEffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RenderingServer::EnvVolumetricFogShadowFilter p_filter, RD::ComputeListID compute_list, bool p_vertical, bool p_horizontal) { +	uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, 0, 0, 0, 0 }; + +	switch (p_filter) { +		case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED: +		case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW: { +			push_constant[5] = 0; +		} break; +		case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM: { +			push_constant[5] = 9; +		} break; +		case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_HIGH: { +			push_constant[5] = 18; +		} break; +	} + +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_FILTER]); +	if (p_vertical) { +		push_constant[6] = 1; +		push_constant[7] = 0; +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_shadow, p_backing_shadow), 0); +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8); +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1); +	} +	if (p_vertical && p_horizontal) { +		RD::get_singleton()->compute_list_add_barrier(compute_list); +	} +	if (p_horizontal) { +		push_constant[6] = 0; +		push_constant[7] = 1; +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_backing_shadow, p_shadow), 0); +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8); +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1); +	} +} + +void RasterizerEffectsRD::sort_buffer(RID p_uniform_set, int p_size) { +	Sort::PushConstant push_constant; +	push_constant.total_elements = p_size; + +	bool done = true; + +	int numThreadGroups = ((p_size - 1) >> 9) + 1; + +	if (numThreadGroups > 1) { +		done = false; +	} + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sort.pipelines[SORT_MODE_BLOCK]); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_uniform_set, 1); +	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(Sort::PushConstant)); +	RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1); + +	int presorted = 512; + +	while (!done) { +		RD::get_singleton()->compute_list_add_barrier(compute_list); + +		done = true; +		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sort.pipelines[SORT_MODE_STEP]); + +		numThreadGroups = 0; + +		if (p_size > presorted) { +			if (p_size > presorted * 2) { +				done = false; +			} + +			int pow2 = presorted; +			while (pow2 < p_size) { +				pow2 *= 2; +			} +			numThreadGroups = pow2 >> 9; +		} + +		unsigned int nMergeSize = presorted * 2; + +		for (unsigned int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 256; nMergeSubSize = nMergeSubSize >> 1) { +			push_constant.job_params[0] = nMergeSubSize; +			if (nMergeSubSize == nMergeSize >> 1) { +				push_constant.job_params[1] = (2 * nMergeSubSize - 1); +				push_constant.job_params[2] = -1; +			} else { +				push_constant.job_params[1] = nMergeSubSize; +				push_constant.job_params[2] = 1; +			} +			push_constant.job_params[3] = 0; + +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(Sort::PushConstant)); +			RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1); +			RD::get_singleton()->compute_list_add_barrier(compute_list); +		} + +		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sort.pipelines[SORT_MODE_INNER]); +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(Sort::PushConstant)); +		RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1); + +		presorted *= 2; +	} + +	RD::get_singleton()->compute_list_end(); +} +  RasterizerEffectsRD::RasterizerEffectsRD() {  	{ // Initialize copy  		Vector<String> copy_modes; @@ -1239,6 +1375,8 @@ RasterizerEffectsRD::RasterizerEffectsRD() {  		copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n");  		copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n#define DST_IMAGE_8BIT\n");  		copy_modes.push_back("\n#define MODE_SIMPLE_COPY_DEPTH\n"); +		copy_modes.push_back("\n#define MODE_SET_COLOR\n"); +		copy_modes.push_back("\n#define MODE_SET_COLOR\n#define DST_IMAGE_8BIT\n");  		copy_modes.push_back("\n#define MODE_MIPMAP\n");  		copy_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n");  		copy_modes.push_back("\n#define MODE_CUBEMAP_TO_PANORAMA\n"); @@ -1560,6 +1698,35 @@ RasterizerEffectsRD::RasterizerEffectsRD() {  		}  	} +	{ +		Vector<String> shadow_reduce_modes; +		shadow_reduce_modes.push_back("\n#define MODE_REDUCE\n"); +		shadow_reduce_modes.push_back("\n#define MODE_FILTER\n"); + +		shadow_reduce.shader.initialize(shadow_reduce_modes); + +		shadow_reduce.shader_version = shadow_reduce.shader.version_create(); + +		for (int i = 0; i < SHADOW_REDUCE_MAX; i++) { +			shadow_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(shadow_reduce.shader.version_get_shader(shadow_reduce.shader_version, i)); +		} +	} + +	{ +		Vector<String> sort_modes; +		sort_modes.push_back("\n#define MODE_SORT_BLOCK\n"); +		sort_modes.push_back("\n#define MODE_SORT_STEP\n"); +		sort_modes.push_back("\n#define MODE_SORT_INNER\n"); + +		sort.shader.initialize(sort_modes); + +		sort.shader_version = sort.shader.version_create(); + +		for (int i = 0; i < SORT_MODE_MAX; i++) { +			sort.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sort.shader.version_get_shader(sort.shader_version, i)); +		} +	} +  	RD::SamplerState sampler;  	sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;  	sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; @@ -1615,6 +1782,7 @@ RasterizerEffectsRD::~RasterizerEffectsRD() {  	resolve.shader.version_free(resolve.shader_version);  	roughness.shader.version_free(roughness.shader_version);  	roughness_limiter.shader.version_free(roughness_limiter.shader_version); +	sort.shader.version_free(sort.shader_version);  	specular_merge.shader.version_free(specular_merge.shader_version);  	ssao.blur_shader.version_free(ssao.blur_shader_version);  	ssao.gather_shader.version_free(ssao.gather_shader_version); @@ -1624,4 +1792,5 @@ RasterizerEffectsRD::~RasterizerEffectsRD() {  	ssr_scale.shader.version_free(ssr_scale.shader_version);  	sss.shader.version_free(sss.shader_version);  	tonemap.shader.version_free(tonemap.shader_version); +	shadow_reduce.shader.version_free(shadow_reduce.shader_version);  } diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h index 80849654de..a0bdd59fd2 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -46,6 +46,8 @@  #include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl.gen.h"  #include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h"  #include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/sort.glsl.gen.h"  #include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h"  #include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h"  #include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h" @@ -64,6 +66,8 @@ class RasterizerEffectsRD {  		COPY_MODE_SIMPLY_COPY,  		COPY_MODE_SIMPLY_COPY_8BIT,  		COPY_MODE_SIMPLY_COPY_DEPTH, +		COPY_MODE_SET_COLOR, +		COPY_MODE_SET_COLOR_8BIT,  		COPY_MODE_MIPMAP,  		COPY_MODE_LINEARIZE_DEPTH,  		COPY_MODE_CUBE_TO_PANORAMA, @@ -80,7 +84,9 @@ class RasterizerEffectsRD {  		COPY_FLAG_GLOW_FIRST_PASS = (1 << 4),  		COPY_FLAG_FLIP_Y = (1 << 5),  		COPY_FLAG_FORCE_LUMINANCE = (1 << 6), -		COPY_FLAG_ALL_SOURCE = (1 << 7) +		COPY_FLAG_ALL_SOURCE = (1 << 7), +		COPY_FLAG_HIGH_QUALITY_GLOW = (1 << 8), +		COPY_FLAG_ALPHA_TO_ONE = (1 << 9),  	};  	struct CopyPushConstant { @@ -102,6 +108,8 @@ class RasterizerEffectsRD {  		float camera_z_far;  		float camera_z_near;  		uint32_t pad2[2]; +		//SET color +		float set_color[4];  	};  	struct Copy { @@ -172,18 +180,20 @@ class RasterizerEffectsRD {  		uint32_t tonemapper;  		uint32_t glow_texture_size[2]; -  		float glow_intensity; -		uint32_t glow_level_flags; +		uint32_t pad3; +  		uint32_t glow_mode; +		float glow_levels[7];  		float exposure;  		float white;  		float auto_exposure_grey; +		uint32_t pad2;  		float pixel_size[2];  		uint32_t use_fxaa; -		uint32_t pad; +		uint32_t use_debanding;  	};  	/* tonemap actually writes to a framebuffer, which is @@ -534,6 +544,37 @@ class RasterizerEffectsRD {  		RID pipelines[RESOLVE_MODE_MAX]; //3 quality levels  	} resolve; +	enum ShadowReduceMode { +		SHADOW_REDUCE_REDUCE, +		SHADOW_REDUCE_FILTER, +		SHADOW_REDUCE_MAX +	}; + +	struct ShadowReduce { +		ShadowReduceShaderRD shader; +		RID shader_version; +		RID pipelines[SHADOW_REDUCE_MAX]; +	} shadow_reduce; + +	enum SortMode { +		SORT_MODE_BLOCK, +		SORT_MODE_STEP, +		SORT_MODE_INNER, +		SORT_MODE_MAX +	}; + +	struct Sort { +		struct PushConstant { +			uint32_t total_elements; +			uint32_t pad[3]; +			int32_t job_params[4]; +		}; + +		SortShaderRD shader; +		RID shader_version; +		RID pipelines[SORT_MODE_MAX]; +	} sort; +  	RID default_sampler;  	RID default_mipmap_sampler;  	RID index_buffer; @@ -567,13 +608,14 @@ class RasterizerEffectsRD {  public:  	void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); -	void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false); +	void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);  	void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);  	void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);  	void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);  	void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);  	void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); -	void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); +	void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false); +	void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);  	void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);  	void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); @@ -593,7 +635,7 @@ public:  		GlowMode glow_mode = GLOW_MODE_ADD;  		float glow_intensity = 1.0; -		uint32_t glow_level_flags = 0; +		float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 };  		Vector2i glow_texture_size;  		bool glow_use_bicubic_upscale = false;  		RID glow_texture; @@ -615,6 +657,7 @@ public:  		RID color_correction_texture;  		bool use_fxaa = false; +		bool use_debanding = false;  		Vector2i texture_size;  	}; @@ -625,7 +668,7 @@ public:  	void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);  	void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);  	void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); -	void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); +	void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);  	void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);  	void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); @@ -633,6 +676,11 @@ public:  	void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples); +	void reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RenderingDevice::ComputeListID compute_list); +	void filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RS::EnvVolumetricFogShadowFilter p_filter, RenderingDevice::ComputeListID compute_list, bool p_vertical = true, bool p_horizontal = true); + +	void sort_buffer(RID p_uniform_set, int p_size); +  	RasterizerEffectsRD();  	~RasterizerEffectsRD();  }; diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp index 18cf4fa340..5f8cf0ee8c 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp @@ -30,7 +30,7 @@  #include "rasterizer_rd.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h"  void RasterizerRD::prepare_for_blitting_render_targets() {  	RD::get_singleton()->prepare_screen_for_drawing(); @@ -90,7 +90,7 @@ void RasterizerRD::begin_frame(double frame_step) {  void RasterizerRD::end_frame(bool p_swap_buffers) {  #ifndef _MSC_VER -#warning TODO: likely passa bool to swap buffers to avoid display? +#warning TODO: likely pass a bool to swap buffers to avoid display?  #endif  	RD::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display?  } diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.h b/servers/rendering/rasterizer_rd/rasterizer_rd.h index cdcc6bfd73..59fb8d2049 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_rd.h @@ -32,7 +32,7 @@  #define RASTERIZER_RD_H  #include "core/os/os.h" -#include "core/thread_work_pool.h" +#include "core/templates/thread_work_pool.h"  #include "servers/rendering/rasterizer.h"  #include "servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h"  #include "servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h" diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index 8c122983da..a275e46473 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -29,7 +29,7 @@  /*************************************************************************/  #include "rasterizer_scene_high_end_rd.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h"  #include "servers/rendering/rendering_device.h"  #include "servers/rendering/rendering_server_raster.h" @@ -51,6 +51,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {  	int blend_mode = BLEND_MODE_MIX;  	int depth_testi = DEPTH_TEST_ENABLED; +	int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;  	int cull = CULL_BACK;  	uses_point_size = false; @@ -82,6 +83,9 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {  	actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);  	actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL); +	actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); +	actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); +  	actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);  	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);  	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS); @@ -154,6 +158,11 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {  	//blend modes +	// if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage +	if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { +		blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; +	} +  	RD::PipelineColorBlendState::Attachment blend_attachment;  	switch (blend_mode) { @@ -199,6 +208,15 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {  			blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;  			uses_blend_alpha = true; //force alpha used because of blend  		} break; +		case BLEND_MODE_ALPHA_TO_COVERAGE: { +			blend_attachment.enable_blend = true; +			blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; +			blend_attachment.color_blend_op = RD::BLEND_OP_ADD; +			blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; +			blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; +			blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; +			blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; +		}  	}  	RD::PipelineColorBlendState blend_state_blend; @@ -245,8 +263,17 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {  				RD::PipelineColorBlendState blend_state;  				RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; +				RD::PipelineMultisampleState multisample_state;  				if (uses_alpha || uses_blend_alpha) { +					// only allow these flags to go through if we have some form of msaa +					if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { +						multisample_state.enable_alpha_to_coverage = true; +					} else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { +						multisample_state.enable_alpha_to_coverage = true; +						multisample_state.enable_alpha_to_one = true; +					} +  					if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {  						blend_state = blend_state_blend;  						if (depth_draw == DEPTH_DRAW_OPAQUE) { @@ -286,7 +313,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {  				}  				RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k); -				pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, RD::PipelineMultisampleState(), depth_stencil, blend_state, 0); +				pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);  			}  		}  	} @@ -782,8 +809,7 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements,  	for (int i = 0; i < p_element_count; i++) {  		const RenderList::Element *e = p_elements[i];  		InstanceData &id = scene_state.instances[i]; -		RasterizerStorageRD::store_transform(e->instance->transform, id.transform); -		RasterizerStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform); +		bool store_transform = true;  		id.flags = 0;  		id.mask = e->instance->layer_mask;  		id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0; @@ -807,12 +833,42 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements,  			}  			id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); +		} else if (e->instance->base_type == RS::INSTANCE_PARTICLES) { +			id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; +			uint32_t stride; +			if (false) { // 2D particles +				id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; +				stride = 2; +			} else { +				stride = 3; +			} + +			id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; +			stride += 1; + +			id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; +			stride += 1; + +			id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + +			if (!storage->particles_is_using_local_coords(e->instance->base)) { +				store_transform = false; +			} +  		} else if (e->instance->base_type == RS::INSTANCE_MESH) {  			if (e->instance->skeleton.is_valid()) {  				id.flags |= INSTANCE_DATA_FLAG_SKELETON;  			}  		} +		if (store_transform) { +			RasterizerStorageRD::store_transform(e->instance->transform, id.transform); +			RasterizerStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform); +		} else { +			RasterizerStorageRD::store_transform(Transform(), id.transform); +			RasterizerStorageRD::store_transform(Transform(), id.normal_transform); +		} +  		if (p_for_depth) {  			id.gi_offset = 0xFFFFFFFF;  			continue; @@ -967,7 +1023,12 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l  				ERR_CONTINUE(true); //should be a bug  			} break;  			case RS::INSTANCE_PARTICLES: { -				ERR_CONTINUE(true); //should be a bug +				RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16); +				ERR_CONTINUE(!mesh.is_valid()); //should be a bug +				primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index & 0xFFFF); + +				xforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); +  			} break;  			default: {  				ERR_CONTINUE(true); //should be a bug @@ -1036,7 +1097,9 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l  				ERR_CONTINUE(true); //should be a bug  			} break;  			case RS::INSTANCE_PARTICLES: { -				ERR_CONTINUE(true); //should be a bug +				RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16); +				ERR_CONTINUE(!mesh.is_valid()); //should be a bug +				storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index & 0xFFFF, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);  			} break;  			default: {  				ERR_CONTINUE(true); //should be a bug @@ -1092,6 +1155,8 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l  			case RS::INSTANCE_IMMEDIATE: {  			} break;  			case RS::INSTANCE_PARTICLES: { +				uint32_t instances = storage->particles_get_amount(e->instance->base); +				RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances);  			} break;  			default: {  				ERR_CONTINUE(true); //should be a bug @@ -1145,12 +1210,31 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende  	scene_state.ubo.time = time;  	scene_state.ubo.gi_upscale_for_msaa = false; +	scene_state.ubo.volumetric_fog_enabled = false; +	scene_state.ubo.fog_enabled = false;  	if (p_render_buffers.is_valid()) {  		RenderBufferDataHighEnd *render_buffers = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);  		if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {  			scene_state.ubo.gi_upscale_for_msaa = true;  		} + +		if (render_buffers_has_volumetric_fog(p_render_buffers)) { +			scene_state.ubo.volumetric_fog_enabled = true; +			float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers); +			if (fog_end > 0.0) { +				scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; +			} else { +				scene_state.ubo.volumetric_fog_inv_length = 1.0; +			} + +			float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup +			if (fog_detail_spread > 0.0) { +				scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; +			} else { +				scene_state.ubo.volumetric_fog_detail_spread = 1.0; +			} +		}  	}  #if 0  	if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) { @@ -1265,12 +1349,30 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende  		scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_environment);  		scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_environment); -		Color ao_color = environment_get_ao_color(p_environment); +		Color ao_color = environment_get_ao_color(p_environment).to_linear();  		scene_state.ubo.ao_color[0] = ao_color.r;  		scene_state.ubo.ao_color[1] = ao_color.g;  		scene_state.ubo.ao_color[2] = ao_color.b;  		scene_state.ubo.ao_color[3] = ao_color.a; +		scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment); +		scene_state.ubo.fog_density = environment_get_fog_density(p_environment); +		scene_state.ubo.fog_height = environment_get_fog_height(p_environment); +		scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_environment); +		if (scene_state.ubo.fog_height_density >= 0.0001) { +			scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; +		} +		scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); + +		Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); +		float fog_energy = environment_get_fog_light_energy(p_environment); + +		scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; +		scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; +		scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; + +		scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); +  	} else {  		if (p_reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {  			scene_state.ubo.use_ambient_light = false; @@ -1488,31 +1590,31 @@ void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, i  				_add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass);  			} break; +#endif  			case RS::INSTANCE_PARTICLES: { +				int draw_passes = storage->particles_get_draw_passes(inst->base); -				RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(inst->base); -				ERR_CONTINUE(!particles); - -				for (int j = 0; j < particles->draw_passes.size(); j++) { - -					RID pmesh = particles->draw_passes[j]; -					if (!pmesh.is_valid()) +				for (int j = 0; j < draw_passes; j++) { +					RID mesh = storage->particles_get_draw_pass_mesh(inst->base, j); +					if (!mesh.is_valid())  						continue; -					RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getornull(pmesh); -					if (!mesh) -						continue; //mesh not assigned -					int ssize = mesh->surfaces.size(); +					const RID *materials = nullptr; +					uint32_t surface_count; -					for (int k = 0; k < ssize; k++) { +					materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); +					if (!materials) { +						continue; //nothing to do +					} -						RasterizerStorageGLES3::Surface *s = mesh->surfaces[k]; -						_add_geometry(s, inst, particles, -1, p_depth_pass, p_shadow_pass); +					for (uint32_t k = 0; k < surface_count; k++) { +						uint32_t surface_index = storage->mesh_surface_get_particles_render_pass_index(mesh, j, render_pass, &geometry_index); +						_add_geometry(inst, (j << 16) | k, materials[j], p_pass_mode, surface_index, p_using_sdfgi);  					}  				}  			} break; -#endif +  			default: {  			}  		} @@ -1671,6 +1773,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  	}  	RID radiance_uniform_set;  	bool draw_sky = false; +	bool draw_sky_fog_only = false;  	Color clear_color;  	bool keep_color = false; @@ -1686,12 +1789,20 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  				clear_color.r *= bg_energy;  				clear_color.g *= bg_energy;  				clear_color.b *= bg_energy; +				if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { +					draw_sky_fog_only = true; +					storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); +				}  			} break;  			case RS::ENV_BG_COLOR: {  				clear_color = environment_get_bg_color(p_environment);  				clear_color.r *= bg_energy;  				clear_color.g *= bg_energy;  				clear_color.b *= bg_energy; +				if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { +					draw_sky_fog_only = true; +					storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); +				}  			} break;  			case RS::ENV_BG_SKY: {  				draw_sky = true; @@ -1708,18 +1819,19 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  			}  		}  		// setup sky if used for ambient, reflections, or background -		if (draw_sky || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { +		if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { +			RENDER_TIMESTAMP("Setup Sky"); +			CameraMatrix projection = p_cam_projection; +			if (p_reflection_probe.is_valid()) { +				CameraMatrix correction; +				correction.set_depth_correction(true); +				projection = correction * p_cam_projection; +			} + +			_setup_sky(p_environment, p_render_buffer, projection, p_cam_transform, screen_size); +  			RID sky = environment_get_sky(p_environment);  			if (sky.is_valid()) { -				RENDER_TIMESTAMP("Setup Sky"); -				CameraMatrix projection = p_cam_projection; -				if (p_reflection_probe.is_valid()) { -					CameraMatrix correction; -					correction.set_depth_correction(true); -					projection = correction * p_cam_projection; -				} - -				_setup_sky(p_environment, p_cam_transform.origin, screen_size);  				_update_sky(p_environment, projection, p_cam_transform);  				radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);  			} else { @@ -1754,6 +1866,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  		RD::get_singleton()->draw_list_end();  		if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { +			RENDER_TIMESTAMP("Resolve Depth Pre-Pass");  			if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) {  				static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 };  				storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]); @@ -1787,8 +1900,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  	bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;  	{ -		bool will_continue_color = (can_continue_color || draw_sky || debug_giprobes || debug_sdfgi_probes); -		bool will_continue_depth = (can_continue_depth || draw_sky || debug_giprobes || debug_sdfgi_probes); +		bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes); +		bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);  		//regular forward for now  		Vector<Color> c; @@ -1815,8 +1928,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  	if (debug_giprobes) {  		//debug giprobes -		bool will_continue_color = (can_continue_color || draw_sky); -		bool will_continue_depth = (can_continue_depth || draw_sky); +		bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); +		bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);  		CameraMatrix dc;  		dc.set_depth_correction(true); @@ -1830,8 +1943,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  	if (debug_sdfgi_probes) {  		//debug giprobes -		bool will_continue_color = (can_continue_color || draw_sky); -		bool will_continue_depth = (can_continue_depth || draw_sky); +		bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); +		bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);  		CameraMatrix dc;  		dc.set_depth_correction(true); @@ -1841,7 +1954,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor  		RD::get_singleton()->draw_list_end();  	} -	if (draw_sky) { +	if (draw_sky || draw_sky_fog_only) {  		RENDER_TIMESTAMP("Render Sky");  		CameraMatrix projection = p_cam_projection; @@ -1933,6 +2046,39 @@ void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase **  	}  } +void RasterizerSceneHighEndRD::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) { +	RENDER_TIMESTAMP("Setup Render Collider Heightfield"); + +	_update_render_base_uniform_set(); + +	render_pass++; + +	scene_state.ubo.dual_paraboloid_side = 0; + +	_setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); + +	render_list.clear(); + +	PassMode pass_mode = PASS_MODE_SHADOW; + +	_fill_render_list(p_cull_result, p_cull_count, pass_mode); + +	_setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + +	RENDER_TIMESTAMP("Render Collider Heightield"); + +	render_list.sort_by_key(false); + +	_fill_instances(render_list.elements, render_list.element_count, true); + +	{ +		//regular forward for now +		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); +		_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_fb), render_list.elements, render_list.element_count, false, pass_mode, true, RID(), RID()); +		RD::get_singleton()->draw_list_end(); +	} +} +  void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {  	RENDER_TIMESTAMP("Setup Rendering Material"); @@ -2502,7 +2648,22 @@ void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_b  			u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers));  			uniforms.push_back(u);  		} - +		{ +			RD::Uniform u; +			u.binding = 10; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			RID vfog = RID(); +			if (p_render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_buffers)) { +				vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers); +				if (vfog.is_null()) { +					vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); +				} +			} else { +				vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); +			} +			u.ids.push_back(vfog); +			uniforms.push_back(u); +		}  		rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);  	}  } @@ -2591,6 +2752,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag  		actions.renames["POINT_SIZE"] = "gl_PointSize";  		actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; +		actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; +		actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; +		actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; +		actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; +  		//builtins  		actions.renames["TIME"] = "scene_data.time"; @@ -2628,12 +2794,16 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag  		actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";  		actions.renames["DEPTH"] = "gl_FragDepth";  		actions.renames["OUTPUT_IS_SRGB"] = "true"; +		actions.renames["FOG"] = "custom_fog"; +		actions.renames["RADIANCE"] = "custom_radiance"; +		actions.renames["IRRADIANCE"] = "custom_irradiance";  		//for light  		actions.renames["VIEW"] = "view";  		actions.renames["LIGHT_COLOR"] = "light_color";  		actions.renames["LIGHT"] = "light";  		actions.renames["ATTENUATION"] = "attenuation"; +		actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";  		actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";  		actions.renames["SPECULAR_LIGHT"] = "specular_light"; @@ -2655,6 +2825,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag  		actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";  		actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; +		actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; +		actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; +		actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; +		actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; +  		actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";  		actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";  		actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; @@ -2664,6 +2839,10 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag  		actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";  		actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; +		actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n"; +		actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n"; +		actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n"; +  		actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";  		actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";  		actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; @@ -2815,6 +2994,13 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag  			u.ids.push_back(render_buffers_get_default_gi_probe_buffer());  			uniforms.push_back(u);  		} +		{ +			RD::Uniform u; +			u.binding = 10; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +			uniforms.push_back(u); +		}  		default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);  	} diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h index a49173de98..db083a75cc 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h @@ -83,6 +83,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {  			BLEND_MODE_ADD,  			BLEND_MODE_SUB,  			BLEND_MODE_MUL, +			BLEND_MODE_ALPHA_TO_COVERAGE  		};  		enum DepthDraw { @@ -110,6 +111,12 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {  		}; +		enum AlphaAntiAliasing { +			ALPHA_ANTIALIASING_OFF, +			ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, +			ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE +		}; +  		bool valid;  		RID version;  		uint32_t vertex_input_mask; @@ -132,6 +139,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {  		bool uses_point_size;  		bool uses_alpha;  		bool uses_blend_alpha; +		bool uses_alpha_clip;  		bool uses_depth_pre_pass;  		bool uses_discard;  		bool uses_roughness; @@ -308,12 +316,6 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {  			float viewport_size[2];  			float screen_pixel_size[2]; -			float time; -			float reflection_multiplier; - -			uint32_t pancake_shadows; -			uint32_t pad; -  			float directional_penumbra_shadow_kernel[128]; //32 vec4s  			float directional_soft_shadow_kernel[128];  			float penumbra_shadow_kernel[128]; @@ -359,6 +361,27 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {  			int32_t sdf_size[3];  			uint32_t gi_upscale_for_msaa; + +			uint32_t volumetric_fog_enabled; +			float volumetric_fog_inv_length; +			float volumetric_fog_detail_spread; +			uint32_t volumetric_fog_pad; + +			// Fog +			uint32_t fog_enabled; +			float fog_density; +			float fog_height; +			float fog_height_density; + +			float fog_light_color[3]; +			float fog_sun_scatter; + +			float fog_aerial_perspective; + +			float time; +			float reflection_multiplier; + +			uint32_t pancake_shadows;  		};  		UBO ubo; @@ -566,6 +589,7 @@ protected:  	virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);  	virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);  	virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); +	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count);  public:  	virtual void set_time(double p_time, double p_step); diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp index bdf9b71c56..e1be9b0ef4 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -30,8 +30,8 @@  #include "rasterizer_scene_rd.h" +#include "core/config/project_settings.h"  #include "core/os/os.h" -#include "core/project_settings.h"  #include "rasterizer_rd.h"  #include "servers/rendering/rendering_server_raster.h" @@ -227,6 +227,7 @@ void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) {  	RD::get_singleton()->free(rb->sdfgi->lightprobe_data);  	RD::get_singleton()->free(rb->sdfgi->lightprobe_history_scroll);  	RD::get_singleton()->free(rb->sdfgi->occlusion_data); +	RD::get_singleton()->free(rb->sdfgi->ambient_texture);  	RD::get_singleton()->free(rb->sdfgi->cascades_ubo); @@ -371,6 +372,16 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co  			RD::TextureView tv;  			tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;  			sdfgi->lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->lightprobe_data); + +			//texture handling ambient data, to integrate with volumetric foc +			RD::TextureFormat tf_ambient = tf_probes; +			tf_ambient.array_layers = sdfgi->cascades.size(); +			tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE +			tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; +			tf_ambient.height = sdfgi->probe_axis_count; +			tf_ambient.type = RD::TEXTURE_TYPE_2D_ARRAY; +			//lightprobe texture is an octahedral texture +			sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());  		}  		sdfgi->cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES); @@ -930,6 +941,13 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co  				u.ids.push_back(parent_average);  				uniforms.push_back(u);  			} +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 14; +				u.ids.push_back(sdfgi->ambient_texture); +				uniforms.push_back(u); +			}  			sdfgi->cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 0);  		} @@ -1155,6 +1173,94 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm  	/* Update dynamic lights */  	{ +		int32_t cascade_light_count[SDFGI::MAX_CASCADES]; + +		for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { +			SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; + +			SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; +			uint32_t idx = 0; +			for (uint32_t j = 0; j < p_directional_light_count; j++) { +				if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { +					break; +				} + +				LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]); +				ERR_CONTINUE(!li); +				Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); +				dir.y *= rb->sdfgi->y_mult; +				dir.normalize(); +				lights[idx].direction[0] = dir.x; +				lights[idx].direction[1] = dir.y; +				lights[idx].direction[2] = dir.z; +				Color color = storage->light_get_color(li->light); +				color = color.to_linear(); +				lights[idx].color[0] = color.r; +				lights[idx].color[1] = color.g; +				lights[idx].color[2] = color.b; +				lights[idx].type = RS::LIGHT_DIRECTIONAL; +				lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); +				lights[idx].has_shadow = storage->light_has_shadow(li->light); + +				idx++; +			} + +			AABB cascade_aabb; +			cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size; +			cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size; + +			for (uint32_t j = 0; j < p_positional_light_count; j++) { +				if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { +					break; +				} + +				LightInstance *li = light_instance_owner.getornull(p_positional_light_instances[j]); +				ERR_CONTINUE(!li); + +				uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); +				if (i > max_sdfgi_cascade) { +					continue; +				} + +				if (!cascade_aabb.intersects(li->aabb)) { +					continue; +				} + +				Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); +				//faster to not do this here +				//dir.y *= rb->sdfgi->y_mult; +				//dir.normalize(); +				lights[idx].direction[0] = dir.x; +				lights[idx].direction[1] = dir.y; +				lights[idx].direction[2] = dir.z; +				Vector3 pos = li->transform.origin; +				pos.y *= rb->sdfgi->y_mult; +				lights[idx].position[0] = pos.x; +				lights[idx].position[1] = pos.y; +				lights[idx].position[2] = pos.z; +				Color color = storage->light_get_color(li->light); +				color = color.to_linear(); +				lights[idx].color[0] = color.r; +				lights[idx].color[1] = color.g; +				lights[idx].color[2] = color.b; +				lights[idx].type = storage->light_get_type(li->light); +				lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); +				lights[idx].has_shadow = storage->light_has_shadow(li->light); +				lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); +				lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); +				lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)); +				lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + +				idx++; +			} + +			if (idx > 0) { +				RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); +			} + +			cascade_light_count[i] = idx; +		} +  		RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();  		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]); @@ -1173,91 +1279,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm  		for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {  			SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; - -			{ //fill light buffer - -				SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; -				uint32_t idx = 0; -				for (uint32_t j = 0; j < p_directional_light_count; j++) { -					if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { -						break; -					} - -					LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]); -					ERR_CONTINUE(!li); -					Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); -					dir.y *= rb->sdfgi->y_mult; -					dir.normalize(); -					lights[idx].direction[0] = dir.x; -					lights[idx].direction[1] = dir.y; -					lights[idx].direction[2] = dir.z; -					Color color = storage->light_get_color(li->light); -					color = color.to_linear(); -					lights[idx].color[0] = color.r; -					lights[idx].color[1] = color.g; -					lights[idx].color[2] = color.b; -					lights[idx].type = RS::LIGHT_DIRECTIONAL; -					lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); -					lights[idx].has_shadow = storage->light_has_shadow(li->light); - -					idx++; -				} - -				AABB cascade_aabb; -				cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size; -				cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size; - -				for (uint32_t j = 0; j < p_positional_light_count; j++) { -					if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { -						break; -					} - -					LightInstance *li = light_instance_owner.getornull(p_positional_light_instances[j]); -					ERR_CONTINUE(!li); - -					uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); -					if (i > max_sdfgi_cascade) { -						continue; -					} - -					if (!cascade_aabb.intersects(li->aabb)) { -						continue; -					} - -					Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); -					//faster to not do this here -					//dir.y *= rb->sdfgi->y_mult; -					//dir.normalize(); -					lights[idx].direction[0] = dir.x; -					lights[idx].direction[1] = dir.y; -					lights[idx].direction[2] = dir.z; -					Vector3 pos = li->transform.origin; -					pos.y *= rb->sdfgi->y_mult; -					lights[idx].position[0] = pos.x; -					lights[idx].position[1] = pos.y; -					lights[idx].position[2] = pos.z; -					Color color = storage->light_get_color(li->light); -					color = color.to_linear(); -					lights[idx].color[0] = color.r; -					lights[idx].color[1] = color.g; -					lights[idx].color[2] = color.b; -					lights[idx].type = storage->light_get_type(li->light); -					lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); -					lights[idx].has_shadow = storage->light_has_shadow(li->light); -					lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); -					lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); -					lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)); -					lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); - -					idx++; -				} - -				if (idx > 0) { -					RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); -				} -				push_constant.light_count = idx; -			} - +			push_constant.light_count = cascade_light_count[i];  			push_constant.cascade = i;  			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0); @@ -1282,6 +1304,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm  	push_constant.ray_bias = rb->sdfgi->probe_bias;  	push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;  	push_constant.image_size[1] = rb->sdfgi->probe_axis_count; +	push_constant.store_ambient_texture = env->volumetric_fog_enabled;  	RID sky_uniform_set = sdfgi_shader.integrate_default_sky_uniform_set;  	push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_DISABLED; @@ -1375,6 +1398,96 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm  	RENDER_TIMESTAMP("<SDFGI Update Probes");  } +void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used) { +	r_gi_probes_used = 0; +	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND(rb == nullptr); + +	RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers); +	GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES]; + +	bool giprobes_changed = false; + +	Transform to_camera; +	to_camera.origin = p_transform.origin; //only translation, make local + +	for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { +		RID texture; +		if (i < p_gi_probe_cull_count) { +			GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); + +			if (gipi) { +				texture = gipi->texture; +				GI::GIProbeData &gipd = gi_probe_data[i]; + +				RID base_probe = gipi->probe; + +				Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera; + +				gipd.xform[0] = to_cell.basis.elements[0][0]; +				gipd.xform[1] = to_cell.basis.elements[1][0]; +				gipd.xform[2] = to_cell.basis.elements[2][0]; +				gipd.xform[3] = 0; +				gipd.xform[4] = to_cell.basis.elements[0][1]; +				gipd.xform[5] = to_cell.basis.elements[1][1]; +				gipd.xform[6] = to_cell.basis.elements[2][1]; +				gipd.xform[7] = 0; +				gipd.xform[8] = to_cell.basis.elements[0][2]; +				gipd.xform[9] = to_cell.basis.elements[1][2]; +				gipd.xform[10] = to_cell.basis.elements[2][2]; +				gipd.xform[11] = 0; +				gipd.xform[12] = to_cell.origin.x; +				gipd.xform[13] = to_cell.origin.y; +				gipd.xform[14] = to_cell.origin.z; +				gipd.xform[15] = 1; + +				Vector3 bounds = storage->gi_probe_get_octree_size(base_probe); + +				gipd.bounds[0] = bounds.x; +				gipd.bounds[1] = bounds.y; +				gipd.bounds[2] = bounds.z; + +				gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe); +				gipd.bias = storage->gi_probe_get_bias(base_probe); +				gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe); +				gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe); +				gipd.anisotropy_strength = 0; +				gipd.ao = storage->gi_probe_get_ao(base_probe); +				gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f); +				gipd.mipmaps = gipi->mipmaps.size(); +			} + +			r_gi_probes_used++; +		} + +		if (texture == RID()) { +			texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); +		} + +		if (texture != rb->giprobe_textures[i]) { +			giprobes_changed = true; +			rb->giprobe_textures[i] = texture; +		} +	} + +	if (giprobes_changed) { +		RD::get_singleton()->free(rb->gi_uniform_set); +		rb->gi_uniform_set = RID(); +		if (rb->volumetric_fog) { +			if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { +				RD::get_singleton()->free(rb->volumetric_fog->uniform_set); +				RD::get_singleton()->free(rb->volumetric_fog->uniform_set2); +			} +			rb->volumetric_fog->uniform_set = RID(); +			rb->volumetric_fog->uniform_set2 = RID(); +		} +	} + +	if (p_gi_probe_cull_count > 0) { +		RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true); +	} +} +  void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) {  	RENDER_TIMESTAMP("Render GI"); @@ -1490,81 +1603,6 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness  		RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, true);  	} -	{ -		RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers); -		GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES]; - -		bool giprobes_changed = false; - -		Transform to_camera; -		to_camera.origin = p_transform.origin; //only translation, make local - -		for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { -			RID texture; -			if (i < p_gi_probe_cull_count) { -				GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); - -				if (gipi) { -					texture = gipi->texture; -					GI::GIProbeData &gipd = gi_probe_data[i]; - -					RID base_probe = gipi->probe; - -					Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera; - -					gipd.xform[0] = to_cell.basis.elements[0][0]; -					gipd.xform[1] = to_cell.basis.elements[1][0]; -					gipd.xform[2] = to_cell.basis.elements[2][0]; -					gipd.xform[3] = 0; -					gipd.xform[4] = to_cell.basis.elements[0][1]; -					gipd.xform[5] = to_cell.basis.elements[1][1]; -					gipd.xform[6] = to_cell.basis.elements[2][1]; -					gipd.xform[7] = 0; -					gipd.xform[8] = to_cell.basis.elements[0][2]; -					gipd.xform[9] = to_cell.basis.elements[1][2]; -					gipd.xform[10] = to_cell.basis.elements[2][2]; -					gipd.xform[11] = 0; -					gipd.xform[12] = to_cell.origin.x; -					gipd.xform[13] = to_cell.origin.y; -					gipd.xform[14] = to_cell.origin.z; -					gipd.xform[15] = 1; - -					Vector3 bounds = storage->gi_probe_get_octree_size(base_probe); - -					gipd.bounds[0] = bounds.x; -					gipd.bounds[1] = bounds.y; -					gipd.bounds[2] = bounds.z; - -					gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe); -					gipd.bias = storage->gi_probe_get_bias(base_probe); -					gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe); -					gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe); -					gipd.anisotropy_strength = 0; -					gipd.ao = storage->gi_probe_get_ao(base_probe); -					gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f); -				} -			} - -			if (texture == RID()) { -				texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); -			} - -			if (texture != rb->giprobe_textures[i]) { -				giprobes_changed = true; -				rb->giprobe_textures[i] = texture; -			} -		} - -		if (giprobes_changed) { -			RD::get_singleton()->free(rb->gi_uniform_set); -			rb->gi_uniform_set = RID(); -		} - -		if (p_gi_probe_cull_count > 0) { -			RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true); -		} -	} -  	if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {  		Vector<RD::Uniform> uniforms;  		{ @@ -2032,22 +2070,33 @@ RID RasterizerSceneRD::sky_get_material(RID p_sky) const {  void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {  	ERR_FAIL_COND(!is_environment(p_environment)); +	SkyMaterialData *material = nullptr; +  	Sky *sky = sky_owner.getornull(environment_get_sky(p_environment)); -	ERR_FAIL_COND(!sky); -	RID sky_material = sky_get_material(environment_get_sky(p_environment)); +	RID sky_material; -	SkyMaterialData *material = nullptr; +	RS::EnvironmentBG background = environment_get_background(p_environment); -	if (sky_material.is_valid()) { -		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); -		if (!material || !material->shader_data->valid) { -			material = nullptr; +	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { +		ERR_FAIL_COND(!sky); +		sky_material = sky_get_material(environment_get_sky(p_environment)); + +		if (sky_material.is_valid()) { +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); +			if (!material || !material->shader_data->valid) { +				material = nullptr; +			} +		} + +		if (!material) { +			sky_material = sky_shader.default_material; +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);  		}  	} -	if (!material) { -		sky_material = sky_shader.default_material; +	if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { +		sky_material = sky_scene_state.fog_material;  		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);  	} @@ -2087,7 +2136,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue  		clear_colors.push_back(Color(0.0, 0.0, 0.0));  		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); -		storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); +		storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);  		RD::get_singleton()->draw_list_end();  	} @@ -2100,149 +2149,192 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue  		clear_colors.push_back(Color(0.0, 0.0, 0.0));  		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); -		storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); +		storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);  		RD::get_singleton()->draw_list_end();  	}  	RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; -	RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND); +	RID texture_uniform_set; +	if (sky) { +		texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND); +	} else { +		texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set; +	}  	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); -	storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); +	storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);  	RD::get_singleton()->draw_list_end();  } -void RasterizerSceneRD::_setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size) { +void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) {  	ERR_FAIL_COND(!is_environment(p_environment)); +	SkyMaterialData *material = nullptr; +  	Sky *sky = sky_owner.getornull(environment_get_sky(p_environment)); -	ERR_FAIL_COND(!sky); -	RID sky_material = sky_get_material(environment_get_sky(p_environment)); +	RID sky_material; -	SkyMaterialData *material = nullptr; +	SkyShaderData *shader_data = nullptr; -	if (sky_material.is_valid()) { -		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); -		if (!material || !material->shader_data->valid) { -			material = nullptr; +	RS::EnvironmentBG background = environment_get_background(p_environment); + +	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { +		ERR_FAIL_COND(!sky); +		sky_material = sky_get_material(environment_get_sky(p_environment)); + +		if (sky_material.is_valid()) { +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); +			if (!material || !material->shader_data->valid) { +				material = nullptr; +			}  		} -	} -	if (!material) { -		sky_material = sky_shader.default_material; -		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); -	} +		if (!material) { +			sky_material = sky_shader.default_material; +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); +		} -	ERR_FAIL_COND(!material); +		ERR_FAIL_COND(!material); -	SkyShaderData *shader_data = material->shader_data; +		shader_data = material->shader_data; -	ERR_FAIL_COND(!shader_data); +		ERR_FAIL_COND(!shader_data); +	} -	// Invalidate supbass buffers if screen size changes -	if (sky->screen_size != p_screen_size) { -		sky->screen_size = p_screen_size; -		sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x; -		sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y; -		if (shader_data->uses_half_res) { -			if (sky->half_res_pass.is_valid()) { -				RD::get_singleton()->free(sky->half_res_pass); -				sky->half_res_pass = RID(); +	if (sky) { +		// Invalidate supbass buffers if screen size changes +		if (sky->screen_size != p_screen_size) { +			sky->screen_size = p_screen_size; +			sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x; +			sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y; +			if (shader_data->uses_half_res) { +				if (sky->half_res_pass.is_valid()) { +					RD::get_singleton()->free(sky->half_res_pass); +					sky->half_res_pass = RID(); +				} +				_sky_invalidate(sky);  			} -			_sky_invalidate(sky); -		} -		if (shader_data->uses_quarter_res) { -			if (sky->quarter_res_pass.is_valid()) { -				RD::get_singleton()->free(sky->quarter_res_pass); -				sky->quarter_res_pass = RID(); +			if (shader_data->uses_quarter_res) { +				if (sky->quarter_res_pass.is_valid()) { +					RD::get_singleton()->free(sky->quarter_res_pass); +					sky->quarter_res_pass = RID(); +				} +				_sky_invalidate(sky);  			} +		} + +		// Create new subpass buffers if necessary +		if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) || +				(shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) || +				sky->radiance.is_null()) {  			_sky_invalidate(sky); +			_update_dirty_skys();  		} -	} -	// Create new subpass buffers if necessary -	if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) || -			(shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) || -			sky->radiance.is_null()) { -		_sky_invalidate(sky); -		_update_dirty_skys(); -	} +		if (shader_data->uses_time && time - sky->prev_time > 0.00001) { +			sky->prev_time = time; +			sky->reflection.dirty = true; +			RenderingServerRaster::redraw_request(); +		} -	if (shader_data->uses_time && time - sky->prev_time > 0.00001) { -		sky->prev_time = time; -		sky->reflection.dirty = true; -		RenderingServerRaster::redraw_request(); -	} +		if (material != sky->prev_material) { +			sky->prev_material = material; +			sky->reflection.dirty = true; +		} -	if (material != sky->prev_material) { -		sky->prev_material = material; -		sky->reflection.dirty = true; -	} +		if (material->uniform_set_updated) { +			material->uniform_set_updated = false; +			sky->reflection.dirty = true; +		} -	if (material->uniform_set_updated) { -		material->uniform_set_updated = false; -		sky->reflection.dirty = true; -	} +		if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) { +			sky->prev_position = p_transform.origin; +			sky->reflection.dirty = true; +		} -	if (!p_position.is_equal_approx(sky->prev_position) && shader_data->uses_position) { -		sky->prev_position = p_position; -		sky->reflection.dirty = true; -	} +		if (shader_data->uses_light) { +			// Check whether the directional_light_buffer changes +			bool light_data_dirty = false; -	if (shader_data->uses_light || sky_scene_state.light_uniform_set.is_null()) { -		// Check whether the directional_light_buffer changes -		bool light_data_dirty = false; - -		if (sky_scene_state.directional_light_count != sky_scene_state.last_frame_directional_light_count) { -			light_data_dirty = true; -			for (uint32_t i = sky_scene_state.directional_light_count; i < sky_scene_state.max_directional_lights; i++) { -				sky_scene_state.directional_lights[i].enabled = false; -			} -		} -		if (!light_data_dirty) { -			for (uint32_t i = 0; i < sky_scene_state.directional_light_count; i++) { -				if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] || -						sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] || -						sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] || -						sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy || -						sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] || -						sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] || -						sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] || -						sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled || -						sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) { -					light_data_dirty = true; -					break; +			if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) { +				light_data_dirty = true; +				for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) { +					sky_scene_state.directional_lights[i].enabled = false; +				} +			} +			if (!light_data_dirty) { +				for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) { +					if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] || +							sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] || +							sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] || +							sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy || +							sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] || +							sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] || +							sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] || +							sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled || +							sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) { +						light_data_dirty = true; +						break; +					}  				}  			} + +			if (light_data_dirty) { +				RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true); + +				RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; +				sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights; +				sky_scene_state.directional_lights = temp; +				sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count; +				sky->reflection.dirty = true; +			}  		} +	} -		if (light_data_dirty || sky_scene_state.light_uniform_set.is_null()) { -			RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true); +	//setup fog variables +	sky_scene_state.ubo.volumetric_fog_enabled = false; +	if (p_render_buffers.is_valid()) { +		if (render_buffers_has_volumetric_fog(p_render_buffers)) { +			sky_scene_state.ubo.volumetric_fog_enabled = true; -			if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) { -				RD::get_singleton()->free(sky_scene_state.light_uniform_set); +			float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers); +			if (fog_end > 0.0) { +				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; +			} else { +				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;  			} -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.binding = 0; -				u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -				u.ids.push_back(sky_scene_state.directional_light_buffer); -				uniforms.push_back(u); +			float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup +			if (fog_detail_spread > 0.0) { +				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; +			} else { +				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;  			} +		} -			sky_scene_state.light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_LIGHTS); +		RID fog_uniform_set = render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers); -			RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; -			sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights; -			sky_scene_state.directional_lights = temp; -			sky_scene_state.last_frame_directional_light_count = sky_scene_state.directional_light_count; -			sky->reflection.dirty = true; +		if (fog_uniform_set != RID()) { +			sky_scene_state.fog_uniform_set = fog_uniform_set; +		} else { +			sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;  		}  	} + +	sky_scene_state.ubo.z_far = p_projection.get_z_far(); +	sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment); +	sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment); +	sky_scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); +	Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); +	float fog_energy = environment_get_fog_light_energy(p_environment); +	sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; +	sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; +	sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; +	sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); + +	RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo, true);  }  void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { @@ -2337,7 +2429,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro  				RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES);  				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); -				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); +				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);  				RD::get_singleton()->draw_list_end();  			}  		} @@ -2355,7 +2447,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro  				RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_HALF_RES);  				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); -				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); +				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);  				RD::get_singleton()->draw_list_end();  			}  		} @@ -2369,7 +2461,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro  			RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP);  			cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); -			storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); +			storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);  			RD::get_singleton()->draw_list_end();  		} @@ -2845,11 +2937,12 @@ void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMa  	env->auto_exp_scale = p_auto_exp_scale;  } -void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {  	Environment *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env); +	ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7");  	env->glow_enabled = p_enable; -	env->glow_levels = p_level_flags; +	env->glow_levels = p_levels;  	env->glow_intensity = p_intensity;  	env->glow_strength = p_strength;  	env->glow_mix = p_mix; @@ -2864,6 +2957,10 @@ void RasterizerSceneRD::environment_glow_set_use_bicubic_upscale(bool p_enable)  	glow_bicubic_upscale = p_enable;  } +void RasterizerSceneRD::environment_glow_set_use_high_quality(bool p_enable) { +	glow_high_quality = p_enable; +} +  void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {  	Environment *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env); @@ -2880,6 +2977,106 @@ void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::Envi  	env->sdfgi_y_scale = p_y_scale;  } +void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { +	Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND(!env); + +	env->fog_enabled = p_enable; +	env->fog_light_color = p_light_color; +	env->fog_light_energy = p_light_energy; +	env->fog_sun_scatter = p_sun_scatter; +	env->fog_density = p_density; +	env->fog_height = p_height; +	env->fog_height_density = p_height_density; +	env->fog_aerial_perspective = p_fog_aerial_perspective; +} + +bool RasterizerSceneRD::environment_is_fog_enabled(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, false); + +	return env->fog_enabled; +} +Color RasterizerSceneRD::environment_get_fog_light_color(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, Color()); +	return env->fog_light_color; +} +float RasterizerSceneRD::environment_get_fog_light_energy(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, 0); +	return env->fog_light_energy; +} +float RasterizerSceneRD::environment_get_fog_sun_scatter(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, 0); +	return env->fog_sun_scatter; +} +float RasterizerSceneRD::environment_get_fog_density(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, 0); +	return env->fog_density; +} +float RasterizerSceneRD::environment_get_fog_height(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, 0); + +	return env->fog_height; +} +float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, 0); +	return env->fog_height_density; +} + +float RasterizerSceneRD::environment_get_fog_aerial_perspective(RID p_env) const { +	const Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND_V(!env, 0); +	return env->fog_aerial_perspective; +} + +void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) { +	Environment *env = environment_owner.getornull(p_env); +	ERR_FAIL_COND(!env); + +	env->volumetric_fog_enabled = p_enable; +	env->volumetric_fog_density = p_density; +	env->volumetric_fog_light = p_light; +	env->volumetric_fog_light_energy = p_light_energy; +	env->volumetric_fog_length = p_length; +	env->volumetric_fog_detail_spread = p_detail_spread; +	env->volumetric_fog_shadow_filter = p_shadow_filter; +	env->volumetric_fog_gi_inject = p_gi_inject; +} + +void RasterizerSceneRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { +	volumetric_fog_size = p_size; +	volumetric_fog_depth = p_depth; +} + +void RasterizerSceneRD::environment_set_volumetric_fog_filter_active(bool p_enable) { +	volumetric_fog_filter_active = p_enable; +} +void RasterizerSceneRD::environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) { +	p_shrink_size = nearest_power_of_2_templated(p_shrink_size); +	if (volumetric_fog_directional_shadow_shrink == (uint32_t)p_shrink_size) { +		return; +	} + +	_clear_shadow_shrink_stages(directional_shadow.shrink_stages); +} +void RasterizerSceneRD::environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) { +	p_shrink_size = nearest_power_of_2_templated(p_shrink_size); +	if (volumetric_fog_positional_shadow_shrink == (uint32_t)p_shrink_size) { +		return; +	} + +	for (uint32_t i = 0; i < shadow_atlas_owner.get_rid_count(); i++) { +		ShadowAtlas *sa = shadow_atlas_owner.get_ptr_by_index(i); +		_clear_shadow_shrink_stages(sa->shrink_stages); +	} +} +  void RasterizerSceneRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) {  	sdfgi_ray_count = p_ray_count;  } @@ -3286,6 +3483,7 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) {  	if (shadow_atlas->depth.is_valid()) {  		RD::get_singleton()->free(shadow_atlas->depth);  		shadow_atlas->depth = RID(); +		_clear_shadow_shrink_stages(shadow_atlas->shrink_stages);  	}  	for (int i = 0; i < 4; i++) {  		//clear subdivisions @@ -3579,6 +3777,7 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) {  	if (directional_shadow.depth.is_valid()) {  		RD::get_singleton()->free(directional_shadow.depth); +		_clear_shadow_shrink_stages(directional_shadow.shrink_stages);  		directional_shadow.depth = RID();  	} @@ -4951,6 +5150,8 @@ void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, R  	Environment *env = environment_owner.getornull(p_environment);  	ERR_FAIL_COND(!env); +	RENDER_TIMESTAMP("Process SSAO"); +  	if (rb->ssao.ao[0].is_valid() && rb->ssao.ao_full.is_valid() != ssao_half_size) {  		RD::get_singleton()->free(rb->ssao.depth);  		RD::get_singleton()->free(rb->ssao.ao[0]); @@ -5049,25 +5250,21 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu  	}  	int max_glow_level = -1; -	int glow_mask = 0;  	if (can_use_effects && env && env->glow_enabled) {  		/* see that blur textures are allocated */ -		if (rb->blur[0].texture.is_null()) { +		if (rb->blur[1].texture.is_null()) {  			_allocate_blur_textures(rb);  			_render_buffers_uniform_set_changed(p_render_buffers);  		}  		for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { -			if (env->glow_levels & (1 << i)) { +			if (env->glow_levels[i] > 0.0) {  				if (i >= rb->blur[1].mipmaps.size()) {  					max_glow_level = rb->blur[1].mipmaps.size() - 1; -					glow_mask |= 1 << max_glow_level; -  				} else {  					max_glow_level = i; -					glow_mask |= (1 << i);  				}  			}  		} @@ -5081,9 +5278,9 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu  				if (env->auto_exposure && rb->luminance.current.is_valid()) {  					luminance_texture = rb->luminance.current;  				} -				storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); +				storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);  			} else { -				storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength); +				storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality);  			}  		}  	} @@ -5106,7 +5303,9 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu  			tonemap.use_glow = true;  			tonemap.glow_mode = RasterizerEffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode);  			tonemap.glow_intensity = env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? env->glow_mix : env->glow_intensity; -			tonemap.glow_level_flags = glow_mask; +			for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { +				tonemap.glow_levels[i] = env->glow_levels[i]; +			}  			tonemap.glow_texture_size.x = rb->blur[1].mipmaps[0].width;  			tonemap.glow_texture_size.y = rb->blur[1].mipmaps[0].height;  			tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale; @@ -5119,6 +5318,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu  			tonemap.use_fxaa = true;  		} +		tonemap.use_debanding = rb->use_debanding;  		tonemap.texture_size = Vector2i(rb->width, rb->height);  		if (env) { @@ -5463,13 +5663,49 @@ RID RasterizerSceneRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_b  	return rb->sdfgi->occlusion_texture;  } -void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) { +bool RasterizerSceneRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const { +	const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND_V(!rb, false); + +	return rb->volumetric_fog != nullptr; +} +RID RasterizerSceneRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) { +	const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID()); + +	return rb->volumetric_fog->fog_map; +} + +RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) { +	const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND_V(!rb, RID()); + +	if (!rb->volumetric_fog) { +		return RID(); +	} + +	return rb->volumetric_fog->sky_uniform_set; +} + +float RasterizerSceneRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) { +	const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); +	return rb->volumetric_fog->length; +} +float RasterizerSceneRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) { +	const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); +	return rb->volumetric_fog->spread; +} + +void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	rb->width = p_width;  	rb->height = p_height;  	rb->render_target = p_render_target;  	rb->msaa = p_msaa;  	rb->screen_space_aa = p_screen_space_aa; +	rb->use_debanding = p_use_debanding;  	_free_render_buffer_data(rb);  	{ @@ -5679,10 +5915,11 @@ void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result,  	}  } -void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count) { +void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {  	uint32_t light_count = 0;  	r_directional_light_count = 0; -	sky_scene_state.directional_light_count = 0; +	r_positional_light_count = 0; +	sky_scene_state.ubo.directional_light_count = 0;  	for (int i = 0; i < p_light_cull_count; i++) {  		RID li = p_light_cull_result[i]; @@ -5797,7 +6034,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull  						light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale;  						light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j);  						light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale; -						light_data.shadow_transmittance_z_scale[j] = light_instance_get_shadow_range(li, j); +						light_data.shadow_z_range[j] = light_instance_get_shadow_range(li, j);  						light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j);  						RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrices[j]); @@ -5826,6 +6063,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull  					float fade_start = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);  					light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep  					light_data.fade_to = -light_data.shadow_split_offsets[3]; +					light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);  					light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);  					light_data.softshadow_angle = angular_diameter; @@ -5853,7 +6091,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull  					sky_light_data.enabled = true;  					sky_light_data.size = angular_diameter; -					sky_scene_state.directional_light_count++; +					sky_scene_state.ubo.directional_light_count++;  				}  				r_directional_light_count++; @@ -5867,6 +6105,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull  				Transform light_transform = light_instance_get_base_transform(li);  				Cluster::LightData &light_data = cluster.lights[light_count]; +				cluster.lights_instances[light_count] = li;  				float sign = storage->light_is_negative(base) ? -1 : 1;  				Color linear_col = storage->light_get_color(base).to_linear(); @@ -5965,6 +6204,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull  					light_data.atlas_rect[3] = rect.size.height;  					light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); +					light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);  					if (type == RS::LIGHT_OMNI) {  						light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another @@ -6005,6 +6245,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull  				cluster.builder.add_light(type == RS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);  				light_count++; +				r_positional_light_count++;  			} break;  		} @@ -6152,6 +6393,552 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_  	}  } +void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) { +	ERR_FAIL_COND(!rb->volumetric_fog); + +	RD::get_singleton()->free(rb->volumetric_fog->light_density_map); +	RD::get_singleton()->free(rb->volumetric_fog->fog_map); + +	if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { +		RD::get_singleton()->free(rb->volumetric_fog->uniform_set); +	} +	if (rb->volumetric_fog->uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set2)) { +		RD::get_singleton()->free(rb->volumetric_fog->uniform_set2); +	} +	if (rb->volumetric_fog->sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) { +		RD::get_singleton()->free(rb->volumetric_fog->sdfgi_uniform_set); +	} +	if (rb->volumetric_fog->sky_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sky_uniform_set)) { +		RD::get_singleton()->free(rb->volumetric_fog->sky_uniform_set); +	} + +	memdelete(rb->volumetric_fog); + +	rb->volumetric_fog = nullptr; +} + +void RasterizerSceneRD::_allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size) { +	//create fog mipmaps +	uint32_t fog_texture_size = p_target_size; +	uint32_t base_texture_size = p_base_size; + +	ShadowShrinkStage first; +	first.size = base_texture_size; +	first.texture = p_base; +	shrink_stages.push_back(first); //put depth first in case we dont find smaller ones + +	while (fog_texture_size < base_texture_size) { +		base_texture_size = MAX(base_texture_size / 8, fog_texture_size); + +		ShadowShrinkStage s; +		s.size = base_texture_size; + +		RD::TextureFormat tf; +		tf.format = RD::DATA_FORMAT_R32_SFLOAT; +		tf.width = base_texture_size; +		tf.height = base_texture_size; +		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + +		if (base_texture_size == fog_texture_size) { +			s.filter_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); +			tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; +		} + +		s.texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + +		shrink_stages.push_back(s); +	} +} + +void RasterizerSceneRD::_clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages) { +	for (int i = 1; i < shrink_stages.size(); i++) { +		RD::get_singleton()->free(shrink_stages[i].texture); +		if (shrink_stages[i].filter_texture.is_valid()) { +			RD::get_singleton()->free(shrink_stages[i].filter_texture); +		} +	} +	shrink_stages.clear(); +} + +void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) { +	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND(!rb); +	Environment *env = environment_owner.getornull(p_environment); + +	float ratio = float(rb->width) / float((rb->width + rb->height) / 2); +	uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio); +	uint32_t target_height = uint32_t(float(volumetric_fog_size) / ratio); + +	if (rb->volumetric_fog) { +		//validate +		if (!env || !env->volumetric_fog_enabled || rb->volumetric_fog->width != target_width || rb->volumetric_fog->height != target_height || rb->volumetric_fog->depth != volumetric_fog_depth) { +			_volumetric_fog_erase(rb); +			_render_buffers_uniform_set_changed(p_render_buffers); +		} +	} + +	if (!env || !env->volumetric_fog_enabled) { +		//no reason to enable or update, bye +		return; +	} + +	if (env && env->volumetric_fog_enabled && !rb->volumetric_fog) { +		//required volumetric fog but not existing, create +		rb->volumetric_fog = memnew(VolumetricFog); +		rb->volumetric_fog->width = target_width; +		rb->volumetric_fog->height = target_height; +		rb->volumetric_fog->depth = volumetric_fog_depth; + +		RD::TextureFormat tf; +		tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +		tf.width = target_width; +		tf.height = target_height; +		tf.depth = volumetric_fog_depth; +		tf.type = RD::TEXTURE_TYPE_3D; +		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + +		rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + +		tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; + +		rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); +		_render_buffers_uniform_set_changed(p_render_buffers); + +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.binding = 0; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(rb->volumetric_fog->fog_map); +			uniforms.push_back(u); +		} + +		rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG); +	} + +	//update directional shadow + +	if (p_use_directional_shadows) { +		if (directional_shadow.shrink_stages.empty()) { +			if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { +				//invalidate uniform set, we will need a new one +				RD::get_singleton()->free(rb->volumetric_fog->uniform_set); +				rb->volumetric_fog->uniform_set = RID(); +			} +			_allocate_shadow_shrink_stages(directional_shadow.depth, directional_shadow.size, directional_shadow.shrink_stages, volumetric_fog_directional_shadow_shrink); +		} + +		if (directional_shadow.shrink_stages.size() > 1) { +			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +			for (int i = 1; i < directional_shadow.shrink_stages.size(); i++) { +				int32_t src_size = directional_shadow.shrink_stages[i - 1].size; +				int32_t dst_size = directional_shadow.shrink_stages[i].size; +				Rect2i r(0, 0, src_size, src_size); +				int32_t shrink_limit = 8 / (src_size / dst_size); + +				storage->get_effects()->reduce_shadow(directional_shadow.shrink_stages[i - 1].texture, directional_shadow.shrink_stages[i].texture, Size2i(src_size, src_size), r, shrink_limit, compute_list); +				RD::get_singleton()->compute_list_add_barrier(compute_list); +				if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && directional_shadow.shrink_stages[i].filter_texture.is_valid()) { +					Rect2i rf(0, 0, dst_size, dst_size); +					storage->get_effects()->filter_shadow(directional_shadow.shrink_stages[i].texture, directional_shadow.shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), rf, env->volumetric_fog_shadow_filter, compute_list); +				} +			} +			RD::get_singleton()->compute_list_end(); +		} +	} + +	ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + +	if (shadow_atlas) { +		//shrink shadows that need to be shrunk + +		bool force_shrink_shadows = false; + +		if (shadow_atlas->shrink_stages.empty()) { +			if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { +				//invalidate uniform set, we will need a new one +				RD::get_singleton()->free(rb->volumetric_fog->uniform_set); +				rb->volumetric_fog->uniform_set = RID(); +			} +			_allocate_shadow_shrink_stages(shadow_atlas->depth, shadow_atlas->size, shadow_atlas->shrink_stages, volumetric_fog_positional_shadow_shrink); +			force_shrink_shadows = true; +		} + +		if (rb->volumetric_fog->last_shadow_filter != env->volumetric_fog_shadow_filter) { +			//if shadow filter changed, invalidate caches +			rb->volumetric_fog->last_shadow_filter = env->volumetric_fog_shadow_filter; +			force_shrink_shadows = true; +		} + +		cluster.lights_shadow_rect_cache_count = 0; + +		for (int i = 0; i < p_positional_light_count; i++) { +			if (cluster.lights[i].shadow_color_enabled[3] > 127) { +				RID li = cluster.lights_instances[i]; + +				ERR_CONTINUE(!shadow_atlas->shadow_owners.has(li)); + +				uint32_t key = shadow_atlas->shadow_owners[li]; + +				uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; +				uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + +				ERR_CONTINUE((int)shadow >= shadow_atlas->quadrants[quadrant].shadows.size()); + +				ShadowAtlas::Quadrant::Shadow &s = shadow_atlas->quadrants[quadrant].shadows.write[shadow]; + +				if (!force_shrink_shadows && s.fog_version == s.version) { +					continue; //do not update, no need +				} + +				s.fog_version = s.version; + +				uint32_t quadrant_size = shadow_atlas->size >> 1; + +				Rect2i atlas_rect; + +				atlas_rect.position.x = (quadrant & 1) * quadrant_size; +				atlas_rect.position.y = (quadrant >> 1) * quadrant_size; + +				uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); +				atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; +				atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + +				atlas_rect.size.x = shadow_size; +				atlas_rect.size.y = shadow_size; + +				cluster.lights_shadow_rect_cache[cluster.lights_shadow_rect_cache_count] = atlas_rect; + +				cluster.lights_shadow_rect_cache_count++; + +				if (cluster.lights_shadow_rect_cache_count == cluster.max_lights) { +					break; //light limit reached +				} +			} +		} + +		if (cluster.lights_shadow_rect_cache_count > 0) { +			//there are shadows to be shrunk, try to do them in parallel +			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +			for (int i = 1; i < shadow_atlas->shrink_stages.size(); i++) { +				int32_t base_size = shadow_atlas->shrink_stages[0].size; +				int32_t src_size = shadow_atlas->shrink_stages[i - 1].size; +				int32_t dst_size = shadow_atlas->shrink_stages[i].size; + +				uint32_t rect_divisor = base_size / src_size; + +				int32_t shrink_limit = 8 / (src_size / dst_size); + +				//shrink in parallel for more performance +				for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) { +					Rect2i src_rect = cluster.lights_shadow_rect_cache[j]; + +					src_rect.position /= rect_divisor; +					src_rect.size /= rect_divisor; + +					storage->get_effects()->reduce_shadow(shadow_atlas->shrink_stages[i - 1].texture, shadow_atlas->shrink_stages[i].texture, Size2i(src_size, src_size), src_rect, shrink_limit, compute_list); +				} + +				RD::get_singleton()->compute_list_add_barrier(compute_list); + +				if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && shadow_atlas->shrink_stages[i].filter_texture.is_valid()) { +					uint32_t filter_divisor = base_size / dst_size; + +					//filter in parallel for more performance +					for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) { +						Rect2i dst_rect = cluster.lights_shadow_rect_cache[j]; + +						dst_rect.position /= filter_divisor; +						dst_rect.size /= filter_divisor; + +						storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, true, false); +					} + +					RD::get_singleton()->compute_list_add_barrier(compute_list); + +					for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) { +						Rect2i dst_rect = cluster.lights_shadow_rect_cache[j]; + +						dst_rect.position /= filter_divisor; +						dst_rect.size /= filter_divisor; + +						storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, false, true); +					} +				} +			} + +			RD::get_singleton()->compute_list_end(); +		} +	} + +	//update volumetric fog + +	if (rb->volumetric_fog->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { +		//re create uniform set if needed + +		Vector<RD::Uniform> uniforms; + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 1; +			if (shadow_atlas == nullptr || shadow_atlas->shrink_stages.size() == 0) { +				u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); +			} else { +				u.ids.push_back(shadow_atlas->shrink_stages[shadow_atlas->shrink_stages.size() - 1].texture); +			} + +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 2; +			if (directional_shadow.shrink_stages.size() == 0) { +				u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); +			} else { +				u.ids.push_back(directional_shadow.shrink_stages[directional_shadow.shrink_stages.size() - 1].texture); +			} +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 3; +			u.ids.push_back(get_positional_light_buffer()); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.binding = 4; +			u.ids.push_back(get_directional_light_buffer()); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 5; +			u.ids.push_back(get_cluster_builder_texture()); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 6; +			u.ids.push_back(get_cluster_builder_indices_buffer()); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 7; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 8; +			u.ids.push_back(rb->volumetric_fog->light_density_map); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 9; +			u.ids.push_back(rb->volumetric_fog->fog_map); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 10; +			u.ids.push_back(shadow_sampler); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.binding = 11; +			u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 12; +			for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { +				u.ids.push_back(rb->giprobe_textures[i]); +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 13; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} + +		rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0); + +		SWAP(uniforms.write[7].ids.write[0], uniforms.write[8].ids.write[0]); + +		rb->volumetric_fog->uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0); +	} + +	bool using_sdfgi = env->volumetric_fog_gi_inject > 0.0001 && env->sdfgi_enabled && (rb->sdfgi != nullptr); + +	if (using_sdfgi) { +		if (rb->volumetric_fog->sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) { +			Vector<RD::Uniform> uniforms; + +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +				u.binding = 0; +				u.ids.push_back(gi.sdfgi_ubo); +				uniforms.push_back(u); +			} + +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_TEXTURE; +				u.binding = 1; +				u.ids.push_back(rb->sdfgi->ambient_texture); +				uniforms.push_back(u); +			} + +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_TEXTURE; +				u.binding = 2; +				u.ids.push_back(rb->sdfgi->occlusion_texture); +				uniforms.push_back(u); +			} + +			rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI), 1); +		} +	} + +	rb->volumetric_fog->length = env->volumetric_fog_length; +	rb->volumetric_fog->spread = env->volumetric_fog_detail_spread; + +	VolumetricFogShader::PushConstant push_constant; + +	Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents(); +	Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents(); +	float z_near = p_cam_projection.get_z_near(); +	float z_far = p_cam_projection.get_z_far(); +	float fog_end = env->volumetric_fog_length; + +	Vector2 fog_far_size = frustum_near_size.lerp(frustum_far_size, (fog_end - z_near) / (z_far - z_near)); +	Vector2 fog_near_size; +	if (p_cam_projection.is_orthogonal()) { +		fog_near_size = fog_far_size; +	} else { +		fog_near_size = Vector2(); +	} + +	push_constant.fog_frustum_size_begin[0] = fog_near_size.x; +	push_constant.fog_frustum_size_begin[1] = fog_near_size.y; + +	push_constant.fog_frustum_size_end[0] = fog_far_size.x; +	push_constant.fog_frustum_size_end[1] = fog_far_size.y; + +	push_constant.z_near = z_near; +	push_constant.z_far = z_far; + +	push_constant.fog_frustum_end = fog_end; + +	push_constant.fog_volume_size[0] = rb->volumetric_fog->width; +	push_constant.fog_volume_size[1] = rb->volumetric_fog->height; +	push_constant.fog_volume_size[2] = rb->volumetric_fog->depth; + +	push_constant.directional_light_count = p_directional_light_count; + +	Color light = env->volumetric_fog_light.to_linear(); +	push_constant.light_energy[0] = light.r * env->volumetric_fog_light_energy; +	push_constant.light_energy[1] = light.g * env->volumetric_fog_light_energy; +	push_constant.light_energy[2] = light.b * env->volumetric_fog_light_energy; +	push_constant.base_density = env->volumetric_fog_density; + +	push_constant.detail_spread = env->volumetric_fog_detail_spread; +	push_constant.gi_inject = env->volumetric_fog_gi_inject; + +	push_constant.cam_rotation[0] = p_cam_transform.basis[0][0]; +	push_constant.cam_rotation[1] = p_cam_transform.basis[1][0]; +	push_constant.cam_rotation[2] = p_cam_transform.basis[2][0]; +	push_constant.cam_rotation[3] = 0; +	push_constant.cam_rotation[4] = p_cam_transform.basis[0][1]; +	push_constant.cam_rotation[5] = p_cam_transform.basis[1][1]; +	push_constant.cam_rotation[6] = p_cam_transform.basis[2][1]; +	push_constant.cam_rotation[7] = 0; +	push_constant.cam_rotation[8] = p_cam_transform.basis[0][2]; +	push_constant.cam_rotation[9] = p_cam_transform.basis[1][2]; +	push_constant.cam_rotation[10] = p_cam_transform.basis[2][2]; +	push_constant.cam_rotation[11] = 0; +	push_constant.filter_axis = 0; +	push_constant.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0; + +	/*	Vector2 dssize = directional_shadow_get_size(); +	push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x; +	push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y; +*/ +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +	bool use_filter = volumetric_fog_filter_active; + +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]); + +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); +	if (using_sdfgi) { +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1); +	} +	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); +	RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 4, 4, 4); + +	RD::get_singleton()->compute_list_add_barrier(compute_list); + +	if (use_filter) { +		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]); +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); + +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1); + +		RD::get_singleton()->compute_list_add_barrier(compute_list); + +		push_constant.filter_axis = 1; + +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0); +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1); + +		RD::get_singleton()->compute_list_add_barrier(compute_list); +	} + +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); +	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); +	RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1, 8, 8, 1); + +	RD::get_singleton()->compute_list_end(); +} +  void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {  	Color clear_color;  	if (p_render_buffers.is_valid()) { @@ -6190,10 +6977,25 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca  	}  	uint32_t directional_light_count = 0; -	_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count); +	uint32_t positional_light_count = 0; +	_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count, positional_light_count);  	_setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse());  	cluster.builder.bake_cluster(); //bake to cluster +	uint32_t gi_probe_count = 0; +	_setup_giprobes(p_render_buffers, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count, gi_probe_count); + +	if (p_render_buffers.is_valid()) { +		bool directional_shadows = false; +		for (uint32_t i = 0; i < directional_light_count; i++) { +			if (cluster.directional_lights[i].shadow_enabled) { +				directional_shadows = true; +				break; +			} +		} +		_update_volumetric_fog(p_render_buffers, p_environment, p_cam_projection, p_cam_transform, p_shadow_atlas, directional_light_count, directional_shadows, positional_light_count, gi_probe_count); +	} +  	_render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);  	if (p_render_buffers.is_valid()) { @@ -6438,8 +7240,9 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc  		push_constant.grid_size = rb->sdfgi->cascade_size;  		push_constant.cascade = cascade; -		RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();  		if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) { +			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +  			//must pre scroll existing data because not all is dirty  			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL]);  			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_uniform_set, 0); @@ -6481,6 +7284,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc  				ipush_constant.sky_color[1] = 0;  				ipush_constant.sky_color[2] = 0;  				ipush_constant.y_mult = rb->sdfgi->y_mult; +				ipush_constant.store_ambient_texture = false;  				ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;  				ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; @@ -6512,13 +7316,15 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc  			}  			//ok finally barrier -			RD::get_singleton()->compute_list_add_barrier(compute_list); +			RD::get_singleton()->compute_list_end();  		}  		//clear dispatch indirect data  		uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 };  		RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data, true); +		RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +  		bool half_size = true; //much faster, very little difference  		static const int optimized_jf_group_size = 8; @@ -6721,6 +7527,23 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc  	}  } +void RasterizerSceneRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) { +	ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider)); +	Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale(); +	CameraMatrix cm; +	cm.set_orthogonal(-extents.x, extents.x, -extents.z, extents.z, 0, extents.y * 2.0); + +	Vector3 cam_pos = p_transform.origin; +	cam_pos.y += extents.y; + +	Transform cam_xform; +	cam_xform.set_look_at(cam_pos, cam_pos - p_transform.basis.get_axis(Vector3::AXIS_Y), -p_transform.basis.get_axis(Vector3::AXIS_Z).normalized()); + +	RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider); + +	_render_particle_collider_heightfield(fb, cam_xform, cm, p_cull_result, p_cull_count); +} +  void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(!rb); @@ -6836,6 +7659,9 @@ bool RasterizerSceneRD::free(RID p_rid) {  		if (rb->sdfgi) {  			_sdfgi_erase(rb);  		} +		if (rb->volumetric_fog) { +			_volumetric_fog_erase(rb); +		}  		render_buffers_owner.free(p_rid);  	} else if (environment_owner.owns(p_rid)) {  		//not much to delete, just free it @@ -7182,6 +8008,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  		actions.renames["HALF_RES_COLOR"] = "half_res_color";  		actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";  		actions.renames["RADIANCE"] = "radiance"; +		actions.renames["FOG"] = "custom_fog";  		actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";  		actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz";  		actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w"; @@ -7208,6 +8035,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  		actions.custom_samplers["RADIANCE"] = "material_samplers[3]";  		actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";  		actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n"; +		actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";  		actions.sampler_array_name = "material_samplers";  		actions.base_texture_binding_index = 1; @@ -7232,6 +8060,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  		SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);  		sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND); +		sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO)); +  		Vector<RD::Uniform> uniforms;  		{ @@ -7263,7 +8093,70 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  			uniforms.push_back(u);  		} -		sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS); +		{ +			RD::Uniform u; +			u.binding = 2; +			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.ids.push_back(sky_scene_state.uniform_buffer); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.binding = 3; +			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.ids.push_back(sky_scene_state.directional_light_buffer); +			uniforms.push_back(u); +		} + +		sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS); +	} + +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.binding = 0; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			RID vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); +			u.ids.push_back(vfog); +			uniforms.push_back(u); +		} + +		sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG); +	} + +	{ +		// Need defaults for using fog with clear color +		sky_scene_state.fog_shader = storage->shader_create(); +		storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n"); +		sky_scene_state.fog_material = storage->material_create(); +		storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader); + +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 0; +			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 1; +			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 2; +			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); +			uniforms.push_back(u); +		} + +		sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);  	}  	{ @@ -7406,6 +8299,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  		cluster.lights = memnew_arr(Cluster::LightData, cluster.max_lights);  		cluster.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);  		//defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(cluster.max_lights) + "\n"; +		cluster.lights_instances = memnew_arr(RID, cluster.max_lights); +		cluster.lights_shadow_rect_cache = memnew_arr(Rect2i, cluster.max_lights);  		cluster.max_directional_lights = 8;  		uint32_t directional_light_buffer_size = cluster.max_directional_lights * sizeof(Cluster::DirectionalLightData); @@ -7422,8 +8317,30 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  	cluster.builder.setup(16, 8, 24); +	{ +		String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; +		Vector<String> volumetric_fog_modes; +		volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n"); +		volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n"); +		volumetric_fog_modes.push_back("\n#define MODE_FILTER\n"); +		volumetric_fog_modes.push_back("\n#define MODE_FOG\n"); +		volumetric_fog.shader.initialize(volumetric_fog_modes, defines); +		volumetric_fog.shader_version = volumetric_fog.shader.version_create(); +		for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) { +			volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i)); +		} +	}  	default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); +	{ +		RD::SamplerState sampler; +		sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; +		sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; +		sampler.enable_compare = true; +		sampler.compare_op = RD::COMPARE_OP_LESS; +		shadow_sampler = RD::get_singleton()->sampler_create(sampler); +	} +  	camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape"))));  	camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter"));  	environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); @@ -7431,6 +8348,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  	screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount");  	screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit");  	glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; +	glow_high_quality = GLOBAL_GET("rendering/quality/glow/use_high_quality");  	ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));  	sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));  	sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale"); @@ -7441,6 +8359,11 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {  	soft_shadow_kernel = memnew_arr(float, 128);  	shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality"))));  	directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality")))); + +	environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/volumetric_fog/volume_size"), GLOBAL_GET("rendering/volumetric_fog/volume_depth")); +	environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/volumetric_fog/use_filter")); +	environment_set_volumetric_fog_directional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/directional_shadow_shrink")); +	environment_set_volumetric_fog_positional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/positional_shadow_shrink"));  }  RasterizerSceneRD::~RasterizerSceneRD() { @@ -7451,11 +8374,8 @@ RasterizerSceneRD::~RasterizerSceneRD() {  		RD::get_singleton()->free(E->get().cubemap);  	} -	if (sky_scene_state.sampler_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.sampler_uniform_set)) { -		RD::get_singleton()->free(sky_scene_state.sampler_uniform_set); -	} -	if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) { -		RD::get_singleton()->free(sky_scene_state.light_uniform_set); +	if (sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) { +		RD::get_singleton()->free(sky_scene_state.uniform_set);  	}  	RD::get_singleton()->free(default_giprobe_buffer); @@ -7471,14 +8391,19 @@ RasterizerSceneRD::~RasterizerSceneRD() {  	sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);  	sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); +	volumetric_fog.shader.version_free(volumetric_fog.shader_version); +  	memdelete_arr(gi_probe_lights);  	SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);  	sky_shader.shader.version_free(md->shader_data->version);  	RD::get_singleton()->free(sky_scene_state.directional_light_buffer); +	RD::get_singleton()->free(sky_scene_state.uniform_buffer);  	memdelete_arr(sky_scene_state.directional_lights);  	memdelete_arr(sky_scene_state.last_frame_directional_lights);  	storage->free(sky_shader.default_shader);  	storage->free(sky_shader.default_material); +	storage->free(sky_scene_state.fog_shader); +	storage->free(sky_scene_state.fog_material);  	memdelete_arr(directional_penumbra_shadow_kernel);  	memdelete_arr(directional_soft_shadow_kernel);  	memdelete_arr(penumbra_shadow_kernel); @@ -7491,7 +8416,13 @@ RasterizerSceneRD::~RasterizerSceneRD() {  		RD::get_singleton()->free(cluster.decal_buffer);  		memdelete_arr(cluster.directional_lights);  		memdelete_arr(cluster.lights); +		memdelete_arr(cluster.lights_shadow_rect_cache); +		memdelete_arr(cluster.lights_instances);  		memdelete_arr(cluster.reflections);  		memdelete_arr(cluster.decals);  	} + +	RD::get_singleton()->free(shadow_sampler); + +	directional_shadow_atlas_set_size(0);  } diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h index 27eec44ec3..3d5310bb7e 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h @@ -31,8 +31,8 @@  #ifndef RASTERIZER_SCENE_RD_H  #define RASTERIZER_SCENE_RD_H -#include "core/local_vector.h" -#include "core/rid_owner.h" +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h"  #include "servers/rendering/rasterizer.h"  #include "servers/rendering/rasterizer_rd/light_cluster_builder.h"  #include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" @@ -45,6 +45,7 @@  #include "servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl.gen.h"  #include "servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl.gen.h"  #include "servers/rendering/rasterizer_rd/shaders/sky.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl.gen.h"  #include "servers/rendering/rendering_device.h"  class RasterizerSceneRD : public RasterizerScene { @@ -62,14 +63,38 @@ protected:  	};  	struct SkySceneState { +		struct UBO { +			uint32_t volumetric_fog_enabled; +			float volumetric_fog_inv_length; +			float volumetric_fog_detail_spread; + +			float fog_aerial_perspective; + +			float fog_light_color[3]; +			float fog_sun_scatter; + +			uint32_t fog_enabled; +			float fog_density; + +			float z_far; +			uint32_t directional_light_count; +		}; + +		UBO ubo; +  		SkyDirectionalLightData *directional_lights;  		SkyDirectionalLightData *last_frame_directional_lights;  		uint32_t max_directional_lights; -		uint32_t directional_light_count;  		uint32_t last_frame_directional_light_count;  		RID directional_light_buffer; -		RID sampler_uniform_set; -		RID light_uniform_set; +		RID uniform_set; +		RID uniform_buffer; +		RID fog_uniform_set; +		RID default_fog_uniform_set; + +		RID fog_shader; +		RID fog_material; +		RID fog_only_texture_uniform_set;  	} sky_scene_state;  	struct RenderBufferData { @@ -78,15 +103,17 @@ protected:  	};  	virtual RenderBufferData *_create_render_buffer_data() = 0; -	void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count); +	void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);  	void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform);  	void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment); +	void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used);  	virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0;  	virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0;  	virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;  	virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;  	virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; +	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) = 0;  	virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);  	void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); @@ -103,7 +130,7 @@ protected:  	void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);  	void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera); -	void _setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size); +	void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size);  	void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);  	void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);  	void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); @@ -242,10 +269,10 @@ private:  	};  	enum SkySet { -		SKY_SET_SAMPLERS, +		SKY_SET_UNIFORMS,  		SKY_SET_MATERIAL,  		SKY_SET_TEXTURES, -		SKY_SET_LIGHTS, +		SKY_SET_FOG,  		SKY_SET_MAX  	}; @@ -334,7 +361,7 @@ private:  	mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; -	/* REFLECTION PROBE INSTANCE */ +	/* DECAL INSTANCE */  	struct DecalInstance {  		RID decal; @@ -490,6 +517,12 @@ private:  	/* SHADOW ATLAS */ +	struct ShadowShrinkStage { +		RID texture; +		RID filter_texture; +		uint32_t size; +	}; +  	struct ShadowAtlas {  		enum {  			QUADRANT_SHIFT = 27, @@ -503,10 +536,12 @@ private:  			struct Shadow {  				RID owner;  				uint64_t version; +				uint64_t fog_version; // used for fog  				uint64_t alloc_tick;  				Shadow() {  					version = 0; +					fog_version = 0;  					alloc_tick = 0;  				}  			}; @@ -528,6 +563,8 @@ private:  		RID fb; //for copying  		Map<RID, uint32_t> shadow_owners; + +		Vector<ShadowShrinkStage> shrink_stages;  	};  	RID_Owner<ShadowAtlas> shadow_atlas_owner; @@ -556,8 +593,14 @@ private:  		int light_count = 0;  		int size = 0;  		int current_light = 0; + +		Vector<ShadowShrinkStage> shrink_stages; +  	} directional_shadow; +	void _allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size); +	void _clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages); +  	/* SHADOW CUBEMAPS */  	struct ShadowCubemap { @@ -656,10 +699,31 @@ private:  		float auto_exp_scale = 0.5;  		uint64_t auto_exposure_version = 0; +		// Fog +		bool fog_enabled = false; +		Color fog_light_color = Color(0.5, 0.6, 0.7); +		float fog_light_energy = 1.0; +		float fog_sun_scatter = 0.0; +		float fog_density = 0.001; +		float fog_height = 0.0; +		float fog_height_density = 0.0; //can be negative to invert effect +		float fog_aerial_perspective = 0.0; + +		/// Volumetric Fog +		/// +		bool volumetric_fog_enabled = false; +		float volumetric_fog_density = 0.01; +		Color volumetric_fog_light = Color(0, 0, 0); +		float volumetric_fog_light_energy = 0.0; +		float volumetric_fog_length = 64.0; +		float volumetric_fog_detail_spread = 2.0; +		RS::EnvVolumetricFogShadowFilter volumetric_fog_shadow_filter = RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW; +		float volumetric_fog_gi_inject = 0.0; +  		/// Glow  		bool glow_enabled = false; -		int glow_levels = (1 << 2) | (1 << 4); +		Vector<float> glow_levels;  		float glow_intensity = 0.8;  		float glow_strength = 1.0;  		float glow_bloom = 0.0; @@ -704,6 +768,7 @@ private:  	RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;  	bool ssao_half_size = false;  	bool glow_bicubic_upscale = false; +	bool glow_high_quality = false;  	RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW;  	static uint64_t auto_exposure_counter; @@ -739,6 +804,7 @@ private:  	/* RENDER BUFFERS */  	struct SDFGI; +	struct VolumetricFog;  	struct RenderBuffers {  		enum { @@ -749,6 +815,7 @@ private:  		int width = 0, height = 0;  		RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;  		RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; +		bool use_debanding = false;  		RID render_target; @@ -759,6 +826,7 @@ private:  		RID gi_uniform_set;  		SDFGI *sdfgi = nullptr; +		VolumetricFog *volumetric_fog = nullptr;  		//built-in textures used for ping pong image processing and blurring  		struct Blur { @@ -885,6 +953,7 @@ private:  		RID lightprobe_data;  		RID occlusion_texture;  		RID occlusion_data; +		RID ambient_texture; //integrates with volumetric fog  		RID lightprobe_history_scroll; //used for scrolling lightprobes  		RID lightprobe_average_scroll; //used for scrolling lightprobes @@ -1077,6 +1146,9 @@ private:  			float sky_color[3];  			float y_mult; + +			uint32_t store_ambient_texture; +			uint32_t pad[3];  		};  		SdfgiIntegrateShaderRD integrate; @@ -1141,7 +1213,7 @@ private:  			float anisotropy_strength;  			float ao;  			float ao_size; -			uint32_t pad[1]; +			uint32_t mipmaps;  		};  		struct PushConstant { @@ -1219,7 +1291,8 @@ private:  			float soft_shadow_size;  			float soft_shadow_scale;  			uint32_t mask; -			uint32_t pad[2]; +			float shadow_volumetric_fog_fade; +			uint32_t pad;  			float projector_rect[4];  		}; @@ -1236,10 +1309,12 @@ private:  			uint32_t shadow_enabled;  			float fade_from;  			float fade_to; +			uint32_t pad[3]; +			float shadow_volumetric_fog_fade;  			float shadow_bias[4];  			float shadow_normal_bias[4];  			float shadow_transmittance_bias[4]; -			float shadow_transmittance_z_scale[4]; +			float shadow_z_range[4];  			float shadow_range_begin[4];  			float shadow_split_offsets[4];  			float shadow_matrices[4][16]; @@ -1283,6 +1358,9 @@ private:  		LightData *lights;  		uint32_t max_lights;  		RID light_buffer; +		RID *lights_instances; +		Rect2i *lights_shadow_rect_cache; +		uint32_t lights_shadow_rect_cache_count = 0;  		DirectionalLightData *directional_lights;  		uint32_t max_directional_lights; @@ -1292,6 +1370,74 @@ private:  	} cluster; +	struct VolumetricFog { +		uint32_t width = 0; +		uint32_t height = 0; +		uint32_t depth = 0; + +		float length; +		float spread; + +		RID light_density_map; +		RID fog_map; +		RID uniform_set; +		RID uniform_set2; +		RID sdfgi_uniform_set; +		RID sky_uniform_set; + +		int last_shadow_filter = -1; +	}; + +	enum { +		VOLUMETRIC_FOG_SHADER_DENSITY, +		VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI, +		VOLUMETRIC_FOG_SHADER_FILTER, +		VOLUMETRIC_FOG_SHADER_FOG, +		VOLUMETRIC_FOG_SHADER_MAX, +	}; + +	struct VolumetricFogShader { +		struct PushConstant { +			float fog_frustum_size_begin[2]; +			float fog_frustum_size_end[2]; + +			float fog_frustum_end; +			float z_near; +			float z_far; +			uint32_t filter_axis; + +			int32_t fog_volume_size[3]; +			uint32_t directional_light_count; + +			float light_energy[3]; +			float base_density; + +			float detail_spread; +			float gi_inject; +			uint32_t max_gi_probes; +			uint32_t pad; + +			float cam_rotation[12]; +		}; + +		VolumetricFogShaderRD shader; + +		RID shader_version; +		RID pipelines[VOLUMETRIC_FOG_SHADER_MAX]; + +	} volumetric_fog; + +	uint32_t volumetric_fog_depth = 128; +	uint32_t volumetric_fog_size = 128; +	bool volumetric_fog_filter_active = false; +	uint32_t volumetric_fog_directional_shadow_shrink = 512; +	uint32_t volumetric_fog_positional_shadow_shrink = 512; + +	void _volumetric_fog_erase(RenderBuffers *rb); +	void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count); + +	RID shadow_sampler; +  	uint64_t scene_pass = 0;  	uint64_t shadow_atlas_realloc_tolerance_msec = 500; @@ -1387,10 +1533,26 @@ public:  	bool is_environment(RID p_env) const; -	void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); +	void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);  	void environment_glow_set_use_bicubic_upscale(bool p_enable); +	void environment_glow_set_use_high_quality(bool p_enable); + +	void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective); +	bool environment_is_fog_enabled(RID p_env) const; +	Color environment_get_fog_light_color(RID p_env) const; +	float environment_get_fog_light_energy(RID p_env) const; +	float environment_get_fog_sun_scatter(RID p_env) const; +	float environment_get_fog_density(RID p_env) const; +	float environment_get_fog_height(RID p_env) const; +	float environment_get_fog_height_density(RID p_env) const; +	float environment_get_fog_aerial_perspective(RID p_env) const; + +	void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter); -	void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} +	virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth); +	virtual void environment_set_volumetric_fog_filter_active(bool p_enable); +	virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size); +	virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size);  	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);  	void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness); @@ -1411,10 +1573,6 @@ public:  	void environment_set_tonemap(RID p_env, RS::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);  	void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} -	void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {} -	void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} -	void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {} -  	virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size);  	virtual RID camera_effects_create(); @@ -1688,7 +1846,7 @@ public:  	}  */  	RID render_buffers_create(); -	void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa); +	void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding);  	RID render_buffers_get_ao_texture(RID p_render_buffers);  	RID render_buffers_get_back_buffer_texture(RID p_render_buffers); @@ -1708,6 +1866,12 @@ public:  	float render_buffers_get_sdfgi_energy(RID p_render_buffers) const;  	RID render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const; +	bool render_buffers_has_volumetric_fog(RID p_render_buffers) const; +	RID render_buffers_get_volumetric_fog_texture(RID p_render_buffers); +	RID render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers); +	float render_buffers_get_volumetric_fog_end(RID p_render_buffers); +	float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); +  	void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);  	void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); @@ -1717,6 +1881,8 @@ public:  	void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count);  	void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count); +	void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count); +  	virtual void set_scene_pass(uint64_t p_pass) {  		scene_pass = p_pass;  	} diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index 102e0e2eed..8bd4362637 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -30,9 +30,10 @@  #include "rasterizer_storage_rd.h" -#include "core/engine.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h"  #include "core/io/resource_loader.h" -#include "core/project_settings.h" +#include "rasterizer_rd.h"  #include "servers/rendering/shader_language.h"  Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { @@ -714,8 +715,120 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l  	return texture_owner.make_rid(texture);  } -RID RasterizerStorageRD::texture_3d_create(const Vector<Ref<Image>> &p_slices) { -	return RID(); +RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { +	ERR_FAIL_COND_V(p_data.size() == 0, RID()); +	Image::Image3DValidateError verr = Image::validate_3d_image(p_format, p_width, p_height, p_depth, p_mipmaps, p_data); +	if (verr != Image::VALIDATE_3D_OK) { +		ERR_FAIL_V_MSG(RID(), Image::get_3d_image_validation_error_text(verr)); +	} + +	TextureToRDFormat ret_format; +	Image::Format validated_format = Image::FORMAT_MAX; +	Vector<uint8_t> all_data; +	uint32_t mipmap_count = 0; +	Vector<Texture::BufferSlice3D> slices; +	{ +		Vector<Ref<Image>> images; +		uint32_t all_data_size = 0; +		images.resize(p_data.size()); +		for (int i = 0; i < p_data.size(); i++) { +			TextureToRDFormat f; +			images.write[i] = _validate_texture_format(p_data[i], f); +			if (i == 0) { +				ret_format = f; +				validated_format = images[0]->get_format(); +			} + +			all_data_size += images[i]->get_data().size(); +		} + +		all_data.resize(all_data_size); //consolidate all data here +		uint32_t offset = 0; +		Size2i prev_size; +		for (int i = 0; i < p_data.size(); i++) { +			uint32_t s = images[i]->get_data().size(); + +			copymem(&all_data.write[offset], images[i]->get_data().ptr(), s); +			{ +				Texture::BufferSlice3D slice; +				slice.size.width = images[i]->get_width(); +				slice.size.height = images[i]->get_height(); +				slice.offset = offset; +				slice.buffer_size = s; +				slices.push_back(slice); +			} +			offset += s; + +			Size2i img_size(images[i]->get_width(), images[i]->get_height()); +			if (img_size != prev_size) { +				mipmap_count++; +			} +			prev_size = img_size; +		} +	} + +	Texture texture; + +	texture.type = Texture::TYPE_3D; +	texture.width = p_width; +	texture.height = p_height; +	texture.depth = p_depth; +	texture.mipmaps = mipmap_count; +	texture.format = p_data[0]->get_format(); +	texture.validated_format = validated_format; + +	texture.buffer_size_3d = all_data.size(); +	texture.buffer_slices_3d = slices; + +	texture.rd_type = RD::TEXTURE_TYPE_3D; +	texture.rd_format = ret_format.format; +	texture.rd_format_srgb = ret_format.format_srgb; + +	RD::TextureFormat rd_format; +	RD::TextureView rd_view; +	{ //attempt register +		rd_format.format = texture.rd_format; +		rd_format.width = texture.width; +		rd_format.height = texture.height; +		rd_format.depth = texture.depth; +		rd_format.array_layers = 1; +		rd_format.mipmaps = texture.mipmaps; +		rd_format.type = texture.rd_type; +		rd_format.samples = RD::TEXTURE_SAMPLES_1; +		rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; +		if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { +			rd_format.shareable_formats.push_back(texture.rd_format); +			rd_format.shareable_formats.push_back(texture.rd_format_srgb); +		} +	} +	{ +		rd_view.swizzle_r = ret_format.swizzle_r; +		rd_view.swizzle_g = ret_format.swizzle_g; +		rd_view.swizzle_b = ret_format.swizzle_b; +		rd_view.swizzle_a = ret_format.swizzle_a; +	} +	Vector<Vector<uint8_t>> data_slices; +	data_slices.push_back(all_data); //one slice + +	texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices); +	ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID()); +	if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { +		rd_view.format_override = texture.rd_format_srgb; +		texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture); +		if (texture.rd_texture_srgb.is_null()) { +			RD::get_singleton()->free(texture.rd_texture); +			ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID()); +		} +	} + +	//used for 2D, overridable +	texture.width_2d = texture.width; +	texture.height_2d = texture.height; +	texture.is_render_target = false; +	texture.rd_view = rd_view; +	texture.is_proxy = false; + +	return texture_owner.make_rid(texture);  }  RID RasterizerStorageRD::texture_proxy_create(RID p_base) { @@ -771,7 +884,41 @@ void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_i  	_texture_2d_update(p_texture, p_image, p_layer, false);  } -void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) { +void RasterizerStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) { +	Texture *tex = texture_owner.getornull(p_texture); +	ERR_FAIL_COND(!tex); +	ERR_FAIL_COND(tex->type != Texture::TYPE_3D); +	Image::Image3DValidateError verr = Image::validate_3d_image(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps > 1, p_data); +	if (verr != Image::VALIDATE_3D_OK) { +		ERR_FAIL_MSG(Image::get_3d_image_validation_error_text(verr)); +	} + +	Vector<uint8_t> all_data; +	{ +		Vector<Ref<Image>> images; +		uint32_t all_data_size = 0; +		images.resize(p_data.size()); +		for (int i = 0; i < p_data.size(); i++) { +			Ref<Image> image = p_data[i]; +			if (image->get_format() != tex->validated_format) { +				image = image->duplicate(); +				image->convert(tex->validated_format); +			} +			all_data_size += images[i]->get_data().size(); +			images.push_back(image); +		} + +		all_data.resize(all_data_size); //consolidate all data here +		uint32_t offset = 0; + +		for (int i = 0; i < p_data.size(); i++) { +			uint32_t s = images[i]->get_data().size(); +			copymem(&all_data.write[offset], images[i]->get_data().ptr(), s); +			offset += s; +		} +	} + +	RD::get_singleton()->texture_update(tex->rd_texture, 0, all_data, true);  }  void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { @@ -857,7 +1004,25 @@ RID RasterizerStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayere  }  RID RasterizerStorageRD::texture_3d_placeholder_create() { -	return RID(); +	//this could be better optimized to reuse an existing image , done this way +	//for now to get it working +	Ref<Image> image; +	image.instance(); +	image->create(4, 4, false, Image::FORMAT_RGBA8); + +	for (int i = 0; i < 4; i++) { +		for (int j = 0; j < 4; j++) { +			image->set_pixel(i, j, Color(1, 0, 1, 1)); +		} +	} + +	Vector<Ref<Image>> images; +	//cube +	for (int i = 0; i < 4; i++) { +		images.push_back(image); +	} + +	return texture_3d_create(Image::FORMAT_RGBA8, 4, 4, 4, false, images);  }  Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { @@ -889,11 +1054,51 @@ Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const {  }  Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { -	return Ref<Image>(); +	Texture *tex = texture_owner.getornull(p_texture); +	ERR_FAIL_COND_V(!tex, Ref<Image>()); + +	Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, p_layer); +	ERR_FAIL_COND_V(data.size() == 0, Ref<Image>()); +	Ref<Image> image; +	image.instance(); +	image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); +	ERR_FAIL_COND_V(image->empty(), Ref<Image>()); +	if (tex->format != tex->validated_format) { +		image->convert(tex->format); +	} + +	return image;  } -Ref<Image> RasterizerStorageRD::texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const { -	return Ref<Image>(); +Vector<Ref<Image>> RasterizerStorageRD::texture_3d_get(RID p_texture) const { +	Texture *tex = texture_owner.getornull(p_texture); +	ERR_FAIL_COND_V(!tex, Vector<Ref<Image>>()); +	ERR_FAIL_COND_V(tex->type != Texture::TYPE_3D, Vector<Ref<Image>>()); + +	Vector<uint8_t> all_data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0); + +	ERR_FAIL_COND_V(all_data.size() != (int)tex->buffer_size_3d, Vector<Ref<Image>>()); + +	Vector<Ref<Image>> ret; + +	for (int i = 0; i < tex->buffer_slices_3d.size(); i++) { +		const Texture::BufferSlice3D &bs = tex->buffer_slices_3d[i]; +		ERR_FAIL_COND_V(bs.offset >= (uint32_t)all_data.size(), Vector<Ref<Image>>()); +		ERR_FAIL_COND_V(bs.offset + bs.buffer_size > (uint32_t)all_data.size(), Vector<Ref<Image>>()); +		Vector<uint8_t> sub_region = all_data.subarray(bs.offset, bs.offset + bs.buffer_size - 1); + +		Ref<Image> img; +		img.instance(); +		img->create(bs.size.width, bs.size.height, false, tex->validated_format, sub_region); +		ERR_FAIL_COND_V(img->empty(), Vector<Ref<Image>>()); +		if (tex->format != tex->validated_format) { +			img->convert(tex->format); +		} + +		ret.push_back(img); +	} + +	return ret;  }  void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { @@ -913,6 +1118,11 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {  	}  	RD::get_singleton()->free(tex->rd_texture); +	if (tex->canvas_texture) { +		memdelete(tex->canvas_texture); +		tex->canvas_texture = nullptr; +	} +  	Vector<RID> proxies_to_update = tex->proxies;  	Vector<RID> proxies_to_redirect = by_tex->proxies; @@ -920,6 +1130,10 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {  	tex->proxies = proxies_to_update; //restore proxies, so they can be updated +	if (tex->canvas_texture) { +		tex->canvas_texture->diffuse = p_texture; //update +	} +  	for (int i = 0; i < proxies_to_update.size(); i++) {  		texture_proxy_update(proxies_to_update[i], p_texture);  	} @@ -988,6 +1202,167 @@ Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) {  	return texture_2d_get_size(p_proxy);  } +/* CANVAS TEXTURE */ + +void RasterizerStorageRD::CanvasTexture::clear_sets() { +	if (cleared_cache) { +		return; +	} +	for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { +		for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { +			if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j])) { +				RD::get_singleton()->free(uniform_sets[i][j]); +				uniform_sets[i][j] = RID(); +			} +		} +	} +	cleared_cache = true; +} + +RasterizerStorageRD::CanvasTexture::~CanvasTexture() { +	clear_sets(); +} + +RID RasterizerStorageRD::canvas_texture_create() { +	return canvas_texture_owner.make_rid(memnew(CanvasTexture)); +} + +void RasterizerStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { +	CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); +	switch (p_channel) { +		case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: { +			ct->diffuse = p_texture; +		} break; +		case RS::CANVAS_TEXTURE_CHANNEL_NORMAL: { +			ct->normalmap = p_texture; +		} break; +		case RS::CANVAS_TEXTURE_CHANNEL_SPECULAR: { +			ct->specular = p_texture; +		} break; +	} + +	ct->clear_sets(); +} + +void RasterizerStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { +	CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); +	ct->specular_color.r = p_specular_color.r; +	ct->specular_color.g = p_specular_color.g; +	ct->specular_color.b = p_specular_color.b; +	ct->specular_color.a = p_shininess; +	ct->clear_sets(); +} + +void RasterizerStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { +	CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); +	ct->texture_filter = p_filter; +	ct->clear_sets(); +} + +void RasterizerStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { +	CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); +	ct->texture_repeat = p_repeat; +	ct->clear_sets(); +} + +bool RasterizerStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { +	CanvasTexture *ct = nullptr; + +	Texture *t = texture_owner.getornull(p_texture); + +	if (t) { +		//regular texture +		if (!t->canvas_texture) { +			t->canvas_texture = memnew(CanvasTexture); +			t->canvas_texture->diffuse = p_texture; +		} + +		ct = t->canvas_texture; +	} else { +		ct = canvas_texture_owner.getornull(p_texture); +	} + +	if (!ct) { +		return false; //invalid texture RID +	} + +	RS::CanvasItemTextureFilter filter = ct->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? ct->texture_filter : p_base_filter; +	ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, false); + +	RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat; +	ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false); + +	RID uniform_set = ct->uniform_sets[filter][repeat]; +	if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) { +		//create and update +		Vector<RD::Uniform> uniforms; +		{ //diffuse +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 0; + +			t = texture_owner.getornull(ct->diffuse); +			if (!t) { +				u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); +				ct->size_cache = Size2i(1, 1); +			} else { +				u.ids.push_back(t->rd_texture); +				ct->size_cache = Size2i(t->width_2d, t->height_2d); +			} +			uniforms.push_back(u); +		} +		{ //normal +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 1; + +			t = texture_owner.getornull(ct->normalmap); +			if (!t) { +				u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL)); +				ct->use_normal_cache = false; +			} else { +				u.ids.push_back(t->rd_texture); +				ct->use_normal_cache = true; +			} +			uniforms.push_back(u); +		} +		{ //specular +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 2; + +			t = texture_owner.getornull(ct->specular); +			if (!t) { +				u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); +				ct->use_specular_cache = false; +			} else { +				u.ids.push_back(t->rd_texture); +				ct->use_specular_cache = true; +			} +			uniforms.push_back(u); +		} +		{ //sampler +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 3; +			u.ids.push_back(sampler_rd_get_default(filter, repeat)); +			uniforms.push_back(u); +		} + +		uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set); +		ct->uniform_sets[filter][repeat] = uniform_set; +		ct->cleared_cache = false; +	} + +	r_uniform_set = uniform_set; +	r_size = ct->size_cache; +	r_specular_shininess = ct->specular_color; +	r_use_normal = ct->use_normal_cache; +	r_use_specular = ct->use_specular_cache; + +	return true; +} +  /* SHADER API */  RID RasterizerStorageRD::shader_create() { @@ -1051,6 +1426,10 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) {  			}  			material->shader_type = new_type;  		} + +		for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) { +			shader->data->set_default_texture_param(E->key(), E->get()); +		}  	}  	if (shader->data) { @@ -1087,7 +1466,9 @@ void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const S  	} else {  		shader->default_texture_parameter.erase(p_name);  	} - +	if (shader->data) { +		shader->data->set_default_texture_param(p_name, p_texture); +	}  	for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {  		Material *material = E->get();  		_material_queue_update(material, false, true); @@ -3003,9 +3384,9 @@ Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const {  		Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);  		Vector<float> ret; -		ret.resize(multimesh->instances); +		ret.resize(multimesh->instances * multimesh->stride_cache);  		{ -			float *w = multimesh->data_cache.ptrw(); +			float *w = ret.ptrw();  			const uint8_t *r = buffer.ptr();  			copymem(w, r, buffer.size());  		} @@ -3098,7 +3479,1296 @@ void RasterizerStorageRD::_update_dirty_multimeshes() {  	multimesh_dirty_list = nullptr;  } -/* SKELETON */ +/* PARTICLES */ + +RID RasterizerStorageRD::particles_create() { +	return particles_owner.make_rid(Particles()); +} + +void RasterizerStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->emitting = p_emitting; +} + +bool RasterizerStorageRD::particles_get_emitting(RID p_particles) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND_V(!particles, false); + +	return particles->emitting; +} + +void RasterizerStorageRD::_particles_free_data(Particles *particles) { +	if (!particles->particle_buffer.is_valid()) { +		return; +	} +	RD::get_singleton()->free(particles->particle_buffer); +	RD::get_singleton()->free(particles->frame_params_buffer); +	RD::get_singleton()->free(particles->particle_instance_buffer); +	particles->particles_transforms_buffer_uniform_set = RID(); +	particles->particle_buffer = RID(); + +	if (RD::get_singleton()->uniform_set_is_valid(particles->collision_textures_uniform_set)) { +		RD::get_singleton()->free(particles->collision_textures_uniform_set); +	} + +	if (particles->particles_sort_buffer.is_valid()) { +		RD::get_singleton()->free(particles->particles_sort_buffer); +		particles->particles_sort_buffer = RID(); +	} + +	if (particles->emission_buffer != nullptr) { +		particles->emission_buffer = nullptr; +		particles->emission_buffer_data.clear(); +		RD::get_singleton()->free(particles->emission_storage_buffer); +		particles->emission_storage_buffer = RID(); +	} +} + +void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	if (particles->amount == p_amount) { +		return; +	} + +	_particles_free_data(particles); + +	particles->amount = p_amount; + +	if (particles->amount > 0) { +		particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * p_amount); +		particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * 1); +		particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (3 + 1 + 1) * p_amount); +		//needs to clear it + +		{ +			Vector<RD::Uniform> uniforms; + +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 1; +				u.ids.push_back(particles->particle_buffer); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 2; +				u.ids.push_back(particles->particle_instance_buffer); +				uniforms.push_back(u); +			} + +			particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0); +		} +	} + +	particles->prev_ticks = 0; +	particles->phase = 0; +	particles->prev_phase = 0; +	particles->clear = true; +} + +void RasterizerStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	particles->lifetime = p_lifetime; +} + +void RasterizerStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	particles->one_shot = p_one_shot; +} + +void RasterizerStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	particles->pre_process_time = p_time; +} +void RasterizerStorageRD::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	particles->explosiveness = p_ratio; +} +void RasterizerStorageRD::particles_set_randomness_ratio(RID p_particles, float p_ratio) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	particles->randomness = p_ratio; +} + +void RasterizerStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	particles->custom_aabb = p_aabb; +	particles->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->speed_scale = p_scale; +} +void RasterizerStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->use_local_coords = p_enable; +} + +void RasterizerStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->fixed_fps = p_fps; +} + +void RasterizerStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->fractional_delta = p_enable; +} + +void RasterizerStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->collision_base_size = p_size; +} + +void RasterizerStorageRD::particles_set_process_material(RID p_particles, RID p_material) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->process_material = p_material; +} + +void RasterizerStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->draw_order = p_order; +} + +void RasterizerStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->draw_passes.resize(p_passes); +} + +void RasterizerStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); +	particles->draw_passes.write[p_pass] = p_mesh; +} + +void RasterizerStorageRD::particles_restart(RID p_particles) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->restart_request = true; +} + +void RasterizerStorageRD::_particles_allocate_emission_buffer(Particles *particles) { +	ERR_FAIL_COND(particles->emission_buffer != nullptr); + +	particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4); +	zeromem(particles->emission_buffer_data.ptrw(), particles->emission_buffer_data.size()); +	particles->emission_buffer = (ParticleEmissionBuffer *)particles->emission_buffer_data.ptrw(); +	particles->emission_buffer->particle_max = particles->amount; + +	particles->emission_storage_buffer = RD::get_singleton()->storage_buffer_create(particles->emission_buffer_data.size(), particles->emission_buffer_data); + +	if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) { +		//will need to be re-created +		RD::get_singleton()->free(particles->particles_material_uniform_set); +		particles->particles_material_uniform_set = RID(); +	} +} + +void RasterizerStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	ERR_FAIL_COND(p_particles == p_subemitter_particles); + +	particles->sub_emitter = p_subemitter_particles; + +	if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) { +		RD::get_singleton()->free(particles->particles_material_uniform_set); +		particles->particles_material_uniform_set = RID(); //clear and force to re create sub emitting +	} +} + +void RasterizerStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); +	ERR_FAIL_COND(particles->amount == 0); + +	if (particles->emitting) { +		particles->clear = true; +		particles->emitting = false; +	} + +	if (particles->emission_buffer == nullptr) { +		_particles_allocate_emission_buffer(particles); +	} + +	if (particles->inactive) { +		//in case it was inactive, make active again +		particles->inactive = false; +		particles->inactive_time = 0; +	} + +	int32_t idx = particles->emission_buffer->particle_count; +	if (idx < particles->emission_buffer->particle_max) { +		store_transform(p_transform, particles->emission_buffer->data[idx].xform); + +		particles->emission_buffer->data[idx].velocity[0] = p_velocity.x; +		particles->emission_buffer->data[idx].velocity[1] = p_velocity.y; +		particles->emission_buffer->data[idx].velocity[2] = p_velocity.z; + +		particles->emission_buffer->data[idx].custom[0] = p_custom.r; +		particles->emission_buffer->data[idx].custom[1] = p_custom.g; +		particles->emission_buffer->data[idx].custom[2] = p_custom.b; +		particles->emission_buffer->data[idx].custom[3] = p_custom.a; + +		particles->emission_buffer->data[idx].color[0] = p_color.r; +		particles->emission_buffer->data[idx].color[1] = p_color.g; +		particles->emission_buffer->data[idx].color[2] = p_color.b; +		particles->emission_buffer->data[idx].color[3] = p_color.a; + +		particles->emission_buffer->data[idx].flags = p_emit_flags; +		particles->emission_buffer->particle_count++; +	} +} + +void RasterizerStorageRD::particles_request_process(RID p_particles) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	if (!particles->dirty) { +		particles->dirty = true; +		particles->update_list = particle_update_list; +		particle_update_list = particles; +	} +} + +AABB RasterizerStorageRD::particles_get_current_aabb(RID p_particles) { +	const Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND_V(!particles, AABB()); + +	Vector<ParticleData> data; +	data.resize(particles->amount); + +	Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer); + +	Transform inv = particles->emission_transform.affine_inverse(); + +	AABB aabb; +	if (buffer.size()) { +		bool first = true; +		const ParticleData *particle_data = (const ParticleData *)data.ptr(); +		for (int i = 0; i < particles->amount; i++) { +			if (particle_data[i].active) { +				Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]); +				if (!particles->use_local_coords) { +					pos = inv.xform(pos); +				} +				if (first) { +					aabb.position = pos; +					first = false; +				} else { +					aabb.expand_to(pos); +				} +			} +		} +	} + +	float longest_axis_size = 0; +	for (int i = 0; i < particles->draw_passes.size(); i++) { +		if (particles->draw_passes[i].is_valid()) { +			AABB maabb = mesh_get_aabb(particles->draw_passes[i], RID()); +			longest_axis_size = MAX(maabb.get_longest_axis_size(), longest_axis_size); +		} +	} + +	aabb.grow_by(longest_axis_size); + +	return aabb; +} + +AABB RasterizerStorageRD::particles_get_aabb(RID p_particles) const { +	const Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND_V(!particles, AABB()); + +	return particles->custom_aabb; +} + +void RasterizerStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->emission_transform = p_transform; +} + +int RasterizerStorageRD::particles_get_draw_passes(RID p_particles) const { +	const Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND_V(!particles, 0); + +	return particles->draw_passes.size(); +} + +RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { +	const Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND_V(!particles, RID()); +	ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID()); + +	return particles->draw_passes[p_pass]; +} + +void RasterizerStorageRD::particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_PARTICLES_COLLISION); + +	particles->collisions.insert(p_instance); +} + +void RasterizerStorageRD::particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	particles->collisions.erase(p_instance); +} + +void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_delta) { +	if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) { +		Vector<RD::Uniform> uniforms; + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 0; +			u.ids.push_back(p_particles->frame_params_buffer); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 1; +			u.ids.push_back(p_particles->particle_buffer); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 2; +			if (p_particles->emission_storage_buffer.is_valid()) { +				u.ids.push_back(p_particles->emission_storage_buffer); +			} else { +				u.ids.push_back(default_rd_storage_buffer); +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 3; +			Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter); +			if (sub_emitter) { +				if (sub_emitter->emission_buffer == nullptr) { //no emission buffer, allocate emission buffer +					_particles_allocate_emission_buffer(sub_emitter); +				} +				u.ids.push_back(sub_emitter->emission_storage_buffer); +			} else { +				u.ids.push_back(default_rd_storage_buffer); +			} +			uniforms.push_back(u); +		} + +		p_particles->particles_material_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 1); +	} + +	float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0); + +	ParticlesFrameParams &frame_params = p_particles->frame_params; + +	if (p_particles->clear) { +		p_particles->cycle_number = 0; +		p_particles->random_seed = Math::rand(); +	} else if (new_phase < p_particles->phase) { +		if (p_particles->one_shot) { +			p_particles->emitting = false; +		} +		p_particles->cycle_number++; +	} + +	frame_params.emitting = p_particles->emitting; +	frame_params.system_phase = new_phase; +	frame_params.prev_system_phase = p_particles->phase; + +	p_particles->phase = new_phase; + +	frame_params.time = RasterizerRD::singleton->get_total_time(); +	frame_params.delta = p_delta * p_particles->speed_scale; +	frame_params.random_seed = p_particles->random_seed; +	frame_params.explosiveness = p_particles->explosiveness; +	frame_params.randomness = p_particles->randomness; + +	if (p_particles->use_local_coords) { +		store_transform(Transform(), frame_params.emission_transform); +	} else { +		store_transform(p_particles->emission_transform, frame_params.emission_transform); +	} + +	frame_params.cycle = p_particles->cycle_number; + +	{ //collision and attractors + +		frame_params.collider_count = 0; +		frame_params.attractor_count = 0; +		frame_params.particle_size = p_particles->collision_base_size; + +		RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES]; +		RID collision_heightmap_texture; + +		Transform to_particles; +		if (p_particles->use_local_coords) { +			to_particles = p_particles->emission_transform.affine_inverse(); +		} +		uint32_t collision_3d_textures_used = 0; +		for (const Set<RasterizerScene::InstanceBase *>::Element *E = p_particles->collisions.front(); E; E = E->next()) { +			ParticlesCollision *pc = particles_collision_owner.getornull(E->get()->base); +			Transform to_collider = E->get()->transform; +			if (p_particles->use_local_coords) { +				to_collider = to_particles * to_collider; +			} +			Vector3 scale = to_collider.basis.get_scale(); +			to_collider.basis.orthonormalize(); + +			if (pc->type <= RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) { +				//attractor +				if (frame_params.attractor_count >= ParticlesFrameParams::MAX_ATTRACTORS) { +					continue; +				} + +				ParticlesFrameParams::Attractor &attr = frame_params.attractors[frame_params.attractor_count]; + +				store_transform(to_collider, attr.transform); +				attr.strength = pc->attractor_strength; +				attr.attenuation = pc->attractor_attenuation; +				attr.directionality = pc->attractor_directionality; + +				switch (pc->type) { +					case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT: { +						attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_SPHERE; +						float radius = pc->radius; +						radius *= (scale.x + scale.y + scale.z) / 3.0; +						attr.extents[0] = radius; +						attr.extents[1] = radius; +						attr.extents[2] = radius; +					} break; +					case RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT: { +						attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_BOX; +						Vector3 extents = pc->extents * scale; +						attr.extents[0] = extents.x; +						attr.extents[1] = extents.y; +						attr.extents[2] = extents.z; +					} break; +					case RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT: { +						if (collision_3d_textures_used >= ParticlesFrameParams::MAX_3D_TEXTURES) { +							continue; +						} +						attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_VECTOR_FIELD; +						Vector3 extents = pc->extents * scale; +						attr.extents[0] = extents.x; +						attr.extents[1] = extents.y; +						attr.extents[2] = extents.z; +						attr.texture_index = collision_3d_textures_used; + +						collision_3d_textures[collision_3d_textures_used] = pc->field_texture; +						collision_3d_textures_used++; +					} break; +					default: { +					} +				} + +				frame_params.attractor_count++; +			} else { +				//collider +				if (frame_params.collider_count >= ParticlesFrameParams::MAX_COLLIDERS) { +					continue; +				} + +				ParticlesFrameParams::Collider &col = frame_params.colliders[frame_params.collider_count]; + +				store_transform(to_collider, col.transform); +				switch (pc->type) { +					case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: { +						col.type = ParticlesFrameParams::COLLISION_TYPE_SPHERE; +						float radius = pc->radius; +						radius *= (scale.x + scale.y + scale.z) / 3.0; +						col.extents[0] = radius; +						col.extents[1] = radius; +						col.extents[2] = radius; +					} break; +					case RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE: { +						col.type = ParticlesFrameParams::COLLISION_TYPE_BOX; +						Vector3 extents = pc->extents * scale; +						col.extents[0] = extents.x; +						col.extents[1] = extents.y; +						col.extents[2] = extents.z; +					} break; +					case RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE: { +						if (collision_3d_textures_used >= ParticlesFrameParams::MAX_3D_TEXTURES) { +							continue; +						} +						col.type = ParticlesFrameParams::COLLISION_TYPE_SDF; +						Vector3 extents = pc->extents * scale; +						col.extents[0] = extents.x; +						col.extents[1] = extents.y; +						col.extents[2] = extents.z; +						col.texture_index = collision_3d_textures_used; +						col.scale = (scale.x + scale.y + scale.z) * 0.333333333333; //non uniform scale non supported + +						collision_3d_textures[collision_3d_textures_used] = pc->field_texture; +						collision_3d_textures_used++; +					} break; +					case RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE: { +						if (collision_heightmap_texture != RID()) { //already taken +							continue; +						} + +						col.type = ParticlesFrameParams::COLLISION_TYPE_HEIGHT_FIELD; +						Vector3 extents = pc->extents * scale; +						col.extents[0] = extents.x; +						col.extents[1] = extents.y; +						col.extents[2] = extents.z; +						collision_heightmap_texture = pc->heightfield_texture; +					} break; +					default: { +					} +				} + +				frame_params.collider_count++; +			} +		} + +		bool different = false; +		if (collision_3d_textures_used == p_particles->collision_3d_textures_used) { +			for (int i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { +				if (p_particles->collision_3d_textures[i] != collision_3d_textures[i]) { +					different = true; +					break; +				} +			} +		} + +		if (collision_heightmap_texture != p_particles->collision_heightmap_texture) { +			different = true; +		} + +		bool uniform_set_valid = RD::get_singleton()->uniform_set_is_valid(p_particles->collision_textures_uniform_set); + +		if (different || !uniform_set_valid) { +			if (uniform_set_valid) { +				RD::get_singleton()->free(p_particles->collision_textures_uniform_set); +			} + +			Vector<RD::Uniform> uniforms; + +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_TEXTURE; +				u.binding = 0; +				for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { +					RID rd_tex; +					if (i < collision_3d_textures_used) { +						Texture *t = texture_owner.getornull(collision_3d_textures[i]); +						if (t && t->type == Texture::TYPE_3D) { +							rd_tex = t->rd_texture; +						} +					} + +					if (rd_tex == RID()) { +						rd_tex = default_rd_textures[DEFAULT_RD_TEXTURE_3D_WHITE]; +					} +					u.ids.push_back(rd_tex); +				} +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_TEXTURE; +				u.binding = 1; +				if (collision_heightmap_texture.is_valid()) { +					u.ids.push_back(collision_heightmap_texture); +				} else { +					u.ids.push_back(default_rd_textures[DEFAULT_RD_TEXTURE_BLACK]); +				} +				uniforms.push_back(u); +			} +			p_particles->collision_textures_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 2); +		} +	} + +	ParticlesShader::PushConstant push_constant; + +	push_constant.clear = p_particles->clear; +	push_constant.total_particles = p_particles->amount; +	push_constant.lifetime = p_particles->lifetime; +	push_constant.trail_size = 1; +	push_constant.use_fractional_delta = p_particles->fractional_delta; +	push_constant.sub_emitter_mode = !p_particles->emitting && p_particles->emission_buffer && (p_particles->emission_buffer->particle_count > 0 || p_particles->force_sub_emit); + +	p_particles->force_sub_emit = false; //reset + +	Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter); + +	if (sub_emitter && sub_emitter->emission_storage_buffer.is_valid()) { +		//	print_line("updating subemitter buffer"); +		int32_t zero[4] = { 0, sub_emitter->amount, 0, 0 }; +		RD::get_singleton()->buffer_update(sub_emitter->emission_storage_buffer, 0, sizeof(uint32_t) * 4, zero, true); +		push_constant.can_emit = true; + +		if (sub_emitter->emitting) { +			sub_emitter->emitting = false; +			sub_emitter->clear = true; //will need to clear if it was emitting, sorry +		} +		//make sure the sub emitter processes particles too +		sub_emitter->inactive = false; +		sub_emitter->inactive_time = 0; + +		sub_emitter->force_sub_emit = true; + +	} else { +		push_constant.can_emit = false; +	} + +	if (p_particles->emission_buffer && p_particles->emission_buffer->particle_count) { +		RD::get_singleton()->buffer_update(p_particles->emission_storage_buffer, 0, sizeof(uint32_t) * 4 + sizeof(ParticleEmissionBuffer::Data) * p_particles->emission_buffer->particle_count, p_particles->emission_buffer, true); +		p_particles->emission_buffer->particle_count = 0; +	} + +	p_particles->clear = false; + +	RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params, true); + +	ParticlesMaterialData *m = (ParticlesMaterialData *)material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES); +	if (!m) { +		m = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, SHADER_TYPE_PARTICLES); +	} + +	ERR_FAIL_COND(!m); + +	//todo should maybe compute all particle systems together? +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles_shader.base_uniform_set, 0); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, 1); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->collision_textures_uniform_set, 2); + +	if (m->uniform_set.is_valid()) { +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 3); +	} + +	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant)); + +	RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_particles->amount, 1, 1, 64, 1, 1); + +	RD::get_singleton()->compute_list_end(); +} + +void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) { +	Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND(!particles); + +	if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) { +		return; //uninteresting for other modes +	} + +	//copy to sort buffer +	if (particles->particles_sort_buffer == RID()) { +		uint32_t size = particles->amount; +		if (size & 1) { +			size++; //make multiple of 16 +		} +		size *= sizeof(float) * 2; +		particles->particles_sort_buffer = RD::get_singleton()->storage_buffer_create(size); +		{ +			Vector<RD::Uniform> uniforms; + +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 0; +				u.ids.push_back(particles->particles_sort_buffer); +				uniforms.push_back(u); +			} + +			particles->particles_sort_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, ParticlesShader::COPY_MODE_FILL_SORT_BUFFER), 1); +		} +	} + +	Vector3 axis = -p_axis; // cameras look to z negative + +	if (particles->use_local_coords) { +		axis = particles->emission_transform.basis.xform_inv(axis).normalized(); +	} + +	ParticlesShader::CopyPushConstant copy_push_constant; +	copy_push_constant.total_particles = particles->amount; +	copy_push_constant.sort_direction[0] = axis.x; +	copy_push_constant.sort_direction[1] = axis.y; +	copy_push_constant.sort_direction[2] = axis.z; + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); +	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); + +	RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1); + +	RD::get_singleton()->compute_list_end(); + +	effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount); + +	compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER]); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); +	RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); + +	RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1); + +	RD::get_singleton()->compute_list_end(); +} + +void RasterizerStorageRD::update_particles() { +	while (particle_update_list) { +		//use transform feedback to process particles + +		Particles *particles = particle_update_list; + +		//take and remove +		particle_update_list = particles->update_list; +		particles->update_list = nullptr; +		particles->dirty = false; + +		if (particles->restart_request) { +			particles->prev_ticks = 0; +			particles->phase = 0; +			particles->prev_phase = 0; +			particles->clear = true; +			particles->restart_request = false; +		} + +		if (particles->inactive && !particles->emitting) { +			//go next +			continue; +		} + +		if (particles->emitting) { +			if (particles->inactive) { +				//restart system from scratch +				particles->prev_ticks = 0; +				particles->phase = 0; +				particles->prev_phase = 0; +				particles->clear = true; +			} +			particles->inactive = false; +			particles->inactive_time = 0; +		} else { +			particles->inactive_time += particles->speed_scale * RasterizerRD::singleton->get_frame_delta_time(); +			if (particles->inactive_time > particles->lifetime * 1.2) { +				particles->inactive = true; +				continue; +			} +		} + +		bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0; + +		if (particles->clear && particles->pre_process_time > 0.0) { +			float frame_time; +			if (particles->fixed_fps > 0) +				frame_time = 1.0 / particles->fixed_fps; +			else +				frame_time = 1.0 / 30.0; + +			float todo = particles->pre_process_time; + +			while (todo >= 0) { +				_particles_process(particles, frame_time); +				todo -= frame_time; +			} +		} + +		if (particles->fixed_fps > 0) { +			float frame_time; +			float decr; +			if (zero_time_scale) { +				frame_time = 0.0; +				decr = 1.0 / particles->fixed_fps; +			} else { +				frame_time = 1.0 / particles->fixed_fps; +				decr = frame_time; +			} +			float delta = RasterizerRD::singleton->get_frame_delta_time(); +			if (delta > 0.1) { //avoid recursive stalls if fps goes below 10 +				delta = 0.1; +			} else if (delta <= 0.0) { //unlikely but.. +				delta = 0.001; +			} +			float todo = particles->frame_remainder + delta; + +			while (todo >= frame_time) { +				_particles_process(particles, frame_time); +				todo -= decr; +			} + +			particles->frame_remainder = todo; + +		} else { +			if (zero_time_scale) +				_particles_process(particles, 0.0); +			else +				_particles_process(particles, RasterizerRD::singleton->get_frame_delta_time()); +		} + +		//copy particles to instance buffer + +		if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) { +			ParticlesShader::CopyPushConstant copy_push_constant; +			copy_push_constant.total_particles = particles->amount; + +			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); +			RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); + +			RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1); + +			RD::get_singleton()->compute_list_end(); +		} + +		particles->instance_dependency.instance_notify_changed(true, false); //make sure shadows are updated +	} +} + +bool RasterizerStorageRD::particles_is_inactive(RID p_particles) const { +	const Particles *particles = particles_owner.getornull(p_particles); +	ERR_FAIL_COND_V(!particles, false); +	return !particles->emitting && particles->inactive; +} + +/* SKY SHADER */ + +void RasterizerStorageRD::ParticlesShaderData::set_code(const String &p_code) { +	//compile + +	code = p_code; +	valid = false; +	ubo_size = 0; +	uniforms.clear(); + +	if (code == String()) { +		return; //just invalid, but no error +	} + +	ShaderCompilerRD::GeneratedCode gen_code; +	ShaderCompilerRD::IdentifierActions actions; + +	/* +	uses_time = false; + +	actions.render_mode_flags["use_half_res_pass"] = &uses_half_res; +	actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res; + +	actions.usage_flag_pointers["TIME"] = &uses_time; +*/ + +	actions.uniforms = &uniforms; + +	Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code); + +	ERR_FAIL_COND(err != OK); + +	if (version.is_null()) { +		version = base_singleton->particles_shader.shader.version_create(); +	} + +	base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.uniforms, gen_code.compute_global, gen_code.compute, gen_code.defines); +	ERR_FAIL_COND(!base_singleton->particles_shader.shader.version_is_valid(version)); + +	ubo_size = gen_code.uniform_total_size; +	ubo_offsets = gen_code.uniform_offsets; +	texture_uniforms = gen_code.texture_uniforms; + +	//update pipelines + +	pipeline = RD::get_singleton()->compute_pipeline_create(base_singleton->particles_shader.shader.version_get_shader(version, 0)); + +	valid = true; +} + +void RasterizerStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +	if (!p_texture.is_valid()) { +		default_texture_params.erase(p_name); +	} else { +		default_texture_params[p_name] = p_texture; +	} +} + +void RasterizerStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +	Map<int, StringName> order; + +	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { +		if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { +			continue; +		} + +		if (E->get().texture_order >= 0) { +			order[E->get().texture_order + 100000] = E->key(); +		} else { +			order[E->get().order] = E->key(); +		} +	} + +	for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { +		PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); +		pi.name = E->get(); +		p_param_list->push_back(pi); +	} +} + +void RasterizerStorageRD::ParticlesShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { +		if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { +			continue; +		} + +		RasterizerStorage::InstanceShaderParam p; +		p.info = ShaderLanguage::uniform_to_property_info(E->get()); +		p.info.name = E->key(); //supply name +		p.index = E->get().instance_index; +		p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); +		p_param_list->push_back(p); +	} +} + +bool RasterizerStorageRD::ParticlesShaderData::is_param_texture(const StringName &p_param) const { +	if (!uniforms.has(p_param)) { +		return false; +	} + +	return uniforms[p_param].texture_order >= 0; +} + +bool RasterizerStorageRD::ParticlesShaderData::is_animated() const { +	return false; +} + +bool RasterizerStorageRD::ParticlesShaderData::casts_shadows() const { +	return false; +} + +Variant RasterizerStorageRD::ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const { +	if (uniforms.has(p_parameter)) { +		ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; +		Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; +		return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); +	} +	return Variant(); +} + +RasterizerStorageRD::ParticlesShaderData::ParticlesShaderData() { +	valid = false; +} + +RasterizerStorageRD::ParticlesShaderData::~ParticlesShaderData() { +	//pipeline variants will clear themselves if shader is gone +	if (version.is_valid()) { +		base_singleton->particles_shader.shader.version_free(version); +	} +} + +RasterizerStorageRD::ShaderData *RasterizerStorageRD::_create_particles_shader_func() { +	ParticlesShaderData *shader_data = memnew(ParticlesShaderData); +	return shader_data; +} + +void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +	uniform_set_updated = true; + +	if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { +		p_uniform_dirty = true; +		if (uniform_buffer.is_valid()) { +			RD::get_singleton()->free(uniform_buffer); +			uniform_buffer = RID(); +		} + +		ubo_data.resize(shader_data->ubo_size); +		if (ubo_data.size()) { +			uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); +			memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear +		} + +		//clear previous uniform set +		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { +			RD::get_singleton()->free(uniform_set); +			uniform_set = RID(); +		} +	} + +	//check whether buffer changed +	if (p_uniform_dirty && ubo_data.size()) { +		update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); +		RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); +	} + +	uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); + +	if ((uint32_t)texture_cache.size() != tex_uniform_count) { +		texture_cache.resize(tex_uniform_count); +		p_textures_dirty = true; + +		//clear previous uniform set +		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { +			RD::get_singleton()->free(uniform_set); +			uniform_set = RID(); +		} +	} + +	if (p_textures_dirty && tex_uniform_count) { +		update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); +	} + +	if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { +		// This material does not require an uniform set, so don't create it. +		return; +	} + +	if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { +		//no reason to update uniform set, only UBO (or nothing) was needed to update +		return; +	} + +	Vector<RD::Uniform> uniforms; + +	{ +		if (shader_data->ubo_size) { +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.binding = 0; +			u.ids.push_back(uniform_buffer); +			uniforms.push_back(u); +		} + +		const RID *textures = texture_cache.ptrw(); +		for (uint32_t i = 0; i < tex_uniform_count; i++) { +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 1 + i; +			u.ids.push_back(textures[i]); +			uniforms.push_back(u); +		} +	} + +	uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); +} + +RasterizerStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { +	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { +		RD::get_singleton()->free(uniform_set); +	} + +	if (uniform_buffer.is_valid()) { +		RD::get_singleton()->free(uniform_buffer); +	} +} + +RasterizerStorageRD::MaterialData *RasterizerStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) { +	ParticlesMaterialData *material_data = memnew(ParticlesMaterialData); +	material_data->shader_data = p_shader; +	material_data->last_frame = false; +	//update will happen later anyway so do nothing. +	return material_data; +} +//////// + +/* PARTICLES COLLISION API */ + +RID RasterizerStorageRD::particles_collision_create() { +	return particles_collision_owner.make_rid(ParticlesCollision()); +} + +RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND_V(!particles_collision, RID()); +	ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, RID()); + +	if (particles_collision->heightfield_texture == RID()) { +		//create +		int resolutions[RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX] = { 256, 512, 1024, 2048, 4096, 8192 }; +		Size2i size; +		if (particles_collision->extents.x > particles_collision->extents.z) { +			size.x = resolutions[particles_collision->heightfield_resolution]; +			size.y = int32_t(particles_collision->extents.z / particles_collision->extents.x * size.x); +		} else { +			size.y = resolutions[particles_collision->heightfield_resolution]; +			size.x = int32_t(particles_collision->extents.x / particles_collision->extents.z * size.y); +		} + +		RD::TextureFormat tf; +		tf.format = RD::DATA_FORMAT_D32_SFLOAT; +		tf.width = size.x; +		tf.height = size.y; +		tf.type = RD::TEXTURE_TYPE_2D; +		tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + +		particles_collision->heightfield_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + +		Vector<RID> fb_tex; +		fb_tex.push_back(particles_collision->heightfield_texture); +		particles_collision->heightfield_fb = RD::get_singleton()->framebuffer_create(fb_tex); +		particles_collision->heightfield_fb_size = size; +	} + +	return particles_collision->heightfield_fb; +} + +void RasterizerStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	if (p_type == particles_collision->type) { +		return; +	} + +	if (particles_collision->heightfield_texture.is_valid()) { +		RD::get_singleton()->free(particles_collision->heightfield_texture); +		particles_collision->heightfield_texture = RID(); +	} +	particles_collision->type = p_type; +	particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); +	particles_collision->cull_mask = p_cull_mask; +} + +void RasterizerStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	particles_collision->radius = p_radius; +	particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	particles_collision->extents = p_extents; +	particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	particles_collision->attractor_strength = p_strength; +} + +void RasterizerStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	particles_collision->attractor_directionality = p_directionality; +} + +void RasterizerStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	particles_collision->attractor_attenuation = p_curve; +} + +void RasterizerStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	particles_collision->field_texture = p_texture; +} + +void RasterizerStorageRD::particles_collision_height_field_update(RID p_particles_collision) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); +	particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND(!particles_collision); + +	if (particles_collision->heightfield_resolution == p_resolution) { +		return; +	} + +	particles_collision->heightfield_resolution = p_resolution; + +	if (particles_collision->heightfield_texture.is_valid()) { +		RD::get_singleton()->free(particles_collision->heightfield_texture); +		particles_collision->heightfield_texture = RID(); +	} +} + +AABB RasterizerStorageRD::particles_collision_get_aabb(RID p_particles_collision) const { +	ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND_V(!particles_collision, AABB()); + +	switch (particles_collision->type) { +		case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT: +		case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: { +			AABB aabb; +			aabb.position = -Vector3(1, 1, 1) * particles_collision->radius; +			aabb.size = Vector3(2, 2, 2) * particles_collision->radius; +			return aabb; +		} +		default: { +			AABB aabb; +			aabb.position = -particles_collision->extents; +			aabb.size = particles_collision->extents * 2; +			return aabb; +		} +	} + +	return AABB(); +} + +Vector3 RasterizerStorageRD::particles_collision_get_extents(RID p_particles_collision) const { +	const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND_V(!particles_collision, Vector3()); +	return particles_collision->extents; +} + +bool RasterizerStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const { +	const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); +	ERR_FAIL_COND_V(!particles_collision, false); +	return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE; +}  /* SKELETON API */ @@ -3290,6 +4960,7 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) {  	light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0;  	light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;  	light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05; +	light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 1.0;  	return light_owner.make_rid(light);  } @@ -3568,6 +5239,9 @@ void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector  	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);  	ERR_FAIL_COND(!reflection_probe); +	if (reflection_probe->extents == p_extents) { +		return; +	}  	reflection_probe->extents = p_extents;  	reflection_probe->instance_dependency.instance_notify_changed(true, false);  } @@ -4338,6 +6012,7 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {  	//free in reverse dependency order  	if (rt->framebuffer.is_valid()) {  		RD::get_singleton()->free(rt->framebuffer); +		rt->framebuffer_uniform_set = RID(); //chain deleted  	}  	if (rt->color.is_valid()) { @@ -4352,10 +6027,7 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {  			RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy);  		}  		rt->backbuffer_mipmaps.clear(); -		if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) { -			RD::get_singleton()->free(rt->backbuffer_uniform_set); -		} -		rt->backbuffer_uniform_set = RID(); +		rt->backbuffer_uniform_set = RID(); //chain deleted  	}  	rt->framebuffer = RID(); @@ -4459,12 +6131,23 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) {  	tf.width = rt->size.width;  	tf.height = rt->size.height;  	tf.type = RD::TEXTURE_TYPE_2D; -	tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; +	tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;  	tf.mipmaps = mipmaps_required;  	rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView());  	rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); +	{ +		Vector<RID> fb_tex; +		fb_tex.push_back(rt->backbuffer_mipmap0); +		rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(fb_tex); +	} + +	if (rt->framebuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->framebuffer_uniform_set)) { +		//the new one will require the backbuffer. +		RD::get_singleton()->free(rt->framebuffer_uniform_set); +		rt->framebuffer_uniform_set = RID(); +	}  	//create mipmaps  	for (uint32_t i = 1; i < mipmaps_required; i++) {  		RenderTarget::BackbufferMipmap mm; @@ -4562,6 +6245,23 @@ RID RasterizerStorageRD::render_target_get_rd_texture(RID p_render_target) {  	return rt->color;  } +RID RasterizerStorageRD::render_target_get_rd_backbuffer(RID p_render_target) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND_V(!rt, RID()); +	return rt->backbuffer; +} + +RID RasterizerStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND_V(!rt, RID()); + +	if (!rt->backbuffer.is_valid()) { +		_create_render_target_backbuffer(rt); +	} + +	return rt->backbuffer_fb; +} +  void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {  	RenderTarget *rt = render_target_owner.getornull(p_render_target);  	ERR_FAIL_COND(!rt); @@ -4600,21 +6300,30 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {  	rt->clear_requested = false;  } -void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region) { +void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {  	RenderTarget *rt = render_target_owner.getornull(p_render_target);  	ERR_FAIL_COND(!rt);  	if (!rt->backbuffer.is_valid()) {  		_create_render_target_backbuffer(rt);  	} -	Rect2i region = p_region; -	if (region == Rect2i()) { +	Rect2i region; +	if (p_region == Rect2i()) {  		region.size = rt->size; +	} else { +		region = Rect2i(Size2i(), rt->size).clip(p_region); +		if (region.size == Size2i()) { +			return; //nothing to do +		}  	}  	//single texture copy for backbuffer -	RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); -	//effects.copy(rt->color, rt->backbuffer_fb, blur_region); +	//RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); +	effects.copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true); + +	if (!p_gen_mipmaps) { +		return; +	}  	//then mipmap blur  	RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. @@ -4631,32 +6340,81 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target,  	}  } -RID RasterizerStorageRD::render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader) { +void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {  	RenderTarget *rt = render_target_owner.getornull(p_render_target); -	ERR_FAIL_COND_V(!rt, RID()); +	ERR_FAIL_COND(!rt); +	if (!rt->backbuffer.is_valid()) { +		_create_render_target_backbuffer(rt); +	} + +	Rect2i region; +	if (p_region == Rect2i()) { +		region.size = rt->size; +	} else { +		region = Rect2i(Size2i(), rt->size).clip(p_region); +		if (region.size == Size2i()) { +			return; //nothing to do +		} +	} + +	//single texture copy for backbuffer +	effects.set_color(rt->backbuffer_mipmap0, p_color, region, true); +} +void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND(!rt);  	if (!rt->backbuffer.is_valid()) {  		_create_render_target_backbuffer(rt);  	} -	if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) { -		return rt->backbuffer_uniform_set; //if still valid, return/reuse it. +	Rect2i region; +	if (p_region == Rect2i()) { +		region.size = rt->size; +	} else { +		region = Rect2i(Size2i(), rt->size).clip(p_region); +		if (region.size == Size2i()) { +			return; //nothing to do +		}  	} -	//create otherwise -	Vector<RD::Uniform> uniforms; -	RD::Uniform u; -	u.type = RD::UNIFORM_TYPE_TEXTURE; -	u.binding = 0; -	u.ids.push_back(rt->backbuffer); -	uniforms.push_back(u); +	//then mipmap blur +	RID prev_texture = rt->backbuffer_mipmap0; + +	for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { +		region.position.x >>= 1; +		region.position.y >>= 1; +		region.size.x = MAX(1, region.size.x >> 1); +		region.size.y = MAX(1, region.size.y >> 1); -	rt->backbuffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, 3); -	ERR_FAIL_COND_V(!rt->backbuffer_uniform_set.is_valid(), RID()); +		const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; +		effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); +		prev_texture = mm.mipmap; +	} +} +RID RasterizerStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND_V(!rt, RID()); +	return rt->framebuffer_uniform_set; +} +RID RasterizerStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND_V(!rt, RID());  	return rt->backbuffer_uniform_set;  } +void RasterizerStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND(!rt); +	rt->framebuffer_uniform_set = p_uniform_set; +} +void RasterizerStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) { +	RenderTarget *rt = render_target_owner.getornull(p_render_target); +	ERR_FAIL_COND(!rt); +	rt->backbuffer_uniform_set = p_uniform_set; +} +  void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {  	if (mesh_owner.owns(p_base)) {  		Mesh *mesh = mesh_owner.getornull(p_base); @@ -4682,6 +6440,12 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In  	} else if (light_owner.owns(p_base)) {  		Light *l = light_owner.getornull(p_base);  		p_instance->update_dependency(&l->instance_dependency); +	} else if (particles_owner.owns(p_base)) { +		Particles *p = particles_owner.getornull(p_base); +		p_instance->update_dependency(&p->instance_dependency); +	} else if (particles_collision_owner.owns(p_base)) { +		ParticlesCollision *pc = particles_collision_owner.getornull(p_base); +		p_instance->update_dependency(&pc->instance_dependency);  	}  } @@ -4714,6 +6478,12 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {  	if (lightmap_owner.owns(p_rid)) {  		return RS::INSTANCE_LIGHTMAP;  	} +	if (particles_owner.owns(p_rid)) { +		return RS::INSTANCE_PARTICLES; +	} +	if (particles_collision_owner.owns(p_rid)) { +		return RS::INSTANCE_PARTICLES_COLLISION; +	}  	return RS::INSTANCE_NONE;  } @@ -4753,7 +6523,7 @@ RID RasterizerStorageRD::decal_atlas_get_texture() const {  }  RID RasterizerStorageRD::decal_atlas_get_texture_srgb() const { -	return decal_atlas.texture; +	return decal_atlas.texture_srgb;  }  void RasterizerStorageRD::_update_decal_atlas() { @@ -5676,8 +7446,16 @@ bool RasterizerStorageRD::free(RID p_rid) {  			p->rd_texture = RID();  			p->rd_texture_srgb = RID();  		} + +		if (t->canvas_texture) { +			memdelete(t->canvas_texture); +		}  		texture_owner.free(p_rid); +	} else if (canvas_texture_owner.owns(p_rid)) { +		CanvasTexture *ct = canvas_texture_owner.getornull(p_rid); +		memdelete(ct); +		canvas_texture_owner.free(p_rid);  	} else if (shader_owner.owns(p_rid)) {  		Shader *shader = shader_owner.getornull(p_rid);  		//make material unreference this @@ -5746,6 +7524,19 @@ bool RasterizerStorageRD::free(RID p_rid) {  		light->instance_dependency.instance_notify_deleted(p_rid);  		light_owner.free(p_rid); +	} else if (particles_owner.owns(p_rid)) { +		Particles *particles = particles_owner.getornull(p_rid); +		_particles_free_data(particles); +		particles->instance_dependency.instance_notify_deleted(p_rid); +		particles_owner.free(p_rid); +	} else if (particles_collision_owner.owns(p_rid)) { +		ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid); + +		if (particles_collision->heightfield_texture.is_valid()) { +			RD::get_singleton()->free(particles_collision->heightfield_texture); +		} +		particles_collision->instance_dependency.instance_notify_deleted(p_rid); +		particles_collision_owner.free(p_rid);  	} else if (render_target_owner.owns(p_rid)) {  		RenderTarget *rt = render_target_owner.getornull(p_rid); @@ -6065,15 +7856,18 @@ RasterizerStorageRD::RasterizerStorageRD() {  				case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {  					sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;  					sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; +					sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;  				} break;  				case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {  					sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;  					sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT; +					sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT;  				} break;  				case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {  					sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;  					sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; +					sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;  				} break;  				default: {  				} @@ -6210,6 +8004,130 @@ RasterizerStorageRD::RasterizerStorageRD() {  	}  	lightmap_probe_capture_update_speed = GLOBAL_GET("rendering/lightmapper/probe_capture_update_speed"); + +	/* Particles */ + +	{ +		// Initialize particles +		Vector<String> particles_modes; +		particles_modes.push_back(""); +		particles_shader.shader.initialize(particles_modes, String()); +	} +	shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs); +	material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_material_funcs); + +	{ +		ShaderCompilerRD::DefaultIdentifierActions actions; + +		actions.renames["COLOR"] = "PARTICLE.color"; +		actions.renames["VELOCITY"] = "PARTICLE.velocity"; +		//actions.renames["MASS"] = "mass"; ? +		actions.renames["ACTIVE"] = "PARTICLE.is_active"; +		actions.renames["RESTART"] = "restart"; +		actions.renames["CUSTOM"] = "PARTICLE.custom"; +		actions.renames["TRANSFORM"] = "PARTICLE.xform"; +		actions.renames["TIME"] = "FRAME.time"; +		actions.renames["LIFETIME"] = "params.lifetime"; +		actions.renames["DELTA"] = "local_delta"; +		actions.renames["NUMBER"] = "particle"; +		actions.renames["INDEX"] = "index"; +		//actions.renames["GRAVITY"] = "current_gravity"; +		actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform"; +		actions.renames["RANDOM_SEED"] = "FRAME.random_seed"; +		actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION"; +		actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE"; +		actions.renames["FLAG_EMIT_VELOCITY"] = "EMISSION_FLAG_HAS_VELOCITY"; +		actions.renames["FLAG_EMIT_COLOR"] = "EMISSION_FLAG_HAS_COLOR"; +		actions.renames["FLAG_EMIT_CUSTOM"] = "EMISSION_FLAG_HAS_CUSTOM"; +		actions.renames["RESTART_POSITION"] = "restart_position"; +		actions.renames["RESTART_ROT_SCALE"] = "restart_rotation_scale"; +		actions.renames["RESTART_VELOCITY"] = "restart_velocity"; +		actions.renames["RESTART_COLOR"] = "restart_color"; +		actions.renames["RESTART_CUSTOM"] = "restart_custom"; +		actions.renames["emit_particle"] = "emit_particle"; +		actions.renames["COLLIDED"] = "collided"; +		actions.renames["COLLISION_NORMAL"] = "collision_normal"; +		actions.renames["COLLISION_DEPTH"] = "collision_depth"; +		actions.renames["ATTRACTOR_FORCE"] = "attractor_force"; + +		actions.render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; +		actions.render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; +		actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; +		actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISON_SCALE\n"; + +		actions.sampler_array_name = "material_samplers"; +		actions.base_texture_binding_index = 1; +		actions.texture_layout_set = 3; +		actions.base_uniform_string = "material."; +		actions.base_varying_index = 10; + +		actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; +		actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; +		actions.global_buffer_array_variable = "global_variables.data"; + +		particles_shader.compiler.initialize(actions); +	} + +	{ +		// default material and shader for particles shader +		particles_shader.default_shader = shader_create(); +		shader_set_code(particles_shader.default_shader, "shader_type particles; void compute() { COLOR = vec4(1.0); } \n"); +		particles_shader.default_material = material_create(); +		material_set_shader(particles_shader.default_material, particles_shader.default_shader); + +		ParticlesMaterialData *md = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, RasterizerStorageRD::SHADER_TYPE_PARTICLES); +		particles_shader.default_shader_rd = particles_shader.shader.version_get_shader(md->shader_data->version, 0); + +		Vector<RD::Uniform> uniforms; + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 1; +			u.ids.resize(12); +			RID *ids_ptr = u.ids.ptrw(); +			ids_ptr[0] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[1] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[2] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[3] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[4] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[5] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[6] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[7] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[8] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[9] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[10] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[11] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 2; +			u.ids.push_back(global_variables_get_storage_buffer()); +			uniforms.push_back(u); +		} + +		particles_shader.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 0); +	} + +	default_rd_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4); + +	{ +		Vector<String> copy_modes; +		copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n"); +		copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n"); +		copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n"); + +		particles_shader.copy_shader.initialize(copy_modes); + +		particles_shader.copy_shader_version = particles_shader.copy_shader.version_create(); + +		for (int i = 0; i < ParticlesShader::COPY_MODE_MAX; i++) { +			particles_shader.copy_pipelines[i] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i)); +		} +	}  }  RasterizerStorageRD::~RasterizerStorageRD() { @@ -6234,7 +8152,14 @@ RasterizerStorageRD::~RasterizerStorageRD() {  	for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) {  		RD::get_singleton()->free(mesh_default_rd_buffers[i]);  	} +  	giprobe_sdf_shader.version_free(giprobe_sdf_shader_version); +	particles_shader.copy_shader.version_free(particles_shader.copy_shader_version); + +	RenderingServer::get_singleton()->free(particles_shader.default_material); +	RenderingServer::get_singleton()->free(particles_shader.default_shader); + +	RD::get_singleton()->free(default_rd_storage_buffer);  	if (decal_atlas.textures.size()) {  		ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas."); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index b7aedf8717..05cb1b4a73 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -31,11 +31,13 @@  #ifndef RASTERIZER_STORAGE_RD_H  #define RASTERIZER_STORAGE_RD_H -#include "core/rid_owner.h" +#include "core/templates/rid_owner.h"  #include "servers/rendering/rasterizer.h"  #include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h"  #include "servers/rendering/rasterizer_rd/shader_compiler_rd.h"  #include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/particles.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/particles_copy.glsl.gen.h"  #include "servers/rendering/rendering_device.h"  class RasterizerStorageRD : public RasterizerStorage { @@ -172,6 +174,29 @@ public:  	};  private: +	/* CANVAS TEXTURE API (2D) */ + +	struct CanvasTexture { +		RID diffuse; +		RID normalmap; +		RID specular; +		Color specular_color = Color(1, 1, 1, 1); +		float shininess = 1.0; + +		RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; +		RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; +		RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; + +		Size2i size_cache = Size2i(1, 1); +		bool use_normal_cache = false; +		bool use_specular_cache = false; +		bool cleared_cache = true; +		void clear_sets(); +		~CanvasTexture(); +	}; + +	RID_PtrOwner<CanvasTexture> canvas_texture_owner; +  	/* TEXTURE API */  	struct Texture {  		enum Type { @@ -203,6 +228,14 @@ private:  		int height_2d;  		int width_2d; +		struct BufferSlice3D { +			Size2i size; +			uint32_t offset = 0; +			uint32_t buffer_size = 0; +		}; +		Vector<BufferSlice3D> buffer_slices_3d; +		uint32_t buffer_size_3d = 0; +  		bool is_render_target;  		bool is_proxy; @@ -221,6 +254,8 @@ private:  		RS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr;  		void *detect_roughness_callback_ud = nullptr; + +		CanvasTexture *canvas_texture = nullptr;  	};  	struct TextureToRDFormat { @@ -247,6 +282,7 @@ private:  	RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];  	RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; +	RID default_rd_storage_buffer;  	/* DECAL ATLAS */ @@ -386,6 +422,9 @@ private:  			uint32_t multimesh_render_index = 0;  			uint64_t multimesh_render_pass = 0; + +			uint32_t particles_render_index = 0; +			uint64_t particles_render_pass = 0;  		};  		uint32_t blend_shape_count = 0; @@ -448,6 +487,324 @@ private:  	_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);  	void _update_dirty_multimeshes(); +	/* PARTICLES */ + +	struct ParticleData { +		float xform[16]; +		float velocity[3]; +		uint32_t active; +		float color[4]; +		float custom[3]; +		float lifetime; +		uint32_t pad[3]; +	}; + +	struct ParticlesFrameParams { +		enum { +			MAX_ATTRACTORS = 32, +			MAX_COLLIDERS = 32, +			MAX_3D_TEXTURES = 7 +		}; + +		enum AttractorType { +			ATTRACTOR_TYPE_SPHERE, +			ATTRACTOR_TYPE_BOX, +			ATTRACTOR_TYPE_VECTOR_FIELD, +		}; + +		struct Attractor { +			float transform[16]; +			float extents[3]; //exents or radius +			uint32_t type; + +			uint32_t texture_index; //texture index for vector field +			float strength; +			float attenuation; +			float directionality; +		}; + +		enum CollisionType { +			COLLISION_TYPE_SPHERE, +			COLLISION_TYPE_BOX, +			COLLISION_TYPE_SDF, +			COLLISION_TYPE_HEIGHT_FIELD +		}; + +		struct Collider { +			float transform[16]; +			float extents[3]; //exents or radius +			uint32_t type; + +			uint32_t texture_index; //texture index for vector field +			float scale; +			uint32_t pad[2]; +		}; + +		uint32_t emitting; +		float system_phase; +		float prev_system_phase; +		uint32_t cycle; + +		float explosiveness; +		float randomness; +		float time; +		float delta; + +		uint32_t random_seed; +		uint32_t attractor_count; +		uint32_t collider_count; +		float particle_size; + +		float emission_transform[16]; + +		Attractor attractors[MAX_ATTRACTORS]; +		Collider colliders[MAX_COLLIDERS]; +	}; + +	struct ParticleEmissionBufferData { +	}; + +	struct ParticleEmissionBuffer { +		struct Data { +			float xform[16]; +			float velocity[3]; +			uint32_t flags; +			float color[4]; +			float custom[4]; +		}; + +		int32_t particle_count; +		int32_t particle_max; +		uint32_t pad1; +		uint32_t pad2; +		Data data[1]; //its 2020 and empty arrays are still non standard in C++ +	}; + +	struct Particles { +		bool inactive; +		float inactive_time; +		bool emitting; +		bool one_shot; +		int amount; +		float lifetime; +		float pre_process_time; +		float explosiveness; +		float randomness; +		bool restart_request; +		AABB custom_aabb; +		bool use_local_coords; +		RID process_material; + +		RS::ParticlesDrawOrder draw_order; + +		Vector<RID> draw_passes; + +		RID particle_buffer; +		RID particle_instance_buffer; +		RID frame_params_buffer; + +		RID particles_material_uniform_set; +		RID particles_copy_uniform_set; +		RID particles_transforms_buffer_uniform_set; +		RID collision_textures_uniform_set; + +		RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES]; +		uint32_t collision_3d_textures_used = 0; +		RID collision_heightmap_texture; + +		RID particles_sort_buffer; +		RID particles_sort_uniform_set; + +		bool dirty = false; +		Particles *update_list = nullptr; + +		RID sub_emitter; + +		float phase; +		float prev_phase; +		uint64_t prev_ticks; +		uint32_t random_seed; + +		uint32_t cycle_number; + +		float speed_scale; + +		int fixed_fps; +		bool fractional_delta; +		float frame_remainder; +		float collision_base_size; + +		bool clear; + +		bool force_sub_emit = false; + +		Transform emission_transform; + +		Vector<uint8_t> emission_buffer_data; + +		ParticleEmissionBuffer *emission_buffer = nullptr; +		RID emission_storage_buffer; + +		Set<RasterizerScene::InstanceBase *> collisions; + +		Particles() : +				inactive(true), +				inactive_time(0.0), +				emitting(false), +				one_shot(false), +				amount(0), +				lifetime(1.0), +				pre_process_time(0.0), +				explosiveness(0.0), +				randomness(0.0), +				restart_request(false), +				custom_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))), +				use_local_coords(true), +				draw_order(RS::PARTICLES_DRAW_ORDER_INDEX), +				prev_ticks(0), +				random_seed(0), +				cycle_number(0), +				speed_scale(1.0), +				fixed_fps(0), +				fractional_delta(false), +				frame_remainder(0), +				collision_base_size(0.01), +				clear(true) { +		} + +		RasterizerScene::InstanceDependency instance_dependency; + +		ParticlesFrameParams frame_params; +	}; + +	void _particles_process(Particles *p_particles, float p_delta); +	void _particles_allocate_emission_buffer(Particles *particles); +	void _particles_free_data(Particles *particles); + +	struct ParticlesShader { +		struct PushConstant { +			float lifetime; +			uint32_t clear; +			uint32_t total_particles; +			uint32_t trail_size; + +			uint32_t use_fractional_delta; +			uint32_t sub_emitter_mode; +			uint32_t can_emit; +			uint32_t pad; +		}; + +		ParticlesShaderRD shader; +		ShaderCompilerRD compiler; + +		RID default_shader; +		RID default_material; +		RID default_shader_rd; + +		RID base_uniform_set; + +		struct CopyPushConstant { +			float sort_direction[3]; +			uint32_t total_particles; +		}; + +		enum { +			COPY_MODE_FILL_INSTANCES, +			COPY_MODE_FILL_SORT_BUFFER, +			COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER, +			COPY_MODE_MAX, +		}; + +		ParticlesCopyShaderRD copy_shader; +		RID copy_shader_version; +		RID copy_pipelines[COPY_MODE_MAX]; + +	} particles_shader; + +	Particles *particle_update_list = nullptr; + +	struct ParticlesShaderData : public ShaderData { +		bool valid; +		RID version; + +		//RenderPipelineVertexFormatCacheRD pipelines[SKY_VERSION_MAX]; +		Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; +		Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + +		Vector<uint32_t> ubo_offsets; +		uint32_t ubo_size; + +		String path; +		String code; +		Map<StringName, RID> default_texture_params; + +		RID pipeline; + +		bool uses_time; + +		virtual void set_code(const String &p_Code); +		virtual void set_default_texture_param(const StringName &p_name, RID p_texture); +		virtual void get_param_list(List<PropertyInfo> *p_param_list) const; +		virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; +		virtual bool is_param_texture(const StringName &p_param) const; +		virtual bool is_animated() const; +		virtual bool casts_shadows() const; +		virtual Variant get_default_parameter(const StringName &p_parameter) const; +		ParticlesShaderData(); +		virtual ~ParticlesShaderData(); +	}; + +	ShaderData *_create_particles_shader_func(); +	static RasterizerStorageRD::ShaderData *_create_particles_shader_funcs() { +		return base_singleton->_create_particles_shader_func(); +	} + +	struct ParticlesMaterialData : public MaterialData { +		uint64_t last_frame; +		ParticlesShaderData *shader_data; +		RID uniform_buffer; +		RID uniform_set; +		Vector<RID> texture_cache; +		Vector<uint8_t> ubo_data; +		bool uniform_set_updated; + +		virtual void set_render_priority(int p_priority) {} +		virtual void set_next_pass(RID p_pass) {} +		virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); +		virtual ~ParticlesMaterialData(); +	}; + +	MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader); +	static RasterizerStorageRD::MaterialData *_create_particles_material_funcs(ShaderData *p_shader) { +		return base_singleton->_create_particles_material_func(static_cast<ParticlesShaderData *>(p_shader)); +	} + +	void update_particles(); + +	mutable RID_Owner<Particles> particles_owner; + +	/* Particles Collision */ + +	struct ParticlesCollision { +		RS::ParticlesCollisionType type = RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT; +		uint32_t cull_mask = 0xFFFFFFFF; +		float radius = 1.0; +		Vector3 extents = Vector3(1, 1, 1); +		float attractor_strength = 1.0; +		float attractor_attenuation = 1.0; +		float attractor_directionality = 0.0; +		RID field_texture; +		RID heightfield_texture; +		RID heightfield_fb; +		Size2i heightfield_fb_size; + +		RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024; + +		RasterizerScene::InstanceDependency instance_dependency; +	}; + +	mutable RID_Owner<ParticlesCollision> particles_collision_owner; +  	/* Skeleton */  	struct Skeleton { @@ -632,6 +989,7 @@ private:  		bool flags[RENDER_TARGET_FLAG_MAX];  		RID backbuffer; //used for effects +		RID backbuffer_fb;  		RID backbuffer_mipmap0;  		struct BackbufferMipmap { @@ -640,6 +998,8 @@ private:  		};  		Vector<BackbufferMipmap> backbuffer_mipmaps; + +		RID framebuffer_uniform_set;  		RID backbuffer_uniform_set;  		//texture generated for this owner (nor RD). @@ -732,14 +1092,14 @@ public:  	virtual RID texture_2d_create(const Ref<Image> &p_image);  	virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type); -	virtual RID texture_3d_create(const Vector<Ref<Image>> &p_slices); //all slices, then all the mipmaps, must be coherent +	virtual RID texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data); //all slices, then all the mipmaps, must be coherent  	virtual RID texture_proxy_create(RID p_base);  	virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate);  	virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); //mostly used for video and streaming  	virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); -	virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap); +	virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data);  	virtual void texture_proxy_update(RID p_texture, RID p_proxy_to);  	//these two APIs can be used together or in combination with the others. @@ -749,7 +1109,7 @@ public:  	virtual Ref<Image> texture_2d_get(RID p_texture) const;  	virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const; -	virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const; +	virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const;  	virtual void texture_replace(RID p_texture, RID p_by_texture);  	virtual void texture_set_size_override(RID p_texture, int p_width, int p_height); @@ -815,6 +1175,18 @@ public:  		return default_rd_samplers[p_filter][p_repeat];  	} +	/* CANVAS TEXTURE API */ + +	virtual RID canvas_texture_create(); + +	virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture); +	virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess); + +	virtual void canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter); +	virtual void canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat); + +	bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular); +  	/* SHADER API */  	RID shader_create(); @@ -977,6 +1349,19 @@ public:  		return s->multimesh_render_index;  	} +	_FORCE_INLINE_ uint32_t mesh_surface_get_particles_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) { +		Mesh *mesh = mesh_owner.getornull(p_mesh); +		Mesh::Surface *s = mesh->surfaces[p_surface_index]; + +		if (s->particles_render_pass != p_render_pass) { +			(*r_index)++; +			s->particles_render_pass = p_render_pass; +			s->particles_render_index = *r_index; +		} + +		return s->particles_render_index; +	} +  	/* MULTIMESH API */  	RID multimesh_create(); @@ -1184,6 +1569,13 @@ public:  		return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];  	} +	_FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const { +		const Light *light = light_owner.getornull(p_light); +		ERR_FAIL_COND_V(!light, 0.0); + +		return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE]; +	} +  	RS::LightBakeMode light_get_bake_mode(RID p_light);  	uint32_t light_get_max_sdfgi_cascade(RID p_light);  	uint64_t light_get_version(RID p_light) const; @@ -1400,39 +1792,99 @@ public:  	/* PARTICLES */ -	RID particles_create() { return RID(); } +	RID particles_create(); + +	void particles_set_emitting(RID p_particles, bool p_emitting); +	void particles_set_amount(RID p_particles, int p_amount); +	void particles_set_lifetime(RID p_particles, float p_lifetime); +	void particles_set_one_shot(RID p_particles, bool p_one_shot); +	void particles_set_pre_process_time(RID p_particles, float p_time); +	void particles_set_explosiveness_ratio(RID p_particles, float p_ratio); +	void particles_set_randomness_ratio(RID p_particles, float p_ratio); +	void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb); +	void particles_set_speed_scale(RID p_particles, float p_scale); +	void particles_set_use_local_coordinates(RID p_particles, bool p_enable); +	void particles_set_process_material(RID p_particles, RID p_material); +	void particles_set_fixed_fps(RID p_particles, int p_fps); +	void particles_set_fractional_delta(RID p_particles, bool p_enable); +	void particles_set_collision_base_size(RID p_particles, float p_size); +	void particles_restart(RID p_particles); +	void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); +	void particles_set_subemitter(RID p_particles, RID p_subemitter_particles); + +	void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order); + +	void particles_set_draw_passes(RID p_particles, int p_count); +	void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh); + +	void particles_request_process(RID p_particles); +	AABB particles_get_current_aabb(RID p_particles); +	AABB particles_get_aabb(RID p_particles) const; -	void particles_set_emitting(RID p_particles, bool p_emitting) {} -	void particles_set_amount(RID p_particles, int p_amount) {} -	void particles_set_lifetime(RID p_particles, float p_lifetime) {} -	void particles_set_one_shot(RID p_particles, bool p_one_shot) {} -	void particles_set_pre_process_time(RID p_particles, float p_time) {} -	void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {} -	void particles_set_randomness_ratio(RID p_particles, float p_ratio) {} -	void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {} -	void particles_set_speed_scale(RID p_particles, float p_scale) {} -	void particles_set_use_local_coordinates(RID p_particles, bool p_enable) {} -	void particles_set_process_material(RID p_particles, RID p_material) {} -	void particles_set_fixed_fps(RID p_particles, int p_fps) {} -	void particles_set_fractional_delta(RID p_particles, bool p_enable) {} -	void particles_restart(RID p_particles) {} +	void particles_set_emission_transform(RID p_particles, const Transform &p_transform); -	void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {} +	bool particles_get_emitting(RID p_particles); +	int particles_get_draw_passes(RID p_particles) const; +	RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; -	void particles_set_draw_passes(RID p_particles, int p_count) {} -	void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {} +	void particles_set_view_axis(RID p_particles, const Vector3 &p_axis); -	void particles_request_process(RID p_particles) {} -	AABB particles_get_current_aabb(RID p_particles) { return AABB(); } -	AABB particles_get_aabb(RID p_particles) const { return AABB(); } +	virtual bool particles_is_inactive(RID p_particles) const; -	void particles_set_emission_transform(RID p_particles, const Transform &p_transform) {} +	_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) { +		Particles *particles = particles_owner.getornull(p_particles); +		ERR_FAIL_COND_V(!particles, 0); -	bool particles_get_emitting(RID p_particles) { return false; } -	int particles_get_draw_passes(RID p_particles) const { return 0; } -	RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); } +		return particles->amount; +	} + +	_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) { +		Particles *particles = particles_owner.getornull(p_particles); +		ERR_FAIL_COND_V(!particles, false); + +		return particles->use_local_coords; +	} + +	_FORCE_INLINE_ RID particles_get_instance_buffer_uniform_set(RID p_particles, RID p_shader, uint32_t p_set) { +		Particles *particles = particles_owner.getornull(p_particles); +		ERR_FAIL_COND_V(!particles, RID()); +		if (particles->particles_transforms_buffer_uniform_set.is_null()) { +			Vector<RD::Uniform> uniforms; + +			{ +				RD::Uniform u; +				u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 0; +				u.ids.push_back(particles->particle_instance_buffer); +				uniforms.push_back(u); +			} -	virtual bool particles_is_inactive(RID p_particles) const { return false; } +			particles->particles_transforms_buffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set); +		} + +		return particles->particles_transforms_buffer_uniform_set; +	} + +	virtual void particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); +	virtual void particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); + +	/* PARTICLES COLLISION */ + +	virtual RID particles_collision_create(); +	virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type); +	virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask); +	virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius); //for spheres +	virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents); //for non-spheres +	virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength); +	virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality); +	virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve); +	virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture); //for SDF and vector field, heightfield is dynamic +	virtual void particles_collision_height_field_update(RID p_particles_collision); //for SDF and vector field +	virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution); //for SDF and vector field +	virtual AABB particles_collision_get_aabb(RID p_particles_collision) const; +	virtual Vector3 particles_collision_get_extents(RID p_particles_collision) const; +	virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; +	RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;  	/* GLOBAL VARIABLES API */ @@ -1465,7 +1917,10 @@ public:  	void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);  	bool render_target_was_used(RID p_render_target);  	void render_target_set_as_unused(RID p_render_target); -	void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region); +	void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); +	void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); +	void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region); +  	RID render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader);  	virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color); @@ -1477,6 +1932,14 @@ public:  	Size2 render_target_get_size(RID p_render_target);  	RID render_target_get_rd_framebuffer(RID p_render_target);  	RID render_target_get_rd_texture(RID p_render_target); +	RID render_target_get_rd_backbuffer(RID p_render_target); +	RID render_target_get_rd_backbuffer_framebuffer(RID p_render_target); + +	RID render_target_get_framebuffer_uniform_set(RID p_render_target); +	RID render_target_get_backbuffer_uniform_set(RID p_render_target); + +	void render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set); +	void render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set);  	RS::InstanceType get_base_type(RID p_rid) const; @@ -1504,6 +1967,8 @@ public:  	virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;  	virtual String get_captured_timestamp_name(uint32_t p_index) const; +	RID get_default_rd_storage_buffer() { return default_rd_storage_buffer; } +  	static RasterizerStorageRD *base_singleton;  	RasterizerEffectsRD *get_effects(); diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h index cf15e79586..6a72dbc77c 100644 --- a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h +++ b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h @@ -31,7 +31,7 @@  #ifndef RENDER_PIPELINE_CACHE_RD_H  #define RENDER_PIPELINE_CACHE_RD_H -#include "core/spin_lock.h" +#include "core/os/spin_lock.h"  #include "servers/rendering/rendering_device.h"  class RenderPipelineVertexFormatCacheRD { diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp index 1820c39c5a..1a33e9a567 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp @@ -30,8 +30,8 @@  #include "shader_compiler_rd.h" +#include "core/config/project_settings.h"  #include "core/os/os.h" -#include "core/project_settings.h"  #include "rasterizer_storage_rd.h"  #include "servers/rendering_server.h" @@ -423,13 +423,13 @@ static String _get_global_variable_from_type_and_index(const String &p_buffer, c  			return "(" + p_buffer + "[" + p_index + "].x != 0.0)";  		}  		case ShaderLanguage::TYPE_BVEC2: { -			return "(" + p_buffer + "[" + p_index + "].xy != vec2(0.0))"; +			return "(notEqual(" + p_buffer + "[" + p_index + "].xy, vec2(0.0)))";  		}  		case ShaderLanguage::TYPE_BVEC3: { -			return "(" + p_buffer + "[" + p_index + "].xyz != vec3(0.0))"; +			return "(notEqual(" + p_buffer + "[" + p_index + "].xyz, vec3(0.0)))";  		}  		case ShaderLanguage::TYPE_BVEC4: { -			return "(" + p_buffer + "[" + p_index + "].xyzw != vec4(0.0))"; +			return "(notEqual(" + p_buffer + "[" + p_index + "].xyzw, vec4(0.0)))";  		}  		case ShaderLanguage::TYPE_INT: {  			return "floatBitsToInt(" + p_buffer + "[" + p_index + "].x)"; @@ -444,16 +444,16 @@ static String _get_global_variable_from_type_and_index(const String &p_buffer, c  			return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xyzw)";  		}  		case ShaderLanguage::TYPE_UINT: { -			return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].x)"; +			return "floatBitsToUint(" + p_buffer + "[" + p_index + "].x)";  		}  		case ShaderLanguage::TYPE_UVEC2: { -			return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xy)"; +			return "floatBitsToUint(" + p_buffer + "[" + p_index + "].xy)";  		}  		case ShaderLanguage::TYPE_UVEC3: { -			return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyz)"; +			return "floatBitsToUint(" + p_buffer + "[" + p_index + "].xyz)";  		}  		case ShaderLanguage::TYPE_UVEC4: { -			return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyzw)"; +			return "floatBitsToUint(" + p_buffer + "[" + p_index + "].xyzw)";  		}  		case ShaderLanguage::TYPE_FLOAT: {  			return "(" + p_buffer + "[" + p_index + "].x)"; @@ -537,6 +537,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge  				r_gen_code.vertex_global += struct_code;  				r_gen_code.fragment_global += struct_code; +				r_gen_code.compute_global += struct_code;  			}  			int max_texture_uniforms = 0; @@ -591,6 +592,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge  				if (SL::is_sampler_type(E->get().type)) {  					r_gen_code.vertex_global += ucode;  					r_gen_code.fragment_global += ucode; +					r_gen_code.compute_global += ucode;  					GeneratedCode::Texture texture;  					texture.name = E->key(); @@ -700,6 +702,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge  				vcode += ";\n";  				r_gen_code.vertex_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;  				r_gen_code.fragment_global += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode; +				r_gen_code.compute_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;  				index++;  			} @@ -724,6 +727,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge  				gcode += ";\n";  				r_gen_code.vertex_global += gcode;  				r_gen_code.fragment_global += gcode; +				r_gen_code.compute_global += gcode;  			}  			Map<StringName, String> function_code; @@ -741,6 +745,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge  			Set<StringName> added_vtx;  			Set<StringName> added_fragment; //share for light +			Set<StringName> added_compute; //share for light  			for (int i = 0; i < pnode->functions.size(); i++) {  				SL::FunctionNode *fnode = pnode->functions[i].function; @@ -763,6 +768,12 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge  					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);  					r_gen_code.light = function_code[light_name];  				} + +				if (fnode->name == compute_name) { +					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.compute_global, added_compute); +					r_gen_code.compute = function_code[compute_name]; +				} +  				function = nullptr;  			} @@ -1245,6 +1256,8 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide  	r_gen_code.vertex_global = String();  	r_gen_code.fragment = String();  	r_gen_code.fragment_global = String(); +	r_gen_code.compute = String(); +	r_gen_code.compute_global = String();  	r_gen_code.light = String();  	r_gen_code.uses_fragment_time = false;  	r_gen_code.uses_vertex_time = false; @@ -1266,6 +1279,7 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {  	vertex_name = "vertex";  	fragment_name = "fragment"; +	compute_name = "compute";  	light_name = "light";  	time_name = "TIME"; @@ -1281,6 +1295,8 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {  	texture_functions.insert("textureLod");  	texture_functions.insert("textureProjLod");  	texture_functions.insert("textureGrad"); +	texture_functions.insert("textureSize"); +	texture_functions.insert("texelFetch");  }  ShaderCompilerRD::ShaderCompilerRD() { diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/rasterizer_rd/shader_compiler_rd.h index ce94fb743f..694f8fff91 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.h +++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.h @@ -31,7 +31,7 @@  #ifndef SHADER_COMPILER_RD_H  #define SHADER_COMPILER_RD_H -#include "core/pair.h" +#include "core/templates/pair.h"  #include "servers/rendering/shader_language.h"  #include "servers/rendering/shader_types.h"  #include "servers/rendering_server.h" @@ -68,6 +68,8 @@ public:  		String fragment_global;  		String fragment;  		String light; +		String compute_global; +		String compute;  		bool uses_global_textures;  		bool uses_fragment_time; @@ -104,6 +106,7 @@ private:  	StringName vertex_name;  	StringName fragment_name;  	StringName light_name; +	StringName compute_name;  	StringName time_name;  	Set<StringName> texture_functions; diff --git a/servers/rendering/rasterizer_rd/shader_rd.cpp b/servers/rendering/rasterizer_rd/shader_rd.cpp index 8c57651263..865a1e1bbe 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.cpp +++ b/servers/rendering/rasterizer_rd/shader_rd.cpp @@ -30,7 +30,7 @@  #include "shader_rd.h" -#include "core/string_builder.h" +#include "core/string/string_builder.h"  #include "rasterizer_rd.h"  #include "servers/rendering/rendering_device.h" diff --git a/servers/rendering/rasterizer_rd/shader_rd.h b/servers/rendering/rasterizer_rd/shader_rd.h index d9bb068ba6..0c379db6f2 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.h +++ b/servers/rendering/rasterizer_rd/shader_rd.h @@ -31,11 +31,11 @@  #ifndef SHADER_RD_H  #define SHADER_RD_H -#include "core/hash_map.h" -#include "core/map.h"  #include "core/os/mutex.h" -#include "core/rid_owner.h" -#include "core/variant.h" +#include "core/templates/hash_map.h" +#include "core/templates/map.h" +#include "core/templates/rid_owner.h" +#include "core/variant/variant.h"  #include <stdio.h>  /** diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index 67f4edc626..9d531d63ad 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -35,3 +35,8 @@ if "RD_GLSL" in env["BUILDERS"]:      env.RD_GLSL("sdfgi_direct_light.glsl")      env.RD_GLSL("sdfgi_debug.glsl")      env.RD_GLSL("sdfgi_debug_probes.glsl") +    env.RD_GLSL("volumetric_fog.glsl") +    env.RD_GLSL("shadow_reduce.glsl") +    env.RD_GLSL("particles.glsl") +    env.RD_GLSL("particles_copy.glsl") +    env.RD_GLSL("sort.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl index e33b3face9..2a0f94e733 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl @@ -26,7 +26,7 @@ layout(location = 3) out vec2 pixel_size_interp;  #endif  #ifdef USE_MATERIAL_UNIFORMS -layout(set = 1, binding = 1, std140) uniform MaterialUniforms{ +layout(set = 1, binding = 0, std140) uniform MaterialUniforms{  	/* clang-format off */  MATERIAL_UNIFORMS  	/* clang-format on */ @@ -101,7 +101,7 @@ void main() {  				offset += 1;  			} else {  				instance_color = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3)); -				offser += 4; +				offset += 4;  			}  			color *= instance_color; @@ -144,7 +144,7 @@ VERTEX_SHADER_CODE  	color_interp = color; -	if (bool(draw_data.flags & FLAGS_USE_PIXEL_SNAP)) { +	if (canvas_data.use_pixel_snap) {  		vertex = floor(vertex + 0.5);  		// precision issue on some hardware creates artifacts within texture  		// offset uv by a small amount to avoid @@ -226,7 +226,7 @@ layout(location = 3) in vec2 pixel_size_interp;  layout(location = 0) out vec4 frag_color;  #ifdef USE_MATERIAL_UNIFORMS -layout(set = 1, binding = 1, std140) uniform MaterialUniforms{ +layout(set = 1, binding = 0, std140) uniform MaterialUniforms{  	/* clang-format off */  MATERIAL_UNIFORMS  	/* clang-format on */ @@ -249,7 +249,7 @@ vec4 light_compute(  		inout vec4 shadow_modulate,  		vec2 screen_uv,  		vec2 uv, -		vec4 color) { +		vec4 color, bool is_directional) {  	vec4 light = vec4(0.0);  	/* clang-format off */  LIGHT_SHADER_CODE @@ -302,6 +302,99 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo  #endif +#ifdef USE_LIGHTING + +vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) { +	float cNdotL = max(0.0, dot(normal, light_vec)); + +	if (specular_shininess_used) { +		//blinn +		vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough +		vec3 half_vec = normalize(view + light_vec); + +		float cNdotV = max(dot(normal, view), 0.0); +		float cNdotH = max(dot(normal, half_vec), 0.0); +		float cVdotH = max(dot(view, half_vec), 0.0); +		float cLdotH = max(dot(light_vec, half_vec), 0.0); +		float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; +		float blinn = pow(cNdotH, shininess); +		blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); +		float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + +		return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL; +	} else { +		return light_color * base_color * cNdotL; +	} +} + +//float distance = length(shadow_pos); +vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv +#ifdef LIGHT_SHADER_CODE_USED +		, +		vec3 shadow_modulate +#endif +) { +	float shadow; +	uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; + +	if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { +		shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; +	} else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { +		vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); +		shadow = 0.0; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; +		shadow /= 5.0; +	} else { //PCF13 +		vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); +		shadow = 0.0; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x; +		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x; +		shadow /= 13.0; +	} + +	vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color); +#ifdef LIGHT_SHADER_CODE_USED +	shadow_color *= shadow_modulate; +#endif + +	shadow_color.a *= light_color.a; //respect light alpha + +	return mix(light_color, shadow_color, shadow); +} + +void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) { +	uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; + +	switch (blend_mode) { +		case LIGHT_FLAGS_BLEND_MODE_ADD: { +			color.rgb += light_color.rgb * light_color.a; +		} break; +		case LIGHT_FLAGS_BLEND_MODE_SUB: { +			color.rgb -= light_color.rgb * light_color.a; +		} break; +		case LIGHT_FLAGS_BLEND_MODE_MIX: { +			color.rgb = mix(color.rgb, light_color.rgb, light_color.a); +		} break; +	} +} + +#endif +  void main() {  	vec4 color = color_interp;  	vec2 uv = uv_interp; @@ -332,6 +425,7 @@ void main() {  	color *= texture(sampler2D(color_texture, texture_sampler), uv);  	uint light_count = (draw_data.flags >> FLAGS_LIGHT_COUNT_SHIFT) & 0xF; //max 16 lights +	bool using_light = light_count > 0 || canvas_data.directional_light_count > 0;  	vec3 normal; @@ -341,7 +435,7 @@ void main() {  	bool normal_used = false;  #endif -	if (normal_used || (light_count > 0 && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { +	if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {  		normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);  		normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));  		normal_used = true; @@ -358,7 +452,7 @@ void main() {  	bool specular_shininess_used = false;  #endif -	if (specular_shininess_used || (light_count > 0 && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) { +	if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {  		specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);  		specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess);  		specular_shininess_used = true; @@ -401,14 +495,53 @@ FRAGMENT_SHADER_CODE  		normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz);  	} -	vec4 base_color = color; +	vec3 base_color = color.rgb;  	if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) {  		color = vec4(0.0); //invisible by default due to using light mask  	}  	color *= canvas_data.canvas_modulation;  #ifdef USE_LIGHTING -	for (uint i = 0; i < MAX_LIGHT_TEXTURES; i++) { + +	// Directional Lights + +	for (uint i = 0; i < canvas_data.directional_light_count; i++) { +		uint light_base = i; + +		vec2 direction = light_array.data[light_base].position; +		vec4 light_color = light_array.data[light_base].color; + +#ifdef LIGHT_SHADER_CODE_USED + +		vec4 shadow_modulate = vec4(1.0); +		light_color = light_compute(light_vertex, direction, normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, true); +#else + +		if (normal_used) { +			vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height)); +			light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); +		} +#endif + +		if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { +			vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. + +			vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0); + +			light_color = light_shadow_compute(light_base, light_color, shadow_uv +#ifdef LIGHT_SHADER_CODE_USED +					, +					shadow_modulate +#endif +			); +		} + +		light_blend_compute(light_base, light_color, color.rgb); +	} + +	// Positional Lights + +	for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) {  		if (i >= light_count) {  			break;  		} @@ -430,7 +563,8 @@ FRAGMENT_SHADER_CODE  		light_base &= 0xFF;  		vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array.data[light_base].texture_matrix[0], light_array.data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. -		vec4 light_color = texture(sampler2D(light_textures[i], texture_sampler), tex_uv); +		vec2 tex_uv_atlas = tex_uv * light_array.data[light_base].atlas_rect.zw + light_array.data[light_base].atlas_rect.xy; +		vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);  		vec4 light_base_color = light_array.data[light_base].color;  #ifdef LIGHT_SHADER_CODE_USED @@ -439,7 +573,7 @@ FRAGMENT_SHADER_CODE  		vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);  		light_color.rgb *= light_base_color.rgb; -		light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv); +		light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, false);  #else  		light_color.rgb *= light_base_color.rgb * light_base_color.a; @@ -450,24 +584,7 @@ FRAGMENT_SHADER_CODE  			vec3 light_vec = normalize(light_pos - pos);  			float cNdotL = max(0.0, dot(normal, light_vec)); -			if (specular_shininess_used) { -				//blinn -				vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough -				vec3 half_vec = normalize(view + light_vec); - -				float cNdotV = max(dot(normal, view), 0.0); -				float cNdotH = max(dot(normal, half_vec), 0.0); -				float cVdotH = max(dot(view, half_vec), 0.0); -				float cLdotH = max(dot(light_vec, half_vec), 0.0); -				float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; -				float blinn = pow(cNdotH, shininess); -				blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); -				float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); - -				light_color.rgb = specular_shininess.rgb * light_base_color.rgb * s + light_color.rgb * cNdotL; -			} else { -				light_color.rgb *= cNdotL; -			} +			light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);  		}  #endif  		if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { @@ -502,66 +619,20 @@ FRAGMENT_SHADER_CODE  				}  			} +			distance *= light_array.data[light_base].shadow_zfar_inv; +  			//float distance = length(shadow_pos); -			float shadow; -			uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; - -			vec4 shadow_uv = vec4(tex_ofs, 0.0, distance, 1.0); - -			if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { -				shadow = textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv).x; -			} else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { -				vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); -				shadow = 0.0; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size * 2.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size * 2.0).x; -				shadow /= 5.0; -			} else { //PCF13 -				vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); -				shadow = 0.0; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size * 6.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size * 5.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size * 4.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size * 3.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size * 2.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv - shadow_pixel_size).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size * 2.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size * 3.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size * 4.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size * 5.0).x; -				shadow += textureProj(sampler2DShadow(shadow_textures[i], shadow_sampler), shadow_uv + shadow_pixel_size * 6.0).x; -				shadow /= 13.0; -			} +			vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0); -			vec4 shadow_color = light_array.data[light_base].shadow_color; +			light_color = light_shadow_compute(light_base, light_color, shadow_uv  #ifdef LIGHT_SHADER_CODE_USED -			shadow_color *= shadow_modulate; +					, +					shadow_modulate  #endif -			light_color = mix(light_color, shadow_color, shadow); +			);  		} -		uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; - -		switch (blend_mode) { -			case LIGHT_FLAGS_BLEND_MODE_ADD: { -				color.rgb += light_color.rgb * light_color.a; -			} break; -			case LIGHT_FLAGS_BLEND_MODE_SUB: { -				color.rgb -= light_color.rgb * light_color.a; -			} break; -			case LIGHT_FLAGS_BLEND_MODE_MIX: { -				color.rgb = mix(color.rgb, light_color.rgb, light_color.a); -			} break; -			case LIGHT_FLAGS_BLEND_MODE_MASK: { -				light_color.a *= base_color.a; -				color.rgb = mix(color.rgb, light_color.rgb, light_color.a); -			} break; -		} +		light_blend_compute(light_base, light_color, color.rgb);  	}  #endif diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl index 99e70a1976..421282cd4d 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl @@ -8,7 +8,8 @@ layout(push_constant, binding = 0, std430) uniform Constants {  	mat4 projection;  	mat2x4 modelview;  	vec2 direction; -	vec2 pad; +	float z_far; +	float pad;  }  constants; @@ -25,9 +26,18 @@ void main() {  #version 450 +layout(push_constant, binding = 0, std430) uniform Constants { +	mat4 projection; +	mat2x4 modelview; +	vec2 direction; +	float z_far; +	float pad; +} +constants; +  layout(location = 0) in highp float depth;  layout(location = 0) out highp float distance_buf;  void main() { -	distance_buf = depth; +	distance_buf = depth / constants.z_far;  } diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl index a39866004b..bb39584cbb 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl @@ -1,3 +1,6 @@ + +#define MAX_LIGHTS_PER_ITEM 16 +  #define M_PI 3.14159265359  #define FLAGS_INSTANCING_STRIDE_MASK 0xF @@ -12,7 +15,6 @@  #define FLAGS_USING_LIGHT_MASK (1 << 11)  #define FLAGS_NINEPACH_DRAW_CENTER (1 << 12)  #define FLAGS_USING_PARTICLES (1 << 13) -#define FLAGS_USE_PIXEL_SNAP (1 << 14)  #define FLAGS_NINEPATCH_H_MODE_SHIFT 16  #define FLAGS_NINEPATCH_V_MODE_SHIFT 18 @@ -22,13 +24,7 @@  #define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)  #define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) -// In vulkan, sets should always be ordered using the following logic: -// Lower Sets: Sets that change format and layout less often -// Higher sets: Sets that change format and layout very often -// This is because changing a set for another with a different layout or format, -// invalidates all the upper ones. - -/* SET0: Draw Primitive */ +// Push Constant  layout(push_constant, binding = 0, std430) uniform DrawData {  	vec2 world_x; @@ -53,46 +49,31 @@ layout(push_constant, binding = 0, std430) uniform DrawData {  }  draw_data; -// The values passed per draw primitives are cached within it - -layout(set = 0, binding = 1) uniform texture2D color_texture; -layout(set = 0, binding = 2) uniform texture2D normal_texture; -layout(set = 0, binding = 3) uniform texture2D specular_texture; -layout(set = 0, binding = 4) uniform sampler texture_sampler; - -layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer; - -/* SET1: Is reserved for the material */ - -#ifdef USE_MATERIAL_SAMPLERS - -layout(set = 1, binding = 0) uniform sampler material_samplers[12]; +// In vulkan, sets should always be ordered using the following logic: +// Lower Sets: Sets that change format and layout less often +// Higher sets: Sets that change format and layout very often +// This is because changing a set for another with a different layout or format, +// invalidates all the upper ones (as likely internal base offset changes) -#endif +/* SET0: Globals */ -/* SET2: Canvas Item State (including lighting) */ +// The values passed per draw primitives are cached within it -layout(set = 2, binding = 0, std140) uniform CanvasData { +layout(set = 0, binding = 1, std140) uniform CanvasData {  	mat4 canvas_transform;  	mat4 screen_transform;  	mat4 canvas_normal_transform;  	vec4 canvas_modulation;  	vec2 screen_pixel_size;  	float time; -	float time_pad; -	//uint light_count; -} -canvas_data; - -layout(set = 2, binding = 1) uniform textureBuffer skeleton_buffer; +	bool use_pixel_snap; -layout(set = 2, binding = 2, std140) uniform SkeletonData { -	mat4 skeleton_transform; //in world coordinates -	mat4 skeleton_transform_inverse; +	uint directional_light_count; +	uint pad0; +	uint pad1; +	uint pad2;  } -skeleton_data; - -#ifdef USE_LIGHTING +canvas_data;  #define LIGHT_FLAGS_BLEND_MASK (3 << 16)  #define LIGHT_FLAGS_BLEND_MODE_ADD (0 << 16) @@ -110,37 +91,52 @@ struct Light {  	mat2x4 texture_matrix; //light to texture coordinate matrix (transposed)  	mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed)  	vec4 color; -	vec4 shadow_color; -	vec2 position; + +	uint shadow_color; // packed  	uint flags; //index to light texture -	float height;  	float shadow_pixel_size; -	float pad0; -	float pad1; -	float pad2; +	float height; + +	vec2 position; +	float shadow_zfar_inv; +	float shadow_y_ofs; + +	vec4 atlas_rect;  }; -layout(set = 2, binding = 3, std140) uniform LightData { +layout(set = 0, binding = 2, std140) uniform LightData {  	Light data[MAX_LIGHTS];  }  light_array; -layout(set = 2, binding = 4) uniform texture2D light_textures[MAX_LIGHT_TEXTURES]; -layout(set = 2, binding = 5) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES]; +layout(set = 0, binding = 3) uniform texture2D atlas_texture; +layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture; -layout(set = 2, binding = 6) uniform sampler shadow_sampler; +layout(set = 0, binding = 5) uniform sampler shadow_sampler; -#endif +layout(set = 0, binding = 6) uniform texture2D screen_texture; -layout(set = 2, binding = 7, std430) restrict readonly buffer GlobalVariableData { +layout(set = 0, binding = 7) uniform sampler material_samplers[12]; + +layout(set = 0, binding = 8, std430) restrict readonly buffer GlobalVariableData {  	vec4 data[];  }  global_variables; -/* SET3: Render Target Data */ +/* SET1: Is reserved for the material */ + +// -#ifdef SCREEN_TEXTURE_USED +/* SET2: Instancing and Skeleton */ -layout(set = 3, binding = 0) uniform texture2D screen_texture; +layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { +	vec4 data[]; +} +transforms; -#endif +/* SET3: Texture */ + +layout(set = 3, binding = 0) uniform texture2D color_texture; +layout(set = 3, binding = 1) uniform texture2D normal_texture; +layout(set = 3, binding = 2) uniform texture2D specular_texture; +layout(set = 3, binding = 3) uniform sampler texture_sampler; diff --git a/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl b/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl new file mode 100644 index 0000000000..e723468dd8 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl @@ -0,0 +1,95 @@ + +#define CLUSTER_COUNTER_SHIFT 20 +#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1) +#define CLUSTER_COUNTER_MASK 0xfff + +struct LightData { //this structure needs to be as packed as possible +	vec3 position; +	float inv_radius; +	vec3 direction; +	float size; +	uint attenuation_energy; //attenuation +	uint color_specular; //rgb color, a specular (8 bit unorm) +	uint cone_attenuation_angle; // attenuation and angle, (16bit float) +	uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) +	vec4 atlas_rect; // rect in the shadow atlas +	mat4 shadow_matrix; +	float shadow_bias; +	float shadow_normal_bias; +	float transmittance_bias; +	float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle +	float soft_shadow_scale; // scales the shadow kernel for blurrier shadows +	uint mask; +	float shadow_volumetric_fog_fade; +	uint pad; +	vec4 projector_rect; //projector rect in srgb decal atlas +}; + +#define REFLECTION_AMBIENT_DISABLED 0 +#define REFLECTION_AMBIENT_ENVIRONMENT 1 +#define REFLECTION_AMBIENT_COLOR 2 + +struct ReflectionData { +	vec3 box_extents; +	float index; +	vec3 box_offset; +	uint mask; +	vec4 params; // intensity, 0, interior , boxproject +	vec3 ambient; // ambient color +	uint ambient_mode; +	mat4 local_matrix; // up to here for spot and omni, rest is for directional +	// notes: for ambientblend, use distance to edge to blend between already existing global environment +}; + +struct DirectionalLightData { +	vec3 direction; +	float energy; +	vec3 color; +	float size; +	float specular; +	uint mask; +	float softshadow_angle; +	float soft_shadow_scale; +	bool blend_splits; +	bool shadow_enabled; +	float fade_from; +	float fade_to; +	uvec3 pad; +	float shadow_volumetric_fog_fade; +	vec4 shadow_bias; +	vec4 shadow_normal_bias; +	vec4 shadow_transmittance_bias; +	vec4 shadow_z_range; +	vec4 shadow_range_begin; +	vec4 shadow_split_offsets; +	mat4 shadow_matrix1; +	mat4 shadow_matrix2; +	mat4 shadow_matrix3; +	mat4 shadow_matrix4; +	vec4 shadow_color1; +	vec4 shadow_color2; +	vec4 shadow_color3; +	vec4 shadow_color4; +	vec2 uv_scale1; +	vec2 uv_scale2; +	vec2 uv_scale3; +	vec2 uv_scale4; +}; + +struct DecalData { +	mat4 xform; //to decal transform +	vec3 inv_extents; +	float albedo_mix; +	vec4 albedo_rect; +	vec4 normal_rect; +	vec4 orm_rect; +	vec4 emission_rect; +	vec4 modulate; +	float emission_energy; +	uint mask; +	float upper_fade; +	float lower_fade; +	mat3x4 normal_xform; +	vec3 normal; +	float normal_fade; +}; diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index eb39c28fa9..cdd35dfb3f 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -14,6 +14,8 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;  #define FLAG_FLIP_Y (1 << 5)  #define FLAG_FORCE_LUMINANCE (1 << 6)  #define FLAG_COPY_ALL_SOURCE (1 << 7) +#define FLAG_HIGH_QUALITY_GLOW (1 << 8) +#define FLAG_ALPHA_TO_ONE (1 << 9)  layout(push_constant, binding = 1, std430) uniform Params {  	ivec4 section; @@ -34,6 +36,8 @@ layout(push_constant, binding = 1, std430) uniform Params {  	float camera_z_far;  	float camera_z_near;  	uint pad2[2]; + +	vec4 set_color;  }  params; @@ -41,7 +45,7 @@ params;  layout(set = 0, binding = 0) uniform samplerCubeArray source_color;  #elif defined(MODE_CUBEMAP_TO_PANORAMA)  layout(set = 0, binding = 0) uniform samplerCube source_color; -#else +#elif !defined(MODE_SET_COLOR)  layout(set = 0, binding = 0) uniform sampler2D source_color;  #endif @@ -57,12 +61,20 @@ layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buff  layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;  #endif +#ifdef MODE_GAUSSIAN_GLOW +shared vec4 local_cache[256]; +shared vec4 temp_cache[128]; +#endif +  void main() {  	// Pixel being shaded  	ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + +#ifndef MODE_GAUSSIAN_GLOW // Glow needs the extra threads  	if (any(greaterThanEqual(pos, params.section.zw))) { //too large, do nothing  		return;  	} +#endif  #ifdef MODE_MIPMAP @@ -103,45 +115,69 @@ void main() {  #ifdef MODE_GAUSSIAN_GLOW -	//Glow uses larger sigma 1 for a more rounded blur effect +	// First pass copy texture into 16x16 local memory for every 8x8 thread block +	vec2 quad_center_uv = clamp(vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.5) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); +	uint dest_index = gl_LocalInvocationID.x * 2 + gl_LocalInvocationID.y * 2 * 16; -#define GLOW_ADD(m_ofs, m_mult)                                                             \ -	{                                                                                       \ -		ivec2 ofs = base_pos + m_ofs;                                                       \ -		if (all(greaterThanEqual(ofs, section_begin)) && all(lessThan(ofs, section_end))) { \ -			color += texelFetch(source_color, ofs, 0) * m_mult;                             \ -		}                                                                                   \ +	if (bool(params.flags & FLAG_HIGH_QUALITY_GLOW)) { +		vec2 quad_offset_uv = clamp((vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.0)) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); + +		local_cache[dest_index] = (textureLod(source_color, quad_center_uv, 0) + textureLod(source_color, quad_offset_uv, 0)) * 0.5; +		local_cache[dest_index + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.z, 0.0), 0)) * 0.5; +		local_cache[dest_index + 16] = (textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0) + textureLod(source_color, quad_offset_uv + vec2(0.0, 1.0 / params.section.w), 0)) * 0.5; +		local_cache[dest_index + 16 + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.zw), 0)) * 0.5; +	} else { +		local_cache[dest_index] = textureLod(source_color, quad_center_uv, 0); +		local_cache[dest_index + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0); +		local_cache[dest_index + 16] = textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); +		local_cache[dest_index + 16 + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0);  	} +	memoryBarrierShared(); +	barrier(); + +	// Horizontal pass. Needs to copy into 8x16 chunk of local memory so vertical pass has full resolution +	uint read_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 32 + 4; +	vec4 color_top = vec4(0.0); +	color_top += local_cache[read_index] * 0.174938; +	color_top += local_cache[read_index + 1] * 0.165569; +	color_top += local_cache[read_index + 2] * 0.140367; +	color_top += local_cache[read_index + 3] * 0.106595; +	color_top += local_cache[read_index - 1] * 0.165569; +	color_top += local_cache[read_index - 2] * 0.140367; +	color_top += local_cache[read_index - 3] * 0.106595; + +	vec4 color_bottom = vec4(0.0); +	color_bottom += local_cache[read_index + 16] * 0.174938; +	color_bottom += local_cache[read_index + 1 + 16] * 0.165569; +	color_bottom += local_cache[read_index + 2 + 16] * 0.140367; +	color_bottom += local_cache[read_index + 3 + 16] * 0.106595; +	color_bottom += local_cache[read_index - 1 + 16] * 0.165569; +	color_bottom += local_cache[read_index - 2 + 16] * 0.140367; +	color_bottom += local_cache[read_index - 3 + 16] * 0.106595; + +	// rotate samples to take advantage of cache coherency +	uint write_index = gl_LocalInvocationID.y * 2 + gl_LocalInvocationID.x * 16; + +	temp_cache[write_index] = color_top; +	temp_cache[write_index + 1] = color_bottom; + +	memoryBarrierShared(); +	barrier(); + +	// Vertical pass +	uint index = gl_LocalInvocationID.y + gl_LocalInvocationID.x * 16 + 4;  	vec4 color = vec4(0.0); -	if (bool(params.flags & FLAG_HORIZONTAL)) { -		ivec2 base_pos = (pos + params.section.xy) << 1; -		ivec2 section_begin = params.section.xy << 1; -		ivec2 section_end = section_begin + (params.section.zw << 1); - -		GLOW_ADD(ivec2(0, 0), 0.174938); -		GLOW_ADD(ivec2(1, 0), 0.165569); -		GLOW_ADD(ivec2(2, 0), 0.140367); -		GLOW_ADD(ivec2(3, 0), 0.106595); -		GLOW_ADD(ivec2(-1, 0), 0.165569); -		GLOW_ADD(ivec2(-2, 0), 0.140367); -		GLOW_ADD(ivec2(-3, 0), 0.106595); -		color *= params.glow_strength; -	} else { -		ivec2 base_pos = pos + params.section.xy; -		ivec2 section_begin = params.section.xy; -		ivec2 section_end = section_begin + params.section.zw; - -		GLOW_ADD(ivec2(0, 0), 0.288713); -		GLOW_ADD(ivec2(0, 1), 0.233062); -		GLOW_ADD(ivec2(0, 2), 0.122581); -		GLOW_ADD(ivec2(0, -1), 0.233062); -		GLOW_ADD(ivec2(0, -2), 0.122581); -		color *= params.glow_strength; -	} +	color += temp_cache[index] * 0.174938; +	color += temp_cache[index + 1] * 0.165569; +	color += temp_cache[index + 2] * 0.140367; +	color += temp_cache[index + 3] * 0.106595; +	color += temp_cache[index - 1] * 0.165569; +	color += temp_cache[index - 2] * 0.140367; +	color += temp_cache[index - 3] * 0.106595; -#undef GLOW_ADD +	color *= params.glow_strength;  	if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) {  #ifdef GLOW_USE_AUTO_EXPOSURE @@ -170,25 +206,24 @@ void main() {  		}  		color = textureLod(source_color, uv, 0.0); -		if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { -			color.rgb = vec3(max(max(color.r, color.g), color.b)); -		} -		imageStore(dest_buffer, pos + params.target, color); -  	} else {  		color = texelFetch(source_color, pos + params.section.xy, 0); -		if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { -			color.rgb = vec3(max(max(color.r, color.g), color.b)); -		} -  		if (bool(params.flags & FLAG_FLIP_Y)) {  			pos.y = params.section.w - pos.y - 1;  		} +	} -		imageStore(dest_buffer, pos + params.target, color); +	if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { +		color.rgb = vec3(max(max(color.r, color.g), color.b));  	} +	if (bool(params.flags & FLAG_ALPHA_TO_ONE)) { +		color.a = 1.0; +	} + +	imageStore(dest_buffer, pos + params.target, color); +  #endif  #ifdef MODE_SIMPLE_COPY_DEPTH @@ -237,4 +272,8 @@ void main() {  #endif  	imageStore(dest_buffer, pos + params.target, color);  #endif + +#ifdef MODE_SET_COLOR +	imageStore(dest_buffer, pos + params.target, params.set_color); +#endif  } diff --git a/servers/rendering/rasterizer_rd/shaders/gi.glsl b/servers/rendering/rasterizer_rd/shaders/gi.glsl index a1939f75ad..8011dadc72 100644 --- a/servers/rendering/rasterizer_rd/shaders/gi.glsl +++ b/servers/rendering/rasterizer_rd/shaders/gi.glsl @@ -80,7 +80,7 @@ struct GIProbeData {  	float anisotropy_strength;  	float ambient_occlusion;  	float ambient_occlusion_size; -	uint pad2; +	uint mipmaps;  };  layout(set = 0, binding = 16, std140) uniform GIProbes { diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/rasterizer_rd/shaders/particles.glsl new file mode 100644 index 0000000000..926c7ef9fc --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/particles.glsl @@ -0,0 +1,549 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + +/* SET 0: GLOBAL DATA */ + +layout(set = 0, binding = 1) uniform sampler material_samplers[12]; + +layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData { +	vec4 data[]; +} +global_variables; + +/* Set 1: FRAME AND PARTICLE DATA */ + +// a frame history is kept for trail deterministic behavior + +#define MAX_ATTRACTORS 32 + +#define ATTRACTOR_TYPE_SPHERE 0 +#define ATTRACTOR_TYPE_BOX 1 +#define ATTRACTOR_TYPE_VECTOR_FIELD 2 + +struct Attractor { +	mat4 transform; +	vec3 extents; //exents or radius +	uint type; +	uint texture_index; //texture index for vector field +	float strength; +	float attenuation; +	float directionality; +}; + +#define MAX_COLLIDERS 32 + +#define COLLIDER_TYPE_SPHERE 0 +#define COLLIDER_TYPE_BOX 1 +#define COLLIDER_TYPE_SDF 2 +#define COLLIDER_TYPE_HEIGHT_FIELD 3 + +struct Collider { +	mat4 transform; +	vec3 extents; //exents or radius +	uint type; + +	uint texture_index; //texture index for vector field +	float scale; +	uint pad[2]; +}; + +struct FrameParams { +	bool emitting; +	float system_phase; +	float prev_system_phase; +	uint cycle; + +	float explosiveness; +	float randomness; +	float time; +	float delta; + +	uint random_seed; +	uint attractor_count; +	uint collider_count; +	float particle_size; + +	mat4 emission_transform; + +	Attractor attractors[MAX_ATTRACTORS]; +	Collider colliders[MAX_COLLIDERS]; +}; + +layout(set = 1, binding = 0, std430) restrict buffer FrameHistory { +	FrameParams data[]; +} +frame_history; + +struct ParticleData { +	mat4 xform; +	vec3 velocity; +	bool is_active; +	vec4 color; +	vec4 custom; +}; + +layout(set = 1, binding = 1, std430) restrict buffer Particles { +	ParticleData data[]; +} +particles; + +#define EMISSION_FLAG_HAS_POSITION 1 +#define EMISSION_FLAG_HAS_ROTATION_SCALE 2 +#define EMISSION_FLAG_HAS_VELOCITY 4 +#define EMISSION_FLAG_HAS_COLOR 8 +#define EMISSION_FLAG_HAS_CUSTOM 16 + +struct ParticleEmission { +	mat4 xform; +	vec3 velocity; +	uint flags; +	vec4 color; +	vec4 custom; +}; + +layout(set = 1, binding = 2, std430) restrict buffer SourceEmission { +	int particle_count; +	uint pad0; +	uint pad1; +	uint pad2; +	ParticleEmission data[]; +} +src_particles; + +layout(set = 1, binding = 3, std430) restrict buffer DestEmission { +	int particle_count; +	int particle_max; +	uint pad1; +	uint pad2; +	ParticleEmission data[]; +} +dst_particles; + +/* SET 2: COLLIDER/ATTRACTOR TEXTURES */ + +#define MAX_3D_TEXTURES 7 + +layout(set = 2, binding = 0) uniform texture3D sdf_vec_textures[MAX_3D_TEXTURES]; +layout(set = 2, binding = 1) uniform texture2D height_field_texture; + +/* SET 3: MATERIAL */ + +#ifdef USE_MATERIAL_UNIFORMS +layout(set = 3, binding = 0, std140) uniform MaterialUniforms{ +	/* clang-format off */ +MATERIAL_UNIFORMS +	/* clang-format on */ +} material; +#endif + +layout(push_constant, binding = 0, std430) uniform Params { +	float lifetime; +	bool clear; +	uint total_particles; +	uint trail_size; +	bool use_fractional_delta; +	bool sub_emitter_mode; +	bool can_emit; +	uint pad; +} +params; + +uint hash(uint x) { +	x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); +	x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); +	x = (x >> uint(16)) ^ x; +	return x; +} + +bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) { +	if (!params.can_emit) { +		return false; +	} + +	bool valid = false; + +	int dst_index = atomicAdd(dst_particles.particle_count, 1); + +	if (dst_index >= dst_particles.particle_max) { +		atomicAdd(dst_particles.particle_count, -1); +		return false; +	} + +	dst_particles.data[dst_index].xform = p_xform; +	dst_particles.data[dst_index].velocity = p_velocity; +	dst_particles.data[dst_index].color = p_color; +	dst_particles.data[dst_index].custom = p_custom; +	dst_particles.data[dst_index].flags = p_flags; + +	return true; +} + +/* clang-format off */ + +COMPUTE_SHADER_GLOBALS + +/* clang-format on */ + +void main() { +	uint particle = gl_GlobalInvocationID.x; + +	if (particle >= params.total_particles * params.trail_size) { +		return; //discard +	} + +	uint index = particle / params.trail_size; +	uint frame = (particle % params.trail_size); + +#define FRAME frame_history.data[frame] +#define PARTICLE particles.data[particle] + +	bool apply_forces = true; +	bool apply_velocity = true; +	float local_delta = FRAME.delta; + +	float mass = 1.0; + +	bool restart = false; + +	bool restart_position = false; +	bool restart_rotation_scale = false; +	bool restart_velocity = false; +	bool restart_color = false; +	bool restart_custom = false; + +	if (params.clear) { +		PARTICLE.color = vec4(1.0); +		PARTICLE.custom = vec4(0.0); +		PARTICLE.velocity = vec3(0.0); +		PARTICLE.is_active = false; +		PARTICLE.xform = mat4( +				vec4(1.0, 0.0, 0.0, 0.0), +				vec4(0.0, 1.0, 0.0, 0.0), +				vec4(0.0, 0.0, 1.0, 0.0), +				vec4(0.0, 0.0, 0.0, 1.0)); +	} + +	bool collided = false; +	vec3 collision_normal = vec3(0.0); +	float collision_depth = 0.0; + +	vec3 attractor_force = vec3(0.0); + +#if !defined(DISABLE_VELOCITY) + +	if (PARTICLE.is_active) { +		PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta; +	} +#endif + +	/* Process physics if active */ + +	if (PARTICLE.is_active) { +		for (uint i = 0; i < FRAME.attractor_count; i++) { +			vec3 dir; +			float amount; +			vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.attractors[i].transform[3].xyz; +			vec3 local_pos = rel_vec * mat3(FRAME.attractors[i].transform); + +			switch (FRAME.attractors[i].type) { +				case ATTRACTOR_TYPE_SPHERE: { +					dir = normalize(rel_vec); +					float d = length(local_pos) / FRAME.attractors[i].extents.x; +					if (d > 1.0) { +						continue; +					} +					amount = max(0.0, 1.0 - d); +				} break; +				case ATTRACTOR_TYPE_BOX: { +					dir = normalize(rel_vec); + +					vec3 abs_pos = abs(local_pos / FRAME.attractors[i].extents); +					float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z)); +					if (d > 1.0) { +						continue; +					} +					amount = max(0.0, 1.0 - d); + +				} break; +				case ATTRACTOR_TYPE_VECTOR_FIELD: { +					vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents) * 2.0 - 1.0; +					if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) { +						continue; +					} +					vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz; +					dir = mat3(FRAME.attractors[i].transform) * normalize(s); //revert direction +					amount = length(s); + +				} break; +			} +			amount = pow(amount, FRAME.attractors[i].attenuation); +			dir = normalize(mix(dir, FRAME.attractors[i].transform[2].xyz, FRAME.attractors[i].directionality)); +			attractor_force -= amount * dir * FRAME.attractors[i].strength; +		} + +		float particle_size = FRAME.particle_size; + +#ifdef USE_COLLISON_SCALE + +		particle_size *= dot(vec3(length(PARTICLE.xform[0].xyz), length(PARTICLE.xform[1].xyz), length(PARTICLE.xform[2].xyz)), vec3(0.33333333333)); + +#endif + +		for (uint i = 0; i < FRAME.collider_count; i++) { +			vec3 normal; +			float depth; +			bool col = false; + +			vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz; +			vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform); + +			switch (FRAME.colliders[i].type) { +				case COLLIDER_TYPE_SPHERE: { +					float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x); + +					if (d < 0.0) { +						col = true; +						depth = -d; +						normal = normalize(rel_vec); +					} + +				} break; +				case COLLIDER_TYPE_BOX: { +					vec3 abs_pos = abs(local_pos); +					vec3 sgn_pos = sign(local_pos); + +					if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) { +						//point outside box + +						vec3 closest = min(abs_pos, FRAME.colliders[i].extents); +						vec3 rel = abs_pos - closest; +						depth = length(rel) - particle_size; +						if (depth < 0.0) { +							col = true; +							normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos); +							depth = -depth; +						} +					} else { +						//point inside box +						vec3 axis_len = FRAME.colliders[i].extents - abs_pos; +						// there has to be a faster way to do this? +						if (all(lessThan(axis_len.xx, axis_len.yz))) { +							normal = vec3(1, 0, 0); +						} else if (all(lessThan(axis_len.yy, axis_len.xz))) { +							normal = vec3(0, 1, 0); +						} else { +							normal = vec3(0, 0, 1); +						} + +						col = true; +						depth = dot(normal * axis_len, vec3(1)) + particle_size; +						normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos); +					} + +				} break; +				case COLLIDER_TYPE_SDF: { +					vec3 apos = abs(local_pos); +					float extra_dist = 0.0; +					if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside +						vec3 mpos = min(apos, FRAME.colliders[i].extents); +						extra_dist = distance(mpos, apos); +					} + +					if (extra_dist > particle_size) { +						continue; +					} + +					vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5; +					float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r; +					s *= FRAME.colliders[i].scale; +					s += extra_dist; +					if (s < particle_size) { +						col = true; +						depth = particle_size - s; +						const float EPSILON = 0.001; +						normal = mat3(FRAME.colliders[i].transform) * +								 normalize( +										 vec3( +												 texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r, +												 texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r, +												 texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r)); +					} + +				} break; +				case COLLIDER_TYPE_HEIGHT_FIELD: { +					vec3 local_pos_bottom = local_pos; +					local_pos_bottom.y -= particle_size; + +					if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) { +						continue; +					} + +					const float DELTA = 1.0 / 8192.0; + +					vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5; + +					float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r; + +					if (y > uvw_pos.y) { +						//inside heightfield + +						vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; +						vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; +						vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents; + +						normal = normalize(cross(pos1 - pos2, pos1 - pos3)); +						float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y; + +						col = true; +						depth = dot(normal, pos1) - dot(normal, local_pos_bottom); +					} + +				} break; +			} + +			if (col) { +				if (!collided) { +					collided = true; +					collision_normal = normal; +					collision_depth = depth; +				} else { +					vec3 c = collision_normal * collision_depth; +					c += normal * max(0.0, depth - dot(normal, c)); +					collision_normal = normalize(c); +					collision_depth = length(c); +				} +			} +		} +	} + +	if (params.sub_emitter_mode) { +		if (!PARTICLE.is_active) { +			int src_index = atomicAdd(src_particles.particle_count, -1) - 1; + +			if (src_index >= 0) { +				PARTICLE.is_active = true; +				restart = true; + +				if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) { +					PARTICLE.xform[3] = src_particles.data[src_index].xform[3]; +				} else { +					PARTICLE.xform[3] = vec4(0, 0, 0, 1); +					restart_position = true; +				} +				if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) { +					PARTICLE.xform[0] = src_particles.data[src_index].xform[0]; +					PARTICLE.xform[1] = src_particles.data[src_index].xform[1]; +					PARTICLE.xform[2] = src_particles.data[src_index].xform[2]; +				} else { +					PARTICLE.xform[0] = vec4(1, 0, 0, 0); +					PARTICLE.xform[1] = vec4(0, 1, 0, 0); +					PARTICLE.xform[2] = vec4(0, 0, 1, 0); +					restart_rotation_scale = true; +				} +				if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) { +					PARTICLE.velocity = src_particles.data[src_index].velocity; +				} else { +					PARTICLE.velocity = vec3(0); +					restart_velocity = true; +				} +				if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) { +					PARTICLE.color = src_particles.data[src_index].color; +				} else { +					PARTICLE.color = vec4(1); +					restart_color = true; +				} + +				if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) { +					PARTICLE.custom = src_particles.data[src_index].custom; +				} else { +					PARTICLE.custom = vec4(0); +					restart_custom = true; +				} +			} +		} + +	} else if (FRAME.emitting) { +		float restart_phase = float(index) / float(params.total_particles); + +		if (FRAME.randomness > 0.0) { +			uint seed = FRAME.cycle; +			if (restart_phase >= FRAME.system_phase) { +				seed -= uint(1); +			} +			seed *= uint(params.total_particles); +			seed += uint(index); +			float random = float(hash(seed) % uint(65536)) / 65536.0; +			restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles); +		} + +		restart_phase *= (1.0 - FRAME.explosiveness); + +		if (FRAME.system_phase > FRAME.prev_system_phase) { +			// restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed + +			if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) { +				restart = true; +				if (params.use_fractional_delta) { +					local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; +				} +			} + +		} else if (FRAME.delta > 0.0) { +			if (restart_phase >= FRAME.prev_system_phase) { +				restart = true; +				if (params.use_fractional_delta) { +					local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime; +				} + +			} else if (restart_phase < FRAME.system_phase) { +				restart = true; +				if (params.use_fractional_delta) { +					local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; +				} +			} +		} + +		uint current_cycle = FRAME.cycle; + +		if (FRAME.system_phase < restart_phase) { +			current_cycle -= uint(1); +		} + +		uint particle_number = current_cycle * uint(params.total_particles) + particle; + +		if (restart) { +			PARTICLE.is_active = FRAME.emitting; +			restart_position = true; +			restart_rotation_scale = true; +			restart_velocity = true; +			restart_color = true; +			restart_custom = true; +		} +	} + +	if (PARTICLE.is_active) { +		/* clang-format off */ + +COMPUTE_SHADER_CODE + +		/* clang-format on */ +	} +} diff --git a/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl b/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl new file mode 100644 index 0000000000..6c782b6045 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl @@ -0,0 +1,82 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +struct ParticleData { +	mat4 xform; +	vec3 velocity; +	bool is_active; +	vec4 color; +	vec4 custom; +}; + +layout(set = 0, binding = 1, std430) restrict readonly buffer Particles { +	ParticleData data[]; +} +particles; + +layout(set = 0, binding = 2, std430) restrict writeonly buffer Transforms { +	vec4 data[]; +} +instances; + +#ifdef USE_SORT_BUFFER + +layout(set = 1, binding = 0, std430) restrict buffer SortBuffer { +	vec2 data[]; +} +sort_buffer; + +#endif // USE_SORT_BUFFER + +layout(push_constant, binding = 0, std430) uniform Params { +	vec3 sort_direction; +	uint total_particles; +} +params; + +void main() { +#ifdef MODE_FILL_SORT_BUFFER + +	uint particle = gl_GlobalInvocationID.x; +	if (particle >= params.total_particles) { +		return; //discard +	} + +	sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[particle].xform[3].xyz); +	sort_buffer.data[particle].y = float(particle); +#endif + +#ifdef MODE_FILL_INSTANCES + +	uint particle = gl_GlobalInvocationID.x; +	uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom + +	if (particle >= params.total_particles) { +		return; //discard +	} + +#ifdef USE_SORT_BUFFER +	particle = uint(sort_buffer.data[particle].y); //use index from sort buffer +#endif + +	mat4 txform; + +	if (particles.data[particle].is_active) { +		txform = transpose(particles.data[particle].xform); +	} else { +		txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible +	} + +	instances.data[write_offset + 0] = txform[0]; +	instances.data[write_offset + 1] = txform[1]; +	instances.data[write_offset + 2] = txform[2]; +	instances.data[write_offset + 3] = particles.data[particle].color; +	instances.data[write_offset + 4] = particles.data[particle].custom; + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 792a1aa05f..da3c60af04 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -361,6 +361,65 @@ layout(location = 0) out vec4 frag_color;  #endif // RENDER DEPTH +#ifdef ALPHA_HASH_USED + +float hash_2d(vec2 p) { +	return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * +				 (0.1 + abs(sin(13.0 * p.y + p.x)))); +} + +float hash_3d(vec3 p) { +	return hash_2d(vec2(hash_2d(p.xy), p.z)); +} + +float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { +	vec3 dx = dFdx(pos); +	vec3 dy = dFdx(pos); +	float delta_max_sqr = max(length(dx), length(dy)); +	float pix_scale = 1.0 / (hash_scale * delta_max_sqr); + +	vec2 pix_scales = +			vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale)))); + +	vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)), +			hash_3d(floor(pix_scales.y * pos.xyz))); + +	float lerp_factor = fract(log2(pix_scale)); + +	float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y; + +	float min_lerp = min(lerp_factor, 1.0 - lerp_factor); + +	vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), +			(a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), +			1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / +						  (2.0 * min_lerp * (1.0 - min_lerp)))); + +	float alpha_hash_threshold = +			(lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; + +	return clamp(alpha_hash_threshold, 0.0, 1.0); +} + +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + +float calc_mip_level(vec2 texture_coord) { +	vec2 dx = dFdx(texture_coord); +	vec2 dy = dFdy(texture_coord); +	float delta_max_sqr = max(dot(dx, dx), dot(dy, dy)); +	return max(0.0, 0.5 * log2(delta_max_sqr)); +} + +float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) { +	input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number +	input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5; +	return clamp(input_alpha, 0.0, 1.0); +} + +#endif // ALPHA_ANTIALIASING_USED +  // This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.  // We're dividing this factor off because the overall term we'll end up looks like  // (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): @@ -681,9 +740,13 @@ LIGHT_SHADER_CODE  #ifndef USE_NO_SHADOWS -// Produces cheap but low-quality white noise, nothing special +// Produces cheap white noise, optimized for window-space +// Comes from: https://www.shadertoy.com/view/4djSRW +// Copyright: Dave Hoskins, MIT License  float quick_hash(vec2 pos) { -	return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237); +	vec3 p3 = fract(vec3(pos.xyx) * .1031); +	p3 += dot(p3, p3.yzx + 33.33); +	return fract((p3.x + p3.y) * p3.z);  }  float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { @@ -1237,7 +1300,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v  			float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;  			//reconstruct depth -			shadow_z / lights.data[idx].inv_radius; +			shadow_z /= lights.data[idx].inv_radius;  			//distance to light plane  			float z = dot(spot_dir, -light_rel_vec);  			transmittance_z = z - shadow_z; @@ -1601,6 +1664,67 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal  #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +#ifndef MODE_RENDER_DEPTH + +vec4 volumetric_fog_process(vec2 screen_uv, float z) { +	vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length); +	if (fog_pos.z < 0.0) { +		return vec4(0.0); +	} else if (fog_pos.z < 1.0) { +		fog_pos.z = pow(fog_pos.z, scene_data.volumetric_fog_detail_spread); +	} + +	return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); +} + +vec4 fog_process(vec3 vertex) { +	vec3 fog_color = scene_data.fog_light_color; + +	if (scene_data.fog_aerial_perspective > 0.0) { +		vec3 sky_fog_color = vec3(0.0); +		vec3 cube_view = scene_data.radiance_inverse_xform * vertex; +		// mip_level always reads from the second mipmap and higher so the fog is always slightly blurred +		float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)); +#ifdef USE_RADIANCE_CUBEMAP_ARRAY +		float lod, blend; +		blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); +		sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb; +		sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend); +#else +		sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY +		fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective); +	} + +	if (scene_data.fog_sun_scatter > 0.001) { +		vec4 sun_scatter = vec4(0.0); +		float sun_total = 0.0; +		vec3 view = normalize(vertex); + +		for (uint i = 0; i < scene_data.directional_light_count; i++) { +			vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy; +			float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0); +			fog_color += light_color * light_amount * scene_data.fog_sun_scatter; +		} +	} + +	float fog_amount = 1.0 - exp(vertex.z * scene_data.fog_density); + +	if (abs(scene_data.fog_height_density) > 0.001) { +		float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y; + +		float y_dist = scene_data.fog_height - y; + +		float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0); + +		fog_amount = max(vfog_amount, fog_amount); +	} + +	return vec4(fog_color, fog_amount); +} + +#endif +  void main() {  #ifdef MODE_DUAL_PARABOLOID @@ -1627,6 +1751,15 @@ void main() {  	float clearcoat_gloss = 0.0;  	float anisotropy = 0.0;  	vec2 anisotropy_flow = vec2(1.0, 0.0); +#if defined(CUSTOM_FOG_USED) +	vec4 custom_fog = vec4(0.0); +#endif +#if defined(CUSTOM_RADIANCE_USED) +	vec4 custom_radiance = vec4(0.0); +#endif +#if defined(CUSTOM_IRRADIANCE_USED) +	vec4 custom_irradiance = vec4(0.0); +#endif  #if defined(AO_USED)  	float ao = 1.0; @@ -1635,10 +1768,6 @@ void main() {  	float alpha = 1.0; -#if defined(ALPHA_SCISSOR_USED) -	float alpha_scissor = 0.5; -#endif -  #if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)  	vec3 binormal = normalize(binormal_interp);  	vec3 tangent = normalize(tangent_interp); @@ -1675,6 +1804,19 @@ void main() {  	float sss_strength = 0.0; +#ifdef ALPHA_SCISSOR_USED +	float alpha_scissor_threshold = 1.0; +#endif // ALPHA_SCISSOR_USED + +#ifdef ALPHA_HASH_USED +	float alpha_hash_scale = 1.0; +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED +	float alpha_antialiasing_edge = 0.0; +	vec2 alpha_texture_coordinate = vec2(0.0, 0.0); +#endif // ALPHA_ANTIALIASING_EDGE_USED +  	{  		/* clang-format off */ @@ -1683,7 +1825,7 @@ FRAGMENT_SHADER_CODE  		/* clang-format on */  	} -#if defined(LIGHT_TRANSMITTANCE_USED) +#ifdef LIGHT_TRANSMITTANCE_USED  #ifdef SSS_MODE_SKIN  	transmittance_color.a = sss_strength;  #else @@ -1691,25 +1833,43 @@ FRAGMENT_SHADER_CODE  #endif  #endif -#if !defined(USE_SHADOW_TO_OPACITY) +#ifndef USE_SHADOW_TO_OPACITY -#if defined(ALPHA_SCISSOR_USED) -	if (alpha < alpha_scissor) { +#ifdef ALPHA_SCISSOR_USED +	if (alpha < alpha_scissor_threshold) {  		discard;  	}  #endif // ALPHA_SCISSOR_USED -#ifdef USE_OPAQUE_PREPASS +// alpha hash can be used in unison with alpha antialiasing +#ifdef ALPHA_HASH_USED +	if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) { +		discard; +	} +#endif // ALPHA_HASH_USED +// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash +#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) +	alpha = 1.0; +#endif + +#ifdef ALPHA_ANTIALIASING_EDGE_USED +// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather +#ifdef ALPHA_SCISSOR_USED +	alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0); +#endif +	alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge); +#endif // ALPHA_ANTIALIASING_EDGE_USED + +#ifdef USE_OPAQUE_PREPASS  	if (alpha < opaque_prepass_threshold) {  		discard;  	} -  #endif // USE_OPAQUE_PREPASS  #endif // !USE_SHADOW_TO_OPACITY -#if defined(NORMALMAP_USED) +#ifdef NORMALMAP_USED  	normalmap.xy = normalmap.xy * 2.0 - 1.0;  	normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. @@ -1718,7 +1878,7 @@ FRAGMENT_SHADER_CODE  #endif -#if defined(LIGHT_ANISOTROPY_USED) +#ifdef LIGHT_ANISOTROPY_USED  	if (anisotropy > 0.01) {  		//rotation matrix @@ -1844,6 +2004,10 @@ FRAGMENT_SHADER_CODE  		specular_light *= scene_data.ambient_light_color_energy.a;  	} +#if defined(CUSTOM_RADIANCE_USED) +	specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); +#endif +  #ifndef USE_LIGHTMAP  	//lightmap overrides everything  	if (scene_data.use_ambient_light) { @@ -1861,7 +2025,9 @@ FRAGMENT_SHADER_CODE  		}  	}  #endif // USE_LIGHTMAP - +#if defined(CUSTOM_IRRADIANCE_USED) +	ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); +#endif  #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)  	//radiance @@ -2187,8 +2353,8 @@ FRAGMENT_SHADER_CODE  						trans_coord /= trans_coord.w;  						float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; -						shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; -						float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; +						shadow_z *= directional_lights.data[i].shadow_z_range.x; +						float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x;  						transmittance_z = z - shadow_z;  					} @@ -2219,8 +2385,8 @@ FRAGMENT_SHADER_CODE  						trans_coord /= trans_coord.w;  						float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; -						shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; -						float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; +						shadow_z *= directional_lights.data[i].shadow_z_range.y; +						float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y;  						transmittance_z = z - shadow_z;  					} @@ -2251,8 +2417,8 @@ FRAGMENT_SHADER_CODE  						trans_coord /= trans_coord.w;  						float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; -						shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; -						float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; +						shadow_z *= directional_lights.data[i].shadow_z_range.z; +						float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z;  						transmittance_z = z - shadow_z;  					} @@ -2285,8 +2451,8 @@ FRAGMENT_SHADER_CODE  						trans_coord /= trans_coord.w;  						float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; -						shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; -						float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; +						shadow_z *= directional_lights.data[i].shadow_z_range.w; +						float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w;  						transmittance_z = z - shadow_z;  					} @@ -2662,8 +2828,6 @@ FRAGMENT_SHADER_CODE  	diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point  	ambient_light *= 1.0 - metallic; -	//fog -  #ifdef MODE_MULTIPLE_RENDER_TARGETS  #ifdef MODE_UNSHADED @@ -2679,16 +2843,48 @@ FRAGMENT_SHADER_CODE  	specular_buffer = vec4(specular_light, metallic);  #endif +	// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. +	if (scene_data.fog_enabled) { +		vec4 fog = fog_process(vertex); +		diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); +		specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); +	} + +	if (scene_data.volumetric_fog_enabled) { +		vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); +		diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); +		specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); +	} + +#if defined(CUSTOM_FOG_USED) +	diffuse_buffer.rgb = mix(diffuse_buffer.rgb, custom_fog.rgb, custom_fog.a); +	specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), custom_fog.a); +#endif //CUSTOM_FOG_USED +  #else //MODE_MULTIPLE_RENDER_TARGETS  #ifdef MODE_UNSHADED  	frag_color = vec4(albedo, alpha);  #else  	frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); -	//frag_color = vec4(1.0);;; - +	//frag_color = vec4(1.0);  #endif //USE_NO_SHADING +	// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. +	if (scene_data.fog_enabled) { +		vec4 fog = fog_process(vertex); +		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); +	} + +	if (scene_data.volumetric_fog_enabled) { +		vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); +		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); +	} + +#if defined(CUSTOM_FOG_USED) +	frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); +#endif //CUSTOM_FOG_USED +  #endif //MODE_MULTIPLE_RENDER_TARGETS  #endif //MODE_RENDER_DEPTH diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl index c4dc7bd675..e29a490ca1 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl @@ -3,6 +3,8 @@  #define MAX_GI_PROBES 8 +#include "cluster_data_inc.glsl" +  layout(push_constant, binding = 0, std430) uniform DrawCall {  	uint instance_index;  	uint pad; //16 bits minimum size @@ -41,12 +43,6 @@ layout(set = 0, binding = 3, std140) uniform SceneData {  	vec2 viewport_size;  	vec2 screen_pixel_size; -	float time; -	float reflection_multiplier; // one normally, zero when rendering reflections - -	bool pancake_shadows; -	uint pad; -  	//use vec4s because std140 doesnt play nice with vec2s, z and w are wasted  	vec4 directional_penumbra_shadow_kernel[32];  	vec4 directional_soft_shadow_kernel[32]; @@ -94,40 +90,25 @@ layout(set = 0, binding = 3, std140) uniform SceneData {  	ivec3 sdf_size;  	bool gi_upscale_for_msaa; -#if 0 -	vec4 ambient_light_color; -	vec4 bg_color; +	bool volumetric_fog_enabled; +	float volumetric_fog_inv_length; +	float volumetric_fog_detail_spread; +	uint volumetric_fog_pad; -	vec4 fog_color_enabled; -	vec4 fog_sun_color_amount; - -	float ambient_energy; -	float bg_energy; -#endif +	bool fog_enabled; +	float fog_density; +	float fog_height; +	float fog_height_density; -#if 0 -	vec2 shadow_atlas_pixel_size; -	vec2 directional_shadow_pixel_size; +	vec3 fog_light_color; +	float fog_sun_scatter; -	float z_far; +	float fog_aerial_perspective; -	float subsurface_scatter_width; -	float ambient_occlusion_affect_light; -	float ambient_occlusion_affect_ao_channel; -	float opaque_prepass_threshold; +	float time; +	float reflection_multiplier; // one normally, zero when rendering reflections -	bool fog_depth_enabled; -	float fog_depth_begin; -	float fog_depth_end; -	float fog_density; -	float fog_depth_curve; -	bool fog_transmit_enabled; -	float fog_transmit_curve; -	bool fog_height_enabled; -	float fog_height_min; -	float fog_height_max; -	float fog_height_curve; -#endif +	bool pancake_shadows;  }  scene_data; @@ -163,86 +144,16 @@ layout(set = 0, binding = 4, std430) restrict readonly buffer Instances {  }  instances; -struct LightData { //this structure needs to be as packed as possible -	vec3 position; -	float inv_radius; -	vec3 direction; -	float size; -	uint attenuation_energy; //attenuation -	uint color_specular; //rgb color, a specular (8 bit unorm) -	uint cone_attenuation_angle; // attenuation and angle, (16bit float) -	uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) -	vec4 atlas_rect; // rect in the shadow atlas -	mat4 shadow_matrix; -	float shadow_bias; -	float shadow_normal_bias; -	float transmittance_bias; -	float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle -	float soft_shadow_scale; // scales the shadow kernel for blurrier shadows -	uint mask; -	uint pad[2]; -	vec4 projector_rect; //projector rect in srgb decal atlas -}; -  layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {  	LightData data[];  }  lights; -#define REFLECTION_AMBIENT_DISABLED 0 -#define REFLECTION_AMBIENT_ENVIRONMENT 1 -#define REFLECTION_AMBIENT_COLOR 2 - -struct ReflectionData { -	vec3 box_extents; -	float index; -	vec3 box_offset; -	uint mask; -	vec4 params; // intensity, 0, interior , boxproject -	vec3 ambient; // ambient color -	uint ambient_mode; -	mat4 local_matrix; // up to here for spot and omni, rest is for directional -	// notes: for ambientblend, use distance to edge to blend between already existing global environment -}; -  layout(set = 0, binding = 6) buffer restrict readonly ReflectionProbeData {  	ReflectionData data[];  }  reflections; -struct DirectionalLightData { -	vec3 direction; -	float energy; -	vec3 color; -	float size; -	float specular; -	uint mask; -	float softshadow_angle; -	float soft_shadow_scale; -	bool blend_splits; -	bool shadow_enabled; -	float fade_from; -	float fade_to; -	vec4 shadow_bias; -	vec4 shadow_normal_bias; -	vec4 shadow_transmittance_bias; -	vec4 shadow_transmittance_z_scale; -	vec4 shadow_range_begin; -	vec4 shadow_split_offsets; -	mat4 shadow_matrix1; -	mat4 shadow_matrix2; -	mat4 shadow_matrix3; -	mat4 shadow_matrix4; -	vec4 shadow_color1; -	vec4 shadow_color2; -	vec4 shadow_color3; -	vec4 shadow_color4; -	vec2 uv_scale1; -	vec2 uv_scale2; -	vec2 uv_scale3; -	vec2 uv_scale4; -}; -  layout(set = 0, binding = 7, std140) uniform DirectionalLights {  	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];  } @@ -271,31 +182,9 @@ layout(set = 0, binding = 12, std140) restrict readonly buffer LightmapCaptures  }  lightmap_captures; -#define CLUSTER_COUNTER_SHIFT 20 -#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1) -#define CLUSTER_COUNTER_MASK 0xfff -  layout(set = 0, binding = 13) uniform texture2D decal_atlas;  layout(set = 0, binding = 14) uniform texture2D decal_atlas_srgb; -struct DecalData { -	mat4 xform; //to decal transform -	vec3 inv_extents; -	float albedo_mix; -	vec4 albedo_rect; -	vec4 normal_rect; -	vec4 orm_rect; -	vec4 emission_rect; -	vec4 modulate; -	float emission_energy; -	uint mask; -	float upper_fade; -	float lower_fade; -	mat3x4 normal_xform; -	vec3 normal; -	float normal_fade; -}; -  layout(set = 0, binding = 15, std430) restrict readonly buffer Decals {  	DecalData data[];  } @@ -364,7 +253,7 @@ layout(set = 1, binding = 0) uniform textureCube radiance_cubemap;  #endif -/* Set 2, Reflection and Shadow Atlases (view dependant) */ +/* Set 2, Reflection and Shadow Atlases (view dependent) */  layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas; @@ -394,9 +283,7 @@ layout(set = 3, binding = 2) uniform texture2D normal_roughness_buffer;  layout(set = 3, binding = 4) uniform texture2D ao_buffer;  layout(set = 3, binding = 5) uniform texture2D ambient_buffer;  layout(set = 3, binding = 6) uniform texture2D reflection_buffer; -  layout(set = 3, binding = 7) uniform texture2DArray sdfgi_lightprobe_texture; -  layout(set = 3, binding = 8) uniform texture3D sdfgi_occlusion_cascades;  struct GIProbeData { @@ -412,7 +299,7 @@ struct GIProbeData {  	float anisotropy_strength;  	float ambient_occlusion;  	float ambient_occlusion_size; -	uint pad2; +	uint mipmaps;  };  layout(set = 3, binding = 9, std140) uniform GIProbes { @@ -420,6 +307,8 @@ layout(set = 3, binding = 9, std140) uniform GIProbes {  }  gi_probes; +layout(set = 3, binding = 10) uniform texture3D volumetric_fog_texture; +  #endif  /* Set 4 Skeleton & Instancing (Multimesh) */ diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl index a8ee33a664..06dc4b13de 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl @@ -155,18 +155,14 @@ void main() {  		depth = imageLoad(source_depth, ivec2(pos - 0.5)).r; -		if (-depth >= params.camera_z_far) { //went beyond camera -			break; -		} -  		z_from = z_to;  		z_to = z / w;  		if (depth > z_to) {  			// if depth was surpassed -			if (depth <= max(z_to, z_from) + params.depth_tolerance) { -				// check the depth tolerance -				//check that normal is valid +			if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far) { +				// check the depth tolerance and far clip +				// check that normal is valid  				found = true;  			}  			break; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl index c4b29216d5..61e4bf5e18 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl @@ -22,7 +22,7 @@ dispatch_data;  struct ProcessVoxel {  	uint position; //xyz 7 bit packed, extra 11 bits for neigbours  	uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours -	uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous +	uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours  	uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours  	//total neighbours: 26  }; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl index e4779aafaf..d516ab22c3 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl @@ -37,6 +37,8 @@ layout(rgba32i, set = 0, binding = 12) uniform restrict iimage2D lightprobe_aver  layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_average_parent_texture; +layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture; +  layout(set = 1, binding = 0) uniform textureCube sky_irradiance;  layout(set = 1, binding = 1) uniform sampler linear_sampler_mipmaps; @@ -68,6 +70,9 @@ layout(push_constant, binding = 0, std430) uniform Params {  	vec3 sky_color;  	float y_mult; + +	bool store_ambient_texture; +	uint pad[3];  }  params; @@ -319,12 +324,19 @@ void main() {  		imageStore(lightprobe_history_texture, prev_pos, ivalue);  		imageStore(lightprobe_average_texture, average_pos, average); + +		if (params.store_ambient_texture && i == 0) { +			ivec3 ambient_pos = ivec3(pos, int(params.cascade)); +			vec4 ambient_light = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS); +			ambient_light *= 0.88622; // SHL0 +			imageStore(lightprobe_ambient_texture, ambient_pos, ambient_light); +		}  	}  #endif // MODE PROCESS  #ifdef MODE_STORE -	// converting to octahedral in this step is requiered because +	// converting to octahedral in this step is required because  	// octahedral is much faster to read from the screen than spherical harmonics,  	// despite the very slight quality loss @@ -500,7 +512,7 @@ void main() {  			imageStore(lightprobe_average_scroll_texture, dst_pos, value);  		}  	} else if (params.cascade < params.max_cascades - 1) { -		//cant scroll, must look for position in parent cascade +		//can't scroll, must look for position in parent cascade  		//to global coords  		float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl index d7d19897e3..916c60ac89 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl @@ -103,7 +103,7 @@ dispatch_data;  struct ProcessVoxel {  	uint position; //xyz 7 bit packed, extra 11 bits for neigbours  	uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours -	uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous +	uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours  	uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours  	//total neighbours: 26  }; @@ -136,7 +136,7 @@ dispatch_data;  struct ProcessVoxel {  	uint position; //xyz 7 bit packed, extra 11 bits for neigbours  	uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours -	uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous +	uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours  	uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours  	//total neighbours: 26  }; @@ -274,7 +274,7 @@ void main() {  #ifdef MODE_JUMPFLOOD -	//regular jumpflood, efficent for large steps, inefficient for small steps +	//regular jumpflood, efficient for large steps, inefficient for small steps  	ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);  	vec3 posf = vec3(pos); @@ -338,7 +338,7 @@ void main() {  			continue; //was not initialized yet, ignore  		} -		float q_dist = distance(posf, vec3(p.xyz)); +		float q_dist = distance(posf, vec3(q.xyz));  		if (p.w == 0 || q_dist < p_dist) {  			p = q; //just replace because current is unused  			p_dist = q_dist; diff --git a/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl b/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl new file mode 100644 index 0000000000..29443ae7db --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl @@ -0,0 +1,105 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +#define BLOCK_SIZE 8 + +layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in; + +#ifdef MODE_REDUCE + +shared float tmp_data[BLOCK_SIZE * BLOCK_SIZE]; +const uint swizzle_table[BLOCK_SIZE] = uint[](0, 4, 2, 6, 1, 5, 3, 7); +const uint unswizzle_table[BLOCK_SIZE] = uint[](0, 0, 0, 1, 0, 2, 1, 3); + +#endif + +layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D source_depth; +layout(r32f, set = 0, binding = 1) uniform restrict writeonly image2D dst_depth; + +layout(push_constant, binding = 1, std430) uniform Params { +	ivec2 source_size; +	ivec2 source_offset; +	uint min_size; +	uint gaussian_kernel_version; +	ivec2 filter_dir; +} +params; + +void main() { +#ifdef MODE_REDUCE + +	uvec2 pos = gl_LocalInvocationID.xy; + +	ivec2 image_offset = params.source_offset; +	ivec2 image_pos = image_offset + ivec2(gl_GlobalInvocationID.xy); +	uint dst_t = swizzle_table[pos.y] * BLOCK_SIZE + swizzle_table[pos.x]; +	tmp_data[dst_t] = imageLoad(source_depth, min(image_pos, params.source_size - ivec2(1))).r; +	ivec2 image_size = params.source_size; + +	uint t = pos.y * BLOCK_SIZE + pos.x; + +	//neighbours +	uint size = BLOCK_SIZE; + +	do { +		groupMemoryBarrier(); +		barrier(); + +		size >>= 1; +		image_size >>= 1; +		image_offset >>= 1; + +		if (all(lessThan(pos, uvec2(size)))) { +			uint nx = t + size; +			uint ny = t + (BLOCK_SIZE * size); +			uint nxy = ny + size; + +			tmp_data[t] += tmp_data[nx]; +			tmp_data[t] += tmp_data[ny]; +			tmp_data[t] += tmp_data[nxy]; +			tmp_data[t] /= 4.0; +		} + +	} while (size > params.min_size); + +	if (all(lessThan(pos, uvec2(size)))) { +		image_pos = ivec2(unswizzle_table[size + pos.x], unswizzle_table[size + pos.y]); +		image_pos += image_offset + ivec2(gl_WorkGroupID.xy) * int(size); + +		image_size = max(ivec2(1), image_size); //in case image size became 0 + +		if (all(lessThan(image_pos, uvec2(image_size)))) { +			imageStore(dst_depth, image_pos, vec4(tmp_data[t])); +		} +	} +#endif + +#ifdef MODE_FILTER + +	ivec2 image_pos = params.source_offset + ivec2(gl_GlobalInvocationID.xy); +	if (any(greaterThanEqual(image_pos, params.source_size))) { +		return; +	} + +	ivec2 clamp_min = ivec2(params.source_offset); +	ivec2 clamp_max = ivec2(params.source_size) - 1; + +	//gaussian kernel, size 9, sigma 4 +	const int kernel_size = 9; +	const float gaussian_kernel[kernel_size * 3] = float[]( +			0.000229, 0.005977, 0.060598, 0.241732, 0.382928, 0.241732, 0.060598, 0.005977, 0.000229, +			0.028532, 0.067234, 0.124009, 0.179044, 0.20236, 0.179044, 0.124009, 0.067234, 0.028532, +			0.081812, 0.101701, 0.118804, 0.130417, 0.134535, 0.130417, 0.118804, 0.101701, 0.081812); +	float accum = 0.0; +	for (int i = 0; i < kernel_size; i++) { +		ivec2 ofs = clamp(image_pos + params.filter_dir * (i - kernel_size / 2), clamp_min, clamp_max); +		accum += imageLoad(source_depth, ofs).r * gaussian_kernel[params.gaussian_kernel_version + i]; +	} + +	imageStore(dst_depth, image_pos, vec4(accum)); + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl index 9c59be6841..6c985e1f5c 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl @@ -58,6 +58,36 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData  }  global_variables; +layout(set = 0, binding = 2, std140) uniform SceneData { +	bool volumetric_fog_enabled; +	float volumetric_fog_inv_length; +	float volumetric_fog_detail_spread; + +	float fog_aerial_perspective; + +	vec3 fog_light_color; +	float fog_sun_scatter; + +	bool fog_enabled; +	float fog_density; + +	float z_far; +	uint directional_light_count; +} +scene_data; + +struct DirectionalLightData { +	vec4 direction_energy; +	vec4 color_size; +	bool enabled; +}; + +layout(set = 0, binding = 3, std140) uniform DirectionalLights { +	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} + +directional_lights; +  #ifdef USE_MATERIAL_UNIFORMS  layout(set = 1, binding = 0, std140) uniform MaterialUniforms{  	/* clang-format off */ @@ -77,6 +107,8 @@ layout(set = 2, binding = 1) uniform texture2D half_res;  layout(set = 2, binding = 2) uniform texture2D quarter_res;  #endif +layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture; +  #ifdef USE_CUBEMAP_PASS  #define AT_CUBEMAP_PASS true  #else @@ -95,18 +127,6 @@ layout(set = 2, binding = 2) uniform texture2D quarter_res;  #define AT_QUARTER_RES_PASS false  #endif -struct DirectionalLightData { -	vec4 direction_energy; -	vec4 color_size; -	bool enabled; -}; - -layout(set = 3, binding = 0, std140) uniform DirectionalLights { -	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; -} - -directional_lights; -  /* clang-format off */  FRAGMENT_SHADER_GLOBALS @@ -115,6 +135,30 @@ FRAGMENT_SHADER_GLOBALS  layout(location = 0) out vec4 frag_color; +vec4 volumetric_fog_process(vec2 screen_uv) { +	vec3 fog_pos = vec3(screen_uv, 1.0); + +	return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); +} + +vec4 fog_process(vec3 view, vec3 sky_color) { +	vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective); + +	if (scene_data.fog_sun_scatter > 0.001) { +		vec4 sun_scatter = vec4(0.0); +		float sun_total = 0.0; +		for (uint i = 0; i < scene_data.directional_light_count; i++) { +			vec3 light_color = directional_lights.data[i].color_size.xyz * directional_lights.data[i].direction_energy.w; +			float light_amount = pow(max(dot(view, directional_lights.data[i].direction_energy.xyz), 0.0), 8.0); +			fog_color += light_color * light_amount * scene_data.fog_sun_scatter; +		} +	} + +	float fog_amount = clamp(1.0 - exp(-scene_data.z_far * scene_data.fog_density), 0.0, 1.0); + +	return vec4(fog_color, fog_amount); +} +  void main() {  	vec3 cube_normal;  	cube_normal.z = -1.0; @@ -138,6 +182,7 @@ void main() {  	float alpha = 1.0; // Only available to subpasses  	vec4 half_res_color = vec4(1.0);  	vec4 quarter_res_color = vec4(1.0); +	vec4 custom_fog = vec4(0.0);  #ifdef USE_CUBEMAP_PASS  	vec3 inverted_cube_normal = cube_normal; @@ -178,6 +223,25 @@ FRAGMENT_SHADER_CODE  	frag_color.rgb = color * params.position_multiplier.w;  	frag_color.a = alpha; +#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS) + +	// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. +	if (scene_data.fog_enabled) { +		vec4 fog = fog_process(cube_normal, frag_color.rgb); +		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); +	} + +	if (scene_data.volumetric_fog_enabled) { +		vec4 fog = volumetric_fog_process(uv); +		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); +	} + +	if (custom_fog.a > 0.0) { +		frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); +	} + +#endif // DISABLE_FOG +  	// Blending is disabled for Sky, so alpha doesn't blend  	// alpha is used for subsurface scattering so make sure it doesn't get applied to Sky  	if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) { diff --git a/servers/rendering/rasterizer_rd/shaders/sort.glsl b/servers/rendering/rasterizer_rd/shaders/sort.glsl new file mode 100644 index 0000000000..e5ebb9c64b --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/sort.glsl @@ -0,0 +1,203 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +// Original version here: +// https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11/blob/master/gpuparticles11/src/Shaders + +// +// Copyright (c) 2016 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#define SORT_SIZE 512 +#define NUM_THREADS (SORT_SIZE / 2) +#define INVERSION (16 * 2 + 8 * 3) +#define ITERATIONS 1 + +layout(local_size_x = NUM_THREADS, local_size_y = 1, local_size_z = 1) in; + +#ifndef MODE_SORT_STEP + +shared vec2 g_LDS[SORT_SIZE]; + +#endif + +layout(set = 1, binding = 0, std430) restrict buffer SortBuffer { +	vec2 data[]; +} +sort_buffer; + +layout(push_constant, binding = 0, std430) uniform Params { +	uint total_elements; +	uint pad[3]; +	ivec4 job_params; +} +params; + +void main() { +#ifdef MODE_SORT_BLOCK + +	uvec3 Gid = gl_WorkGroupID; +	uvec3 DTid = gl_GlobalInvocationID; +	uvec3 GTid = gl_LocalInvocationID; +	uint GI = gl_LocalInvocationIndex; + +	int GlobalBaseIndex = int((Gid.x * SORT_SIZE) + GTid.x); +	int LocalBaseIndex = int(GI); +	int numElementsInThreadGroup = int(min(SORT_SIZE, params.total_elements - (Gid.x * SORT_SIZE))); + +	// Load shared data + +	int i; +	for (i = 0; i < 2 * ITERATIONS; ++i) { +		if (GI + i * NUM_THREADS < numElementsInThreadGroup) +			g_LDS[LocalBaseIndex + i * NUM_THREADS] = sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS]; +	} + +	groupMemoryBarrier(); +	barrier(); + +	// Bitonic sort +	for (int nMergeSize = 2; nMergeSize <= SORT_SIZE; nMergeSize = nMergeSize * 2) { +		for (int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1) { +			for (i = 0; i < ITERATIONS; ++i) { +				int tmp_index = int(GI + NUM_THREADS * i); +				int index_low = tmp_index & (nMergeSubSize - 1); +				int index_high = 2 * (tmp_index - index_low); +				int index = index_high + index_low; + +				int nSwapElem = nMergeSubSize == nMergeSize >> 1 ? index_high + (2 * nMergeSubSize - 1) - index_low : index_high + nMergeSubSize + index_low; +				if (nSwapElem < numElementsInThreadGroup) { +					vec2 a = g_LDS[index]; +					vec2 b = g_LDS[nSwapElem]; + +					if (a.x > b.x) { +						g_LDS[index] = b; +						g_LDS[nSwapElem] = a; +					} +				} +				groupMemoryBarrier(); +				barrier(); +			} +		} +	} + +	// Store shared data +	for (i = 0; i < 2 * ITERATIONS; ++i) { +		if (GI + i * NUM_THREADS < numElementsInThreadGroup) { +			sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS]; +		} +	} + +#endif + +#ifdef MODE_SORT_STEP + +	uvec3 Gid = gl_WorkGroupID; +	uvec3 GTid = gl_LocalInvocationID; + +	ivec4 tgp; + +	tgp.x = int(Gid.x) * 256; +	tgp.y = 0; +	tgp.z = int(params.total_elements); +	tgp.w = min(512, max(0, tgp.z - int(Gid.x) * 512)); + +	uint localID = int(tgp.x) + GTid.x; // calculate threadID within this sortable-array + +	uint index_low = localID & (params.job_params.x - 1); +	uint index_high = 2 * (localID - index_low); + +	uint index = tgp.y + index_high + index_low; +	uint nSwapElem = tgp.y + index_high + params.job_params.y + params.job_params.z * index_low; + +	if (nSwapElem < tgp.y + tgp.z) { +		vec2 a = sort_buffer.data[index]; +		vec2 b = sort_buffer.data[nSwapElem]; + +		if (a.x > b.x) { +			sort_buffer.data[index] = b; +			sort_buffer.data[nSwapElem] = a; +		} +	} + +#endif + +#ifdef MODE_SORT_INNER + +	uvec3 Gid = gl_WorkGroupID; +	uvec3 DTid = gl_GlobalInvocationID; +	uvec3 GTid = gl_LocalInvocationID; +	uint GI = gl_LocalInvocationIndex; + +	ivec4 tgp; + +	tgp.x = int(Gid.x * 256); +	tgp.y = 0; +	tgp.z = int(params.total_elements.x); +	tgp.w = int(min(512, max(0, params.total_elements - Gid.x * 512))); + +	int GlobalBaseIndex = int(tgp.y + tgp.x * 2 + GTid.x); +	int LocalBaseIndex = int(GI); +	int i; + +	// Load shared data +	for (i = 0; i < 2; ++i) { +		if (GI + i * NUM_THREADS < tgp.w) +			g_LDS[LocalBaseIndex + i * NUM_THREADS] = sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS]; +	} + +	groupMemoryBarrier(); +	barrier(); + +	// sort threadgroup shared memory +	for (int nMergeSubSize = SORT_SIZE >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1) { +		int tmp_index = int(GI); +		int index_low = tmp_index & (nMergeSubSize - 1); +		int index_high = 2 * (tmp_index - index_low); +		int index = index_high + index_low; + +		int nSwapElem = index_high + nMergeSubSize + index_low; + +		if (nSwapElem < tgp.w) { +			vec2 a = g_LDS[index]; +			vec2 b = g_LDS[nSwapElem]; + +			if (a.x > b.x) { +				g_LDS[index] = b; +				g_LDS[nSwapElem] = a; +			} +		} +		groupMemoryBarrier(); +		barrier(); +	} + +	// Store shared data +	for (i = 0; i < 2; ++i) { +		if (GI + i * NUM_THREADS < tgp.w) { +			sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS]; +		} +	} + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl index b7c46a7d0e..4cc4fd3f64 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl @@ -37,16 +37,18 @@ layout(push_constant, binding = 1, std430) uniform Params {  	uvec2 glow_texture_size;  	float glow_intensity; -	uint glow_level_flags; +	uint pad3;  	uint glow_mode; +	float glow_levels[7];  	float exposure;  	float white;  	float auto_exposure_grey; +	uint pad2;  	vec2 pixel_size;  	bool use_fxaa; -	uint pad; +	bool use_debanding;  }  params; @@ -155,6 +157,10 @@ vec3 tonemap_aces(vec3 color, float white) {  }  vec3 tonemap_reinhard(vec3 color, float white) { +	// Ensure color values are positive. +	// They can be negative in the case of negative lights, which leads to undesired behavior. +	color = max(vec3(0.0), color); +  	return (white * color + color) / (color * white + white);  } @@ -186,32 +192,32 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o  vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels  	vec3 glow = vec3(0.0f); -	if (bool(params.glow_level_flags & (1 << 0))) { -		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb; +	if (params.glow_levels[0] > 0.0001) { +		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb * params.glow_levels[0];  	} -	if (bool(params.glow_level_flags & (1 << 1))) { -		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb; +	if (params.glow_levels[1] > 0.0001) { +		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb * params.glow_levels[1];  	} -	if (bool(params.glow_level_flags & (1 << 2))) { -		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb; +	if (params.glow_levels[2] > 0.0001) { +		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb * params.glow_levels[2];  	} -	if (bool(params.glow_level_flags & (1 << 3))) { -		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb; +	if (params.glow_levels[3] > 0.0001) { +		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb * params.glow_levels[3];  	} -	if (bool(params.glow_level_flags & (1 << 4))) { -		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb; +	if (params.glow_levels[4] > 0.0001) { +		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb * params.glow_levels[4];  	} -	if (bool(params.glow_level_flags & (1 << 5))) { -		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb; +	if (params.glow_levels[5] > 0.0001) { +		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb * params.glow_levels[5];  	} -	if (bool(params.glow_level_flags & (1 << 6))) { -		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb; +	if (params.glow_levels[6] > 0.0001) { +		glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb * params.glow_levels[6];  	}  	return glow; @@ -287,9 +293,8 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {  						  dir * rcpDirMin)) *  		  params.pixel_size; -	vec3 rgbA = 0.5 * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz * exposure + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * exposure; -	vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz * exposure + -											textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz * exposure); +	vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); +	vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz);  	float lumaB = dot(rgbB, luma);  	if ((lumaB < lumaMin) || (lumaB > lumaMax)) { @@ -299,6 +304,18 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {  	}  } +// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf +// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom) +// NOTE: `frag_coord` is in pixels (i.e. not normalized UV). +vec3 screen_space_dither(vec2 frag_coord) { +	// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR. +	vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord)); +	dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0)); + +	// Subtract 0.5 to avoid slightly brightening the whole viewport. +	return (dither.rgb - 0.5) / 255.0; +} +  void main() {  	vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; @@ -322,6 +339,11 @@ void main() {  	if (params.use_fxaa) {  		color = do_fxaa(color, exposure, uv_interp);  	} +	if (params.use_debanding) { +		// For best results, debanding should be done before tonemapping. +		// Otherwise, we're adding noise to an already-quantized image. +		color += screen_space_dither(gl_FragCoord.xy); +	}  	color = apply_tonemapping(color, params.white);  	color = linear_to_srgb(color); // regular linear -> SRGB conversion diff --git a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl new file mode 100644 index 0000000000..13b162f0c9 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl @@ -0,0 +1,530 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +#if defined(MODE_FOG) || defined(MODE_FILTER) + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#endif + +#if defined(MODE_DENSITY) + +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; + +#endif + +#include "cluster_data_inc.glsl" + +#define M_PI 3.14159265359 + +layout(set = 0, binding = 1) uniform texture2D shadow_atlas; +layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas; + +layout(set = 0, binding = 3, std430) restrict readonly buffer Lights { +	LightData data[]; +} +lights; + +layout(set = 0, binding = 4, std140) uniform DirectionalLights { +	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} +directional_lights; + +layout(set = 0, binding = 5) uniform utexture3D cluster_texture; + +layout(set = 0, binding = 6, std430) restrict readonly buffer ClusterData { +	uint indices[]; +} +cluster_data; + +layout(set = 0, binding = 7) uniform sampler linear_sampler; + +#ifdef MODE_DENSITY +layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map; +layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused +#endif + +#ifdef MODE_FOG +layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map; +layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map; +#endif + +#ifdef MODE_FILTER +layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map; +layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map; +#endif + +layout(set = 0, binding = 10) uniform sampler shadow_sampler; + +#define MAX_GI_PROBES 8 + +struct GIProbeData { +	mat4 xform; +	vec3 bounds; +	float dynamic_range; + +	float bias; +	float normal_bias; +	bool blend_ambient; +	uint texture_slot; + +	float anisotropy_strength; +	float ambient_occlusion; +	float ambient_occlusion_size; +	uint mipmaps; +}; + +layout(set = 0, binding = 11, std140) uniform GIProbes { +	GIProbeData data[MAX_GI_PROBES]; +} +gi_probes; + +layout(set = 0, binding = 12) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; + +layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps; + +#ifdef ENABLE_SDFGI + +// SDFGI Integration on set 1 +#define SDFGI_MAX_CASCADES 8 + +struct SDFGIProbeCascadeData { +	vec3 position; +	float to_probe; +	ivec3 probe_world_offset; +	float to_cell; // 1/bounds * grid_size +}; + +layout(set = 1, binding = 0, std140) uniform SDFGI { +	vec3 grid_size; +	uint max_cascades; + +	bool use_occlusion; +	int probe_axis_size; +	float probe_to_uvw; +	float normal_bias; + +	vec3 lightprobe_tex_pixel_size; +	float energy; + +	vec3 lightprobe_uv_offset; +	float y_mult; + +	vec3 occlusion_clamp; +	uint pad3; + +	vec3 occlusion_renormalize; +	uint pad4; + +	vec3 cascade_probe_size; +	uint pad5; + +	SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES]; +} +sdfgi; + +layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture; + +layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture; + +#endif //SDFGI + +layout(push_constant, binding = 0, std430) uniform Params { +	vec2 fog_frustum_size_begin; +	vec2 fog_frustum_size_end; + +	float fog_frustum_end; +	float z_near; +	float z_far; +	int filter_axis; + +	ivec3 fog_volume_size; +	uint directional_light_count; + +	vec3 light_color; +	float base_density; + +	float detail_spread; +	float gi_inject; +	uint max_gi_probes; +	uint pad; + +	mat3x4 cam_rotation; +} +params; + +float get_depth_at_pos(float cell_depth_size, int z) { +	float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels +	d = pow(d, params.detail_spread); +	return params.fog_frustum_end * d; +} + +vec3 hash3f(uvec3 x) { +	x = ((x >> 16) ^ x) * 0x45d9f3b; +	x = ((x >> 16) ^ x) * 0x45d9f3b; +	x = (x >> 16) ^ x; +	return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF)); +} + +void main() { +	vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size); + +#ifdef MODE_DENSITY + +	ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); +	if (any(greaterThanEqual(pos, params.fog_volume_size))) { +		return; //do not compute +	} + +	vec3 posf = vec3(pos); + +	//posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0; + +	vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels +	fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); + +	vec3 view_pos; +	view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z)); +	view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; +	view_pos.y = -view_pos.y; + +	vec3 total_light = params.light_color; + +	float total_density = params.base_density; +	float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1)); +	//compute directional lights + +	for (uint i = 0; i < params.directional_light_count; i++) { +		vec3 shadow_attenuation = vec3(1.0); + +		if (directional_lights.data[i].shadow_enabled) { +			float depth_z = -view_pos.z; + +			vec4 pssm_coord; +			vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb; +			vec3 light_dir = directional_lights.data[i].direction; +			vec4 v = vec4(view_pos, 1.0); +			float z_range; + +			if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { +				pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); +				pssm_coord /= pssm_coord.w; +				z_range = directional_lights.data[i].shadow_z_range.x; + +			} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { +				pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); +				pssm_coord /= pssm_coord.w; +				z_range = directional_lights.data[i].shadow_z_range.y; + +			} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { +				pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); +				pssm_coord /= pssm_coord.w; +				z_range = directional_lights.data[i].shadow_z_range.z; + +			} else { +				pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); +				pssm_coord /= pssm_coord.w; +				z_range = directional_lights.data[i].shadow_z_range.w; +			} + +			float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r; +			float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade); + +			/* +			//float shadow = textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord); +			float shadow = 0.0; +			for(float xi=-1;xi<=1;xi++) { +				for(float yi=-1;yi<=1;yi++) { +					vec2 ofs = vec2(xi,yi) * 1.5 * params.directional_shadow_pixel_size; +					shadow += textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord + vec4(ofs,0.0,0.0)); +				} + +			} + +			shadow /= 3.0 * 3.0; + +*/ +			shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance + +			shadow_attenuation = mix(shadow_color, vec3(1.0), shadow); +		} + +		total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy / M_PI; +	} + +	//compute lights from cluster + +	vec3 cluster_pos; +	cluster_pos.xy = fog_unit_pos.xy; +	cluster_pos.z = clamp((abs(view_pos.z) - params.z_near) / (params.z_far - params.z_near), 0.0, 1.0); + +	uvec4 cluster_cell = texture(usampler3D(cluster_texture, linear_sampler), cluster_pos); + +	uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT; +	uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK; + +	for (uint i = 0; i < omni_light_count; i++) { +		uint light_index = cluster_data.indices[omni_light_pointer + i]; + +		vec3 light_pos = lights.data[i].position; +		float d = distance(lights.data[i].position, view_pos) * lights.data[i].inv_radius; +		vec3 shadow_attenuation = vec3(1.0); + +		if (d < 1.0) { +			vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); +			vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); + +			float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); + +			vec3 light = attenuation_energy.y * color_specular.rgb / M_PI; + +			vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled); + +			if (shadow_color_enabled.a > 0.5) { +				//has shadow +				vec4 v = vec4(view_pos, 1.0); + +				vec4 splane = (lights.data[i].shadow_matrix * v); +				float shadow_len = length(splane.xyz); //need to remember shadow len from here + +				splane.xyz = normalize(splane.xyz); +				vec4 clamp_rect = lights.data[i].atlas_rect; + +				if (splane.z >= 0.0) { +					splane.z += 1.0; + +					clamp_rect.y += clamp_rect.w; + +				} else { +					splane.z = 1.0 - splane.z; +				} + +				splane.xy /= splane.z; + +				splane.xy = splane.xy * 0.5 + 0.5; +				splane.z = shadow_len * lights.data[i].inv_radius; +				splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; +				splane.w = 1.0; //needed? i think it should be 1 already + +				float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; +				float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade); + +				shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); +			} +			total_light += light * attenuation * shadow_attenuation; +		} +	} + +	uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT; +	uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK; + +	for (uint i = 0; i < spot_light_count; i++) { +		uint light_index = cluster_data.indices[spot_light_pointer + i]; + +		vec3 light_pos = lights.data[i].position; +		vec3 light_rel_vec = lights.data[i].position - view_pos; +		float d = length(light_rel_vec) * lights.data[i].inv_radius; +		vec3 shadow_attenuation = vec3(1.0); + +		if (d < 1.0) { +			vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); +			vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); + +			float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); + +			vec3 spot_dir = lights.data[i].direction; +			vec2 spot_att_angle = unpackHalf2x16(lights.data[i].cone_attenuation_angle); +			float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y); +			float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y)); +			attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x); + +			vec3 light = attenuation_energy.y * color_specular.rgb / M_PI; + +			vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled); + +			if (shadow_color_enabled.a > 0.5) { +				//has shadow +				vec4 v = vec4(view_pos, 1.0); + +				vec4 splane = (lights.data[i].shadow_matrix * v); +				splane /= splane.w; + +				float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; +				float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade); + +				shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); +			} + +			total_light += light * attenuation * shadow_attenuation; +		} +	} + +	vec3 world_pos = mat3(params.cam_rotation) * view_pos; + +	for (uint i = 0; i < params.max_gi_probes; i++) { +		vec3 position = (gi_probes.data[i].xform * vec4(world_pos, 1.0)).xyz; + +		//this causes corrupted pixels, i have no idea why.. +		if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, gi_probes.data[i].bounds))))) { +			position /= gi_probes.data[i].bounds; + +			vec4 light = vec4(0.0); +			for (uint j = 0; j < gi_probes.data[i].mipmaps; j++) { +				vec4 slight = textureLod(sampler3D(gi_probe_textures[i], linear_sampler_with_mipmaps), position, float(j)); +				float a = (1.0 - light.a); +				light += a * slight; +			} + +			light.rgb *= gi_probes.data[i].dynamic_range * params.gi_inject; + +			total_light += light.rgb; +		} +	} + +	//sdfgi +#ifdef ENABLE_SDFGI + +	{ +		float blend = -1.0; +		vec3 ambient_total = vec3(0.0); + +		for (uint i = 0; i < sdfgi.max_cascades; i++) { +			vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe; + +			if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) { +				continue; //skip cascade +			} + +			vec3 base_pos = floor(cascade_pos); +			ivec3 probe_base_pos = ivec3(base_pos); + +			vec4 ambient_accum = vec4(0.0); + +			ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i)); +			tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size; + +			for (uint j = 0; j < 8; j++) { +				ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); +				ivec3 probe_posi = probe_base_pos; +				probe_posi += offset; + +				// Compute weight + +				vec3 probe_pos = vec3(probe_posi); +				vec3 probe_to_pos = cascade_pos - probe_pos; + +				vec3 trilinear = vec3(1.0) - abs(probe_to_pos); +				float weight = trilinear.x * trilinear.y * trilinear.z; + +				// Compute lightprobe occlusion + +				if (sdfgi.use_occlusion) { +					ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); +					vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); + +					vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw; +					occ_pos.z += float(i); +					if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures +						occ_pos.x += 1.0; +					} + +					occ_pos *= sdfgi.occlusion_renormalize; +					float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask); + +					weight *= max(occlusion, 0.01); +				} + +				// Compute ambient texture position + +				ivec3 uvw = tex_pos; +				uvw.xy += offset.xy; +				uvw.x += offset.z * sdfgi.probe_axis_size; + +				vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb; + +				ambient_accum.rgb += ambient * weight; +				ambient_accum.a += weight; +			} + +			if (ambient_accum.a > 0) { +				ambient_accum.rgb /= ambient_accum.a; +			} +			ambient_total = ambient_accum.rgb; +			break; +		} + +		total_light += ambient_total * params.gi_inject; +	} + +#endif + +	imageStore(density_map, pos, vec4(total_light, total_density)); +#endif + +#ifdef MODE_FOG + +	ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0); + +	if (any(greaterThanEqual(pos, params.fog_volume_size))) { +		return; //do not compute +	} + +	vec4 fog_accum = vec4(0.0); +	float prev_z = 0.0; + +	float t = 1.0; + +	for (int i = 0; i < params.fog_volume_size.z; i++) { +		//compute fog position +		ivec3 fog_pos = pos + ivec3(0, 0, i); +		//get fog value +		vec4 fog = imageLoad(density_map, fog_pos); + +		//get depth at cell pos +		float z = get_depth_at_pos(fog_cell_size.z, i); +		//get distance from previous pos +		float d = abs(prev_z - z); +		//compute exinction based on beer's +		float extinction = t * exp(-d * fog.a); +		//compute alpha based on different of extinctions +		float alpha = t - extinction; +		//update extinction +		t = extinction; + +		fog_accum += vec4(fog.rgb * alpha, alpha); +		prev_z = z; + +		vec4 fog_value; + +		if (fog_accum.a > 0.0) { +			fog_value = vec4(fog_accum.rgb / fog_accum.a, 1.0 - t); +		} else { +			fog_value = vec4(0.0); +		} + +		imageStore(fog_map, fog_pos, fog_value); +	} + +#endif + +#ifdef MODE_FILTER + +	ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); + +	const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303); + +	const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1)); +	ivec3 offset = filter_dir[params.filter_axis]; + +	vec4 accum = vec4(0.0); +	for (int i = -3; i <= 3; i++) { +		accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3]; +	} + +	imageStore(dest_map, pos, accum); + +#endif +}  |