Kaynağa Gözat

Dynamic object support for GI Probes (a bit buggy still)

Juan Linietsky 6 yıl önce
ebeveyn
işleme
561b431d85

+ 2 - 2
drivers/vulkan/rendering_device_vulkan.cpp

@@ -2656,7 +2656,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
 			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
 			image_memory_barrier.pNext = NULL;
 			image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
 			image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
 			image_memory_barrier.newLayout = src_tex->layout;
 			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@@ -2677,7 +2677,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
 			image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
 			image_memory_barrier.pNext = NULL;
 			image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+			image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
 			image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 			image_memory_barrier.newLayout = dst_tex->layout;
 

+ 3 - 0
drivers/vulkan/vulkan_context.cpp

@@ -60,6 +60,9 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(VkDebugU
 			strstr(pCallbackData->pMessage, "must be a memory object") != NULL) {
 		return VK_FALSE;
 	}
+	if (strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != NULL) {
+		return VK_FALSE;
+	}
 
 	if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
 		strcat(prefix, "VERBOSE : ");

+ 2 - 0
scene/3d/visual_instance.cpp

@@ -298,6 +298,7 @@ void GeometryInstance::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT);
+	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_dynamic_gi"), "set_flag", "get_flag", FLAG_USE_DYNAMIC_GI);
 
 	ADD_GROUP("LOD", "lod_");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance");
@@ -313,6 +314,7 @@ void GeometryInstance::_bind_methods() {
 	BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY);
 
 	BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT);
+	BIND_ENUM_CONSTANT(FLAG_USE_DYNAMIC_GI);
 	BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
 	BIND_ENUM_CONSTANT(FLAG_MAX);
 }

+ 1 - 0
scene/3d/visual_instance.h

@@ -87,6 +87,7 @@ class GeometryInstance : public VisualInstance {
 public:
 	enum Flags {
 		FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT,
+		FLAG_USE_DYNAMIC_GI = VS::INSTANCE_FLAG_USE_DYNAMIC_GI,
 		FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
 		FLAG_MAX = VS::INSTANCE_FLAG_MAX,
 	};

+ 8 - 2
servers/visual/rasterizer.h

@@ -140,7 +140,8 @@ public:
 		bool mirror : 8;
 		bool receive_shadows : 8;
 		bool visible : 8;
-		bool baked_light : 4; //this flag is only to know if it actually did use baked light
+		bool baked_light : 2; //this flag is only to know if it actually did use baked light
+		bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light
 		bool redraw_if_visible : 4;
 
 		float depth; //used for sorting
@@ -151,6 +152,9 @@ public:
 		RID lightmap;
 		Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader
 
+		AABB aabb;
+		AABB transformed_aabb;
+
 		virtual void dependency_deleted(RID p_dependency) = 0;
 		virtual void dependency_changed(bool p_aabb, bool p_dependencies) = 0;
 
@@ -204,6 +208,7 @@ public:
 			layer_mask = 1;
 			instance_version = 0;
 			baked_light = false;
+			dynamic_gi = false;
 			redraw_if_visible = false;
 			lightmap_capture = NULL;
 		}
@@ -233,11 +238,12 @@ public:
 	virtual RID gi_probe_instance_create(RID p_gi_probe) = 0;
 	virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0;
 	virtual bool gi_probe_needs_update(RID p_probe) const = 0;
-	virtual void gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances) = 0;
+	virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 0;
 
 	virtual 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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
 
 	virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 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 set_scene_pass(uint64_t p_pass) = 0;
 	virtual void set_time(double p_time) = 0;

+ 64 - 10
servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp

@@ -308,9 +308,11 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
 						if (depth_draw == DEPTH_DRAW_OPAQUE) {
 							depth_stencil.enable_depth_write = false; //alpha does not draw depth
 						}
-					} else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS)) {
+					} else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
 						if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
 							//none, blend state contains nothing
+						} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+							blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
 						} else {
 							blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
 						}
@@ -326,6 +328,9 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
 						//none, leave empty
 					} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
 						blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
+					} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+						blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+
 					} else {
 						//specular write
 						blend_state = blend_state_opaque_specular;
@@ -601,7 +606,7 @@ bool RasterizerSceneForwardRD::free(RID p_rid) {
 	return false;
 }
 
-void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count) {
+void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth) {
 
 	for (int i = 0; i < p_element_count; i++) {
 
@@ -637,6 +642,10 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements,
 			}
 		}
 
+		if (p_for_depth) {
+			id.gi_offset = 0xFFFFFFFF;
+			continue;
+		}
 		//forward
 
 		uint32_t reflection_count = 0;
@@ -850,6 +859,9 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
 			case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
 				shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
 			} break;
+			case PASS_MODE_DEPTH_MATERIAL: {
+				shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+			} break;
 		}
 
 		RenderPipelineVertexFormatCacheRD *pipeline = nullptr;
@@ -939,12 +951,12 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
 	}
 }
 
-void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) {
+void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y) {
 
 	//CameraMatrix projection = p_cam_projection;
 	//projection.flip_y(); // Vulkan and modern APIs use Y-Down
 	CameraMatrix correction;
-	correction.set_depth_correction(!p_reflection_probe.is_valid());
+	correction.set_depth_correction(p_flip_y);
 	CameraMatrix projection = correction * p_cam_projection;
 
 	//store camera into ubo
@@ -1236,7 +1248,7 @@ void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_insta
 			return;
 		}
 
-		if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
+		if (p_pass_mode != PASS_MODE_DEPTH_MATERIAL && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
 			//shader does not use discard and does not write a vertex position, use generic material
 			if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) {
 				p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
@@ -1837,7 +1849,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
 	_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
 	_setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
 	_setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform);
-	_setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas);
+	_setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid());
 
 	render_list.clear();
 	_fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
@@ -1896,7 +1908,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
 
 	render_list.sort_by_key(false);
 
-	_fill_instances(render_list.elements, render_list.element_count);
+	_fill_instances(render_list.elements, render_list.element_count, false);
 
 	bool can_continue = true; //unless the middle buffers are needed
 	bool debug_giprobes = debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
@@ -1952,7 +1964,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
 
 	render_list.sort_by_reverse_depth_and_priority(true);
 
-	_fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count);
+	_fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false);
 
 	{
 		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
@@ -2087,7 +2099,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
 	scene_state.ubo.z_far = p_zfar;
 	scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
 
-	_setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID());
+	_setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true);
 
 	render_list.clear();
 
@@ -2101,7 +2113,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
 
 	render_list.sort_by_key(false);
 
-	_fill_instances(render_list.elements, render_list.element_count);
+	_fill_instances(render_list.elements, render_list.element_count, true);
 
 	{
 		//regular forward for now
@@ -2111,6 +2123,47 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
 	}
 }
 
+void RasterizerSceneForwardRD::_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 Shadow");
+
+	_update_render_base_uniform_set();
+
+	render_pass++;
+
+	scene_state.ubo.shadow_z_offset = 0;
+	scene_state.ubo.shadow_z_slope_scale = 0;
+	scene_state.ubo.z_far = 0;
+	scene_state.ubo.dual_paraboloid_side = 0;
+
+	_setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false);
+
+	render_list.clear();
+
+	PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
+	_fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
+
+	_setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID());
+
+	RENDER_TIMESTAMP("Render Material");
+
+	render_list.sort_by_key(false);
+
+	_fill_instances(render_list.elements, render_list.element_count, true);
+
+	{
+		//regular forward for now
+		Vector<Color> clear;
+		clear.push_back(Color(0, 0, 0, 0));
+		clear.push_back(Color(0, 0, 0, 0));
+		clear.push_back(Color(0, 0, 0, 0));
+		clear.push_back(Color(0, 0, 0, 0));
+		clear.push_back(Color(0, 0, 0, 0));
+		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+		_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true);
+		RD::get_singleton()->draw_list_end();
+	}
+}
+
 void RasterizerSceneForwardRD::_update_render_base_uniform_set() {
 
 	if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || gi_probe_slots_are_dirty()) {
@@ -2425,6 +2478,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
 		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
 		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_BUFFER\n");
 		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_ROUGHNESS_BUFFER\n");
+		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
 		shader_versions.push_back("");
 		shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
 		shader_versions.push_back("\n#define USE_VOXEL_CONE_TRACING\n");

+ 5 - 2
servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h

@@ -45,6 +45,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 		SHADER_VERSION_DEPTH_PASS_DP,
 		SHADER_VERSION_DEPTH_PASS_WITH_NORMAL,
 		SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+		SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
 		SHADER_VERSION_COLOR_PASS,
 		SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
 		SHADER_VERSION_VCT_COLOR_PASS,
@@ -519,14 +520,15 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 		PASS_MODE_DEPTH,
 		PASS_MODE_DEPTH_NORMAL,
 		PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
+		PASS_MODE_DEPTH_MATERIAL,
 	};
 
-	void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas);
+	void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y);
 	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);
 	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_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform);
 
-	void _fill_instances(RenderList::Element **p_elements, int p_element_count);
+	void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth);
 	void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi);
 	_FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index);
 	_FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index);
@@ -540,6 +542,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 protected:
 	virtual void _render_scene(RenderBufferData *p_buffer_data, 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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
 	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 p_use_dp_flip);
+	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);
 
 public:
 	virtual void set_time(double p_time);

+ 587 - 105
servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -1245,7 +1245,7 @@ bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const {
 	return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
 }
 
-void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances) {
+void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) {
 
 	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
 	ERR_FAIL_COND(!gi_probe);
@@ -1266,6 +1266,13 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
 			gi_probe->mipmaps.clear();
 		}
 
+		for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
+			RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
+			RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
+		}
+
+		gi_probe->dynamic_maps.clear();
+
 		Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
 
 		if (octree_size != Vector3i()) {
@@ -1354,6 +1361,21 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
 					u.ids.push_back(gi_probe->write_buffer);
 					uniforms.push_back(u);
 				}
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_TEXTURE;
+					u.binding = 9;
+					u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
+					uniforms.push_back(u);
+				}
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_SAMPLER;
+					u.binding = 10;
+					u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+					uniforms.push_back(u);
+				}
+
 				{
 					Vector<RD::Uniform> copy_uniforms = uniforms;
 					if (i == 0) {
@@ -1376,13 +1398,6 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
 							u.ids.push_back(gi_probe->texture);
 							copy_uniforms.push_back(u);
 						}
-						{
-							RD::Uniform u;
-							u.type = RD::UNIFORM_TYPE_SAMPLER;
-							u.binding = 6;
-							u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
-							copy_uniforms.push_back(u);
-						}
 
 						if (gi_probe_use_anisotropy) {
 							{
@@ -1436,138 +1451,579 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector<RID> &p_light_
 
 				gi_probe->mipmaps.push_back(mipmap);
 			}
+
+			{
+				uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+				uint32_t oversample = nearest_power_of_2_templated(4);
+				int mipmap_index = 0;
+
+				while (mipmap_index < gi_probe->mipmaps.size()) {
+					GIProbeInstance::DynamicMap dmap;
+
+					if (oversample > 0) {
+						dmap.size = dynamic_map_size * (1 << oversample);
+						dmap.mipmap = -1;
+						oversample--;
+					} else {
+						dmap.size = dynamic_map_size >> mipmap_index;
+						dmap.mipmap = mipmap_index;
+						mipmap_index++;
+					}
+
+					RD::TextureFormat dtf;
+					dtf.width = dmap.size;
+					dtf.height = dmap.size;
+					dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+					dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+					if (gi_probe->dynamic_maps.size() == 0) {
+						dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+					}
+					dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+					if (gi_probe->dynamic_maps.size() == 0) {
+						//render depth for first one
+						dtf.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;
+						dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+						dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+					}
+
+					//just use depth as-is
+					dtf.format = RD::DATA_FORMAT_R32_SFLOAT;
+					dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+					dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+					if (gi_probe->dynamic_maps.size() == 0) {
+
+						dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+						dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+						dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+						dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+						dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+						Vector<RID> fb;
+						fb.push_back(dmap.albedo);
+						fb.push_back(dmap.normal);
+						fb.push_back(dmap.orm);
+						fb.push_back(dmap.texture); //emission
+						fb.push_back(dmap.depth);
+						fb.push_back(dmap.fb_depth);
+
+						dmap.fb = RD::get_singleton()->framebuffer_create(fb);
+
+						{
+							Vector<RD::Uniform> uniforms;
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+								u.binding = 3;
+								u.ids.push_back(gi_probe_lights_uniform);
+								uniforms.push_back(u);
+							}
+
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 5;
+								u.ids.push_back(dmap.albedo);
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 6;
+								u.ids.push_back(dmap.normal);
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 7;
+								u.ids.push_back(dmap.orm);
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_TEXTURE;
+								u.binding = 8;
+								u.ids.push_back(dmap.fb_depth);
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_TEXTURE;
+								u.binding = 9;
+								u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_SAMPLER;
+								u.binding = 10;
+								u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 11;
+								u.ids.push_back(dmap.texture);
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 12;
+								u.ids.push_back(dmap.depth);
+								uniforms.push_back(u);
+							}
+
+							dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
+						}
+					} else {
+						bool plot = dmap.mipmap >= 0;
+						bool write = dmap.mipmap < (gi_probe->mipmaps.size() - 1);
+
+						Vector<RD::Uniform> uniforms;
+
+						{
+							RD::Uniform u;
+							u.type = RD::UNIFORM_TYPE_IMAGE;
+							u.binding = 5;
+							u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture);
+							uniforms.push_back(u);
+						}
+						{
+							RD::Uniform u;
+							u.type = RD::UNIFORM_TYPE_IMAGE;
+							u.binding = 6;
+							u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth);
+							uniforms.push_back(u);
+						}
+
+						if (write) {
+
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 7;
+								u.ids.push_back(dmap.texture);
+								uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 8;
+								u.ids.push_back(dmap.depth);
+								uniforms.push_back(u);
+							}
+						}
+
+						{
+							RD::Uniform u;
+							u.type = RD::UNIFORM_TYPE_TEXTURE;
+							u.binding = 9;
+							u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
+							uniforms.push_back(u);
+						}
+						{
+							RD::Uniform u;
+							u.type = RD::UNIFORM_TYPE_SAMPLER;
+							u.binding = 10;
+							u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+							uniforms.push_back(u);
+						}
+
+						if (plot) {
+
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_IMAGE;
+								u.binding = 11;
+								u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture);
+								uniforms.push_back(u);
+							}
+							if (gi_probe_is_anisotropic()) {
+								{
+									RD::Uniform u;
+									u.type = RD::UNIFORM_TYPE_IMAGE;
+									u.binding = 12;
+									u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[0]);
+									uniforms.push_back(u);
+								}
+								{
+									RD::Uniform u;
+									u.type = RD::UNIFORM_TYPE_IMAGE;
+									u.binding = 13;
+									u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[1]);
+									uniforms.push_back(u);
+								}
+							}
+						}
+
+						dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT], 0);
+					}
+
+					gi_probe->dynamic_maps.push_back(dmap);
+				}
+			}
 		}
 
 		gi_probe->last_probe_data_version = data_version;
 		gi_probe_slots_dirty = true;
+		p_update_light_instances = true; //just in case
 	}
 
 	// UDPDATE TIME
 
-	uint32_t light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
-	{
-		Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe);
-		Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse();
-		//update lights
+	if (gi_probe->has_dynamic_object_data) {
+		//if it has dynamic object data, it needs to be cleared
+		RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true);
+	}
 
-		for (uint32_t i = 0; i < light_count; i++) {
-			GIProbeLight &l = gi_probe_lights[i];
-			RID light_instance = p_light_instances[i];
-			RID light = light_instance_get_base_light(light_instance);
+	uint32_t light_count = 0;
 
-			l.type = storage->light_get_type(light);
-			l.attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_ATTENUATION);
-			l.energy = storage->light_get_param(light, VS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, VS::LIGHT_PARAM_INDIRECT_ENERGY);
-			l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, VS::LIGHT_PARAM_RANGE), 0, 0)).length();
-			Color color = storage->light_get_color(light).to_linear();
-			l.color[0] = color.r;
-			l.color[1] = color.g;
-			l.color[2] = color.b;
+	if (p_update_light_instances || p_dynamic_object_count > 0) {
 
-			l.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ANGLE));
-			l.spot_attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ATTENUATION);
+		light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
 
-			Transform xform = light_instance_get_base_transform(light_instance);
+		{
+			Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe);
+			Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse();
+			//update lights
 
-			Vector3 pos = to_probe_xform.xform(xform.origin);
-			Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
+			for (uint32_t i = 0; i < light_count; i++) {
+				GIProbeLight &l = gi_probe_lights[i];
+				RID light_instance = p_light_instances[i];
+				RID light = light_instance_get_base_light(light_instance);
 
-			l.position[0] = pos.x;
-			l.position[1] = pos.y;
-			l.position[2] = pos.z;
+				l.type = storage->light_get_type(light);
+				l.attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_ATTENUATION);
+				l.energy = storage->light_get_param(light, VS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, VS::LIGHT_PARAM_INDIRECT_ENERGY);
+				l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, VS::LIGHT_PARAM_RANGE), 0, 0)).length();
+				Color color = storage->light_get_color(light).to_linear();
+				l.color[0] = color.r;
+				l.color[1] = color.g;
+				l.color[2] = color.b;
 
-			l.direction[0] = dir.x;
-			l.direction[1] = dir.y;
-			l.direction[2] = dir.z;
+				l.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ANGLE));
+				l.spot_attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ATTENUATION);
 
-			l.has_shadow = storage->light_has_shadow(light);
-		}
+				Transform xform = light_instance_get_base_transform(light_instance);
+
+				Vector3 pos = to_probe_xform.xform(xform.origin);
+				Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
 
-		RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights, true);
+				l.position[0] = pos.x;
+				l.position[1] = pos.y;
+				l.position[2] = pos.z;
+
+				l.direction[0] = dir.x;
+				l.direction[1] = dir.y;
+				l.direction[2] = dir.z;
+
+				l.has_shadow = storage->light_has_shadow(light);
+			}
+
+			RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights, true);
+		}
 	}
 
-	// PROCESS MIPMAPS
-	if (gi_probe->mipmaps.size()) {
-		//can update mipmaps
-
-		Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
-		GIProbePushConstant push_constant;
-
-		push_constant.limits[0] = probe_size.x;
-		push_constant.limits[1] = probe_size.y;
-		push_constant.limits[2] = probe_size.z;
-		push_constant.stack_size = gi_probe->mipmaps.size();
-		push_constant.emission_scale = 1.0;
-		push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
-		push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
-		push_constant.light_count = light_count;
-		push_constant.aniso_strength = storage->gi_probe_get_anisotropy_strength(gi_probe->probe);
-
-		/*		print_line("probe update to version " + itos(gi_probe->last_probe_version));
-		print_line("propagation " + rtos(push_constant.propagation));
-		print_line("dynrange " + rtos(push_constant.dynamic_range));
-*/
-		RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
-		int passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
-		int wg_size = 64;
-		int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
-
-		for (int pass = 0; pass < passes; pass++) {
-
-			for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
-				if (i == 0) {
-					RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
-				} else if (i == 1) {
-					RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
-				}
+	if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) {
+		// PROCESS MIPMAPS
+		if (gi_probe->mipmaps.size()) {
+			//can update mipmaps
+
+			Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
+
+			GIProbePushConstant push_constant;
+
+			push_constant.limits[0] = probe_size.x;
+			push_constant.limits[1] = probe_size.y;
+			push_constant.limits[2] = probe_size.z;
+			push_constant.stack_size = gi_probe->mipmaps.size();
+			push_constant.emission_scale = 1.0;
+			push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
+			push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
+			push_constant.light_count = light_count;
+			push_constant.aniso_strength = storage->gi_probe_get_anisotropy_strength(gi_probe->probe);
+
+			/*		print_line("probe update to version " + itos(gi_probe->last_probe_version));
+			print_line("propagation " + rtos(push_constant.propagation));
+			print_line("dynrange " + rtos(push_constant.dynamic_range));
+	*/
+			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+			int passes;
+			if (p_update_light_instances) {
+				passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
+			} else {
+				passes = 1; //only re-blitting is necessary
+			}
+			int wg_size = 64;
+			int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
+
+			for (int pass = 0; pass < passes; pass++) {
+
+				if (p_update_light_instances) {
+
+					for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
+						if (i == 0) {
+							RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
+						} else if (i == 1) {
+							RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
+						}
+
+						if (pass == 1 || i > 0) {
+							RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+						}
+						if (pass == 0 || i > 0) {
+							RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
+						} else {
+							RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
+						}
+
+						push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
+						push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+
+						int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
+						while (wg_todo) {
+							int wg_count = MIN(wg_todo, wg_limit_x);
+							RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+							RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+							wg_todo -= wg_count;
+							push_constant.cell_offset += wg_count * wg_size;
+						}
+					}
 
-				if (pass == 1 || i > 0) {
 					RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
 				}
-				if (pass == 0 || i > 0) {
-					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
-				} else {
-					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
+
+				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+
+				for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
+
+					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
+
+					push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
+					push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+
+					int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
+					while (wg_todo) {
+						int wg_count = MIN(wg_todo, wg_limit_x);
+						RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+						RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+						wg_todo -= wg_count;
+						push_constant.cell_offset += wg_count * wg_size;
+					}
 				}
+			}
+
+			RD::get_singleton()->compute_list_end();
+		}
+	}
 
-				push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
-				push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+	gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again
 
-				int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
-				while (wg_todo) {
-					int wg_count = MIN(wg_todo, wg_limit_x);
-					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
-					RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
-					wg_todo -= wg_count;
-					push_constant.cell_offset += wg_count * wg_size;
+	if (p_dynamic_object_count && gi_probe->dynamic_maps.size()) {
+
+		Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
+		int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+
+		Transform oversample_scale;
+		oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
+
+		Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(gi_probe->probe);
+		Transform to_world_xform = gi_probe->transform * to_cell.affine_inverse();
+		Transform to_probe_xform = to_world_xform.affine_inverse();
+
+		AABB probe_aabb(Vector3(), octree_size);
+
+		//this could probably be better parallelized in compute..
+		for (int i = 0; i < p_dynamic_object_count; i++) {
+
+			InstanceBase *instance = p_dynamic_objects[i];
+			//not used, so clear
+			instance->depth_layer = 0;
+			instance->depth = 0;
+
+			//transform aabb to giprobe
+			AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb);
+
+			//this needs to wrap to grid resolution to avoid jitter
+			//also extend margin a bit just in case
+			Vector3i begin = aabb.position - Vector3i(1, 1, 1);
+			Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1);
+
+			for (int j = 0; j < 3; j++) {
+				if ((end[j] - begin[j]) & 1) {
+					end[j]++; //for half extents split, it needs to be even
 				}
+				begin[j] = MAX(begin[j], 0);
+				end[j] = MIN(end[j], octree_size[j] * multiplier);
 			}
 
-			RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+			//aabb = aabb.intersection(probe_aabb); //intersect
+			aabb.position = begin;
+			aabb.size = end - begin;
 
-			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+			//print_line("aabb: " + aabb);
 
-			for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
+			for (int j = 0; j < 6; j++) {
 
-				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
+				//if (j != 0 && j != 3) {
+				//	continue;
+				//}
+				static const Vector3 render_z[6] = {
+					Vector3(1, 0, 0),
+					Vector3(0, 1, 0),
+					Vector3(0, 0, 1),
+					Vector3(-1, 0, 0),
+					Vector3(0, -1, 0),
+					Vector3(0, 0, -1),
+				};
+				static const Vector3 render_up[6] = {
+					Vector3(0, 1, 0),
+					Vector3(0, 0, 1),
+					Vector3(0, 1, 0),
+					Vector3(0, 1, 0),
+					Vector3(0, 0, 1),
+					Vector3(0, 1, 0),
+				};
+
+				Vector3 render_dir = render_z[j];
+				Vector3 up_dir = render_up[j];
+
+				Vector3 center = aabb.position + aabb.size * 0.5;
+				Transform xform;
+				xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
+
+				Vector3 x_dir = xform.basis.get_axis(0).abs();
+				int x_axis = int(Vector3(0, 1, 2).dot(x_dir));
+				Vector3 y_dir = xform.basis.get_axis(1).abs();
+				int y_axis = int(Vector3(0, 1, 2).dot(y_dir));
+				Vector3 z_dir = -xform.basis.get_axis(2);
+				int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs()));
+
+				Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]);
+				bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0);
+				bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0);
+				bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0);
+
+				CameraMatrix cm;
+				cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
+
+				_render_material(to_world_xform * xform, cm, true, &instance, 1, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
+
+				GIProbeDynamicPushConstant push_constant;
+				zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant));
+				push_constant.limits[0] = octree_size.x;
+				push_constant.limits[1] = octree_size.y;
+				push_constant.limits[2] = octree_size.z;
+				push_constant.light_count = p_light_instances.size();
+				push_constant.x_dir[0] = x_dir[0];
+				push_constant.x_dir[1] = x_dir[1];
+				push_constant.x_dir[2] = x_dir[2];
+				push_constant.y_dir[0] = y_dir[0];
+				push_constant.y_dir[1] = y_dir[1];
+				push_constant.y_dir[2] = y_dir[2];
+				push_constant.z_dir[0] = z_dir[0];
+				push_constant.z_dir[1] = z_dir[1];
+				push_constant.z_dir[2] = z_dir[2];
+				push_constant.z_base = xform.origin[z_axis];
+				push_constant.z_sign = (z_flip ? -1.0 : 1.0);
+				push_constant.pos_multiplier = float(1.0) / multiplier;
+				push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
+				push_constant.flip_x = x_flip;
+				push_constant.flip_y = y_flip;
+				push_constant.rect_pos[0] = rect.position[0];
+				push_constant.rect_pos[1] = rect.position[1];
+				push_constant.rect_size[0] = rect.size[0];
+				push_constant.rect_size[1] = rect.size[1];
+				push_constant.prev_rect_ofs[0] = 0;
+				push_constant.prev_rect_ofs[1] = 0;
+				push_constant.prev_rect_size[0] = 0;
+				push_constant.prev_rect_size[1] = 0;
+				push_constant.keep_downsample_color = true;
+
+				//process lighting
+				RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
+				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[0].uniform_set, 0);
+				RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+				RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
+				//print_line("rect: " + itos(i) + ": " + rect);
+
+				for (int k = 1; k < gi_probe->dynamic_maps.size(); k++) {
+
+					// enlarge the rect if needed so all pixels fit when downscaled,
+					// this ensures downsampling is smooth and optimal because no pixels are left behind
+
+					//x
+					if (rect.position.x & 1) {
+						rect.size.x++;
+						push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal
+					} else {
+						push_constant.prev_rect_ofs[0] = 0;
+					}
+					if (rect.size.x & 1) {
+						rect.size.x++;
+					}
 
-				push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
-				push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
+					rect.position.x >>= 1;
+					rect.size.x = MAX(1, rect.size.x >> 1);
+
+					//y
+					if (rect.position.y & 1) {
+						rect.size.y++;
+						push_constant.prev_rect_ofs[1] = 1;
+					} else {
+						push_constant.prev_rect_ofs[1] = 0;
+					}
+					if (rect.size.y & 1) {
+						rect.size.y++;
+					}
+
+					rect.position.y >>= 1;
+					rect.size.y = MAX(1, rect.size.y >> 1);
+
+					//shrink limits to ensure plot does not go outside map
+					if (gi_probe->dynamic_maps[i].mipmap > 0) {
+						for (int l = 0; l < 3; l++) {
+							push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1);
+						}
+					}
 
-				int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
-				while (wg_todo) {
-					int wg_count = MIN(wg_todo, wg_limit_x);
-					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
-					RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
-					wg_todo -= wg_count;
-					push_constant.cell_offset += wg_count * wg_size;
+					//print_line("rect: " + itos(i) + ": " + rect);
+					push_constant.rect_pos[0] = rect.position[0];
+					push_constant.rect_pos[1] = rect.position[1];
+					push_constant.prev_rect_size[0] = push_constant.rect_size[0];
+					push_constant.prev_rect_size[1] = push_constant.rect_size[1];
+					push_constant.rect_size[0] = rect.size[0];
+					push_constant.rect_size[1] = rect.size[1];
+					push_constant.keep_downsample_color = gi_probe->dynamic_maps[i].mipmap <= 0;
+					;
+
+					RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+					if (gi_probe->dynamic_maps[k].mipmap < 0) {
+						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
+					} else if (k < gi_probe->dynamic_maps.size() - 1) {
+						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
+					} else {
+						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
+					}
+					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[k].uniform_set, 0);
+					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+					RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
 				}
+
+				RD::get_singleton()->compute_list_end();
 			}
 		}
 
-		RD::get_singleton()->compute_list_end();
+		gi_probe->has_dynamic_object_data = true; //clear until dynamic object data is used again
 	}
 
 	gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe);
@@ -1584,6 +2040,7 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
 	CameraMatrix transform = (p_camera_with_transform * CameraMatrix(gi_probe->transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(gi_probe->probe).affine_inverse());
 
 	int level = 0;
+	Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
 
 	GIProbeDebugPushConstant push_constant;
 	push_constant.alpha = p_alpha;
@@ -1591,7 +2048,10 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
 	push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset;
 	push_constant.level = level;
 
-	int cell_count = gi_probe->mipmaps[level].cell_count;
+	push_constant.bounds[0] = octree_size.x >> level;
+	push_constant.bounds[1] = octree_size.y >> level;
+	push_constant.bounds[2] = octree_size.z >> level;
+	push_constant.pad = 0;
 
 	for (int i = 0; i < 4; i++) {
 		for (int j = 0; j < 4; j++) {
@@ -1643,8 +2103,15 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis
 		}
 	}
 
+	int cell_count;
+	if (!p_emission && p_lighting && gi_probe->has_dynamic_object_data) {
+		cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2];
+	} else {
+		cell_count = gi_probe->mipmaps[level].cell_count;
+	}
+
 	giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0);
-	RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? GI_PROBE_DEBUG_LIGHT : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+	RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
 	RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0);
 	RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
 	RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
@@ -1875,6 +2342,11 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas
 	}
 }
 
+void RasterizerSceneRD::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_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region);
+}
+
 bool RasterizerSceneRD::free(RID p_rid) {
 
 	if (render_buffers_owner.owns(p_rid)) {
@@ -1903,6 +2375,11 @@ bool RasterizerSceneRD::free(RID p_rid) {
 			RD::get_singleton()->free(gi_probe->anisotropy[1]);
 		}
 
+		for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
+			RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
+			RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
+		}
+
 		gi_probe_slots.write[gi_probe->slot] = RID();
 
 		gi_probe_instance_owner.free(p_rid);
@@ -2002,6 +2479,10 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
 		versions.push_back("\n#define MODE_SECOND_BOUNCE\n");
 		versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n");
 		versions.push_back("\n#define MODE_WRITE_TEXTURE\n");
+		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n");
+		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
+		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
+		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
 
 		giprobe_shader.initialize(versions, defines);
 		giprobe_lighting_shader_version = giprobe_shader.version_create();
@@ -2021,6 +2502,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
 		versions.push_back("\n#define MODE_DEBUG_COLOR\n");
 		versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
 		versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
+		versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
 
 		giprobe_debug_shader.initialize(versions, defines);
 		giprobe_debug_shader_version = giprobe_debug_shader.version_create();

+ 49 - 1
servers/visual/rasterizer_rd/rasterizer_scene_rd.h

@@ -26,6 +26,7 @@ protected:
 
 	virtual void _render_scene(RenderBufferData *p_buffer_data, 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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 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) = 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 _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);
 
@@ -155,6 +156,26 @@ private:
 		uint32_t pad;
 	};
 
+	struct GIProbeDynamicPushConstant {
+
+		int32_t limits[3];
+		uint32_t light_count;
+		int32_t x_dir[3];
+		float z_base;
+		int32_t y_dir[3];
+		float z_sign;
+		int32_t z_dir[3];
+		float pos_multiplier;
+		uint32_t rect_pos[2];
+		uint32_t rect_size[2];
+		uint32_t prev_rect_ofs[2];
+		uint32_t prev_rect_size[2];
+		uint32_t flip_x;
+		uint32_t flip_y;
+		float dynamic_range;
+		uint32_t keep_downsample_color;
+	};
+
 	struct GIProbeInstance {
 
 		RID probe;
@@ -174,6 +195,21 @@ private:
 		};
 		Vector<Mipmap> mipmaps;
 
+		struct DynamicMap {
+			RID texture; //color normally, or emission on first pass
+			RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
+			RID depth; //actual depth buffer for the first pass, float depth for later passes
+			RID normal; //normal buffer for the first pass
+			RID albedo; //emission buffer for the first pass
+			RID orm; //orm buffer for the first pass
+			RID fb; //used for rendering, only valid on first map
+			RID uniform_set;
+			uint32_t size;
+			int mipmap; // mipmap to write to, -1 if no mipmap assigned
+		};
+
+		Vector<DynamicMap> dynamic_maps;
+
 		int slot = -1;
 		uint32_t last_probe_version = 0;
 		uint32_t last_probe_data_version = 0;
@@ -181,6 +217,8 @@ private:
 		uint64_t last_pass = 0;
 		uint32_t render_index = 0;
 
+		bool has_dynamic_object_data = false;
+
 		Transform transform;
 	};
 
@@ -198,6 +236,10 @@ private:
 		GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
 		GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
 		GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
+		GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
+		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
+		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
+		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
 		GI_PROBE_SHADER_VERSION_MAX
 	};
 	GiprobeShaderRD giprobe_shader;
@@ -211,6 +253,7 @@ private:
 		GI_PROBE_DEBUG_COLOR,
 		GI_PROBE_DEBUG_LIGHT,
 		GI_PROBE_DEBUG_EMISSION,
+		GI_PROBE_DEBUG_LIGHT_FULL,
 		GI_PROBE_DEBUG_MAX
 	};
 
@@ -220,6 +263,8 @@ private:
 		float dynamic_range;
 		float alpha;
 		uint32_t level;
+		int32_t bounds[3];
+		uint32_t pad;
 	};
 
 	GiprobeDebugShaderRD giprobe_debug_shader;
@@ -662,7 +707,8 @@ public:
 	RID gi_probe_instance_create(RID p_base);
 	void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
 	bool gi_probe_needs_update(RID p_probe) const;
-	void gi_probe_update(RID p_probe, const Vector<RID> &p_light_instances);
+	void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects);
+
 	_FORCE_INLINE_ uint32_t gi_probe_instance_get_slot(RID p_probe) {
 		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
 		return gi_probe->slot;
@@ -726,6 +772,8 @@ public:
 
 	void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
 
+	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 set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; }
 	_FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; }
 

+ 198 - 135
servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp

@@ -3558,41 +3558,19 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
 
 	bool data_version_changed = false;
 
-	if (gi_probe->octree_buffer_size != p_octree_cells.size() || gi_probe->data_buffer_size != p_data_cells.size()) {
-		//buffer size changed, clear if needed
-		if (gi_probe->octree_buffer.is_valid()) {
-			RD::get_singleton()->free(gi_probe->octree_buffer);
-			RD::get_singleton()->free(gi_probe->data_buffer);
-
-			gi_probe->octree_buffer = RID();
-			gi_probe->data_buffer = RID();
-			gi_probe->octree_buffer_size = 0;
-			gi_probe->data_buffer_size = 0;
-			gi_probe->cell_count = 0;
+	if (gi_probe->octree_buffer.is_valid()) {
+		RD::get_singleton()->free(gi_probe->octree_buffer);
+		RD::get_singleton()->free(gi_probe->data_buffer);
+		if (gi_probe->sdf_texture.is_valid()) {
+			RD::get_singleton()->free(gi_probe->sdf_texture);
 		}
 
-		data_version_changed = true;
-
-	} else if (gi_probe->octree_buffer_size) {
-		//they are the same and size did not change..
-		//update
-
-		PoolVector<uint8_t>::Read rc = p_octree_cells.read();
-		PoolVector<uint8_t>::Read rd = p_data_cells.read();
-
-		RD::get_singleton()->buffer_update(gi_probe->octree_buffer, 0, gi_probe->octree_buffer_size, rc.ptr());
-		RD::get_singleton()->buffer_update(gi_probe->data_buffer, 0, gi_probe->data_buffer_size, rd.ptr());
-	}
-
-	if (gi_probe->level_counts.size() != p_level_counts.size()) {
-		data_version_changed = true;
-	} else {
-		for (int i = 0; i < p_level_counts.size(); i++) {
-			if (gi_probe->level_counts[i] != p_level_counts[i]) {
-				data_version_changed = true;
-				break;
-			}
-		}
+		gi_probe->sdf_texture = RID();
+		gi_probe->octree_buffer = RID();
+		gi_probe->data_buffer = RID();
+		gi_probe->octree_buffer_size = 0;
+		gi_probe->data_buffer_size = 0;
+		gi_probe->cell_count = 0;
 	}
 
 	gi_probe->to_cell_xform = p_to_cell_xform;
@@ -3600,7 +3578,7 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
 	gi_probe->octree_size = p_octree_size;
 	gi_probe->level_counts = p_level_counts;
 
-	if (p_octree_cells.size() && gi_probe->octree_buffer.is_null()) {
+	if (p_octree_cells.size()) {
 		ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32
 
 		uint32_t cell_count = p_octree_cells.size() / 32;
@@ -3612,13 +3590,80 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t
 		gi_probe->octree_buffer_size = p_octree_cells.size();
 		gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
 		gi_probe->data_buffer_size = p_data_cells.size();
-		data_version_changed = true;
+
+		{
+			{
+				RD::TextureFormat tf;
+				tf.format = RD::DATA_FORMAT_R8_UNORM;
+				tf.width = gi_probe->octree_size.x;
+				tf.height = gi_probe->octree_size.y;
+				tf.depth = gi_probe->octree_size.z;
+				tf.type = RD::TEXTURE_TYPE_3D;
+				tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+				tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM);
+				tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT);
+				gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			}
+			RID shared_tex;
+			{
+
+				RD::TextureView tv;
+				tv.format_override = RD::DATA_FORMAT_R8_UINT;
+				shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture);
+			}
+			//update SDF texture
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.binding = 1;
+				u.ids.push_back(gi_probe->octree_buffer);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.binding = 2;
+				u.ids.push_back(gi_probe->data_buffer);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.type = RD::UNIFORM_TYPE_IMAGE;
+				u.binding = 3;
+				u.ids.push_back(shared_tex);
+				uniforms.push_back(u);
+			}
+
+			RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0);
+
+			{
+				uint32_t push_constant[4] = { 0, 0, 0, 0 };
+
+				for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) {
+					push_constant[0] += gi_probe->level_counts[i];
+				}
+				push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1];
+
+				print_line("offset: " + itos(push_constant[0]));
+				print_line("size: " + itos(push_constant[1]));
+				//create SDF
+				RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline);
+				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
+				RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4);
+				RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4);
+				RD::get_singleton()->compute_list_end();
+			}
+
+			RD::get_singleton()->free(uniform_set);
+			RD::get_singleton()->free(shared_tex);
+		}
 	}
 
 	gi_probe->version++;
-	if (data_version_changed) {
-		gi_probe->data_version++;
-	}
+	gi_probe->data_version++;
+
 	gi_probe->instance_dependency.instance_notify_changed(true, false);
 }
 
@@ -3794,6 +3839,13 @@ RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
 	return gi_probe->data_buffer;
 }
 
+RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, RID());
+
+	return gi_probe->sdf_texture;
+}
+
 /* RENDER TARGET API */
 
 void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
@@ -4583,110 +4635,121 @@ RasterizerStorageRD::RasterizerStorageRD() {
 	{
 
 		{ //vertex
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(float) * 3);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				float *fptr = (float *)w.ptr();
-				fptr[0] = 0.0;
-				fptr[1] = 0.0;
-				fptr[2] = 0.0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
 
-		{ //normal
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(float) * 3);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				float *fptr = (float *)w.ptr();
-				fptr[0] = 1.0;
-				fptr[1] = 0.0;
-				fptr[2] = 0.0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
+				PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(float) * 3);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		float *fptr = (float *)w.ptr();
+		fptr[0] = 0.0;
+		fptr[1] = 0.0;
+		fptr[2] = 0.0;
+	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
 
-		{ //tangent
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(float) * 4);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				float *fptr = (float *)w.ptr();
-				fptr[0] = 1.0;
-				fptr[1] = 0.0;
-				fptr[2] = 0.0;
-				fptr[3] = 0.0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
+{ //normal
+	PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(float) * 3);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		float *fptr = (float *)w.ptr();
+		fptr[0] = 1.0;
+		fptr[1] = 0.0;
+		fptr[2] = 0.0;
+	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
 
-		{ //color
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(float) * 4);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				float *fptr = (float *)w.ptr();
-				fptr[0] = 1.0;
-				fptr[1] = 1.0;
-				fptr[2] = 1.0;
-				fptr[3] = 1.0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
+{ //tangent
+	PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(float) * 4);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		float *fptr = (float *)w.ptr();
+		fptr[0] = 1.0;
+		fptr[1] = 0.0;
+		fptr[2] = 0.0;
+		fptr[3] = 0.0;
+	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
 
-		{ //tex uv 1
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(float) * 2);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				float *fptr = (float *)w.ptr();
-				fptr[0] = 0.0;
-				fptr[1] = 0.0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
-		{ //tex uv 2
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(float) * 2);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				float *fptr = (float *)w.ptr();
-				fptr[0] = 0.0;
-				fptr[1] = 0.0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
+{ //color
+	PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(float) * 4);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		float *fptr = (float *)w.ptr();
+		fptr[0] = 1.0;
+		fptr[1] = 1.0;
+		fptr[2] = 1.0;
+		fptr[3] = 1.0;
+	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
 
-		{ //bones
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(uint32_t) * 4);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				uint32_t *fptr = (uint32_t *)w.ptr();
-				fptr[0] = 0;
-				fptr[1] = 0;
-				fptr[2] = 0;
-				fptr[3] = 0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
+{ //tex uv 1
+	PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(float) * 2);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		float *fptr = (float *)w.ptr();
+		fptr[0] = 0.0;
+		fptr[1] = 0.0;
+	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+{ //tex uv 2
+	PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(float) * 2);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		float *fptr = (float *)w.ptr();
+		fptr[0] = 0.0;
+		fptr[1] = 0.0;
+	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
 
-		{ //weights
-			PoolVector<uint8_t> buffer;
-			buffer.resize(sizeof(float) * 4);
-			{
-				PoolVector<uint8_t>::Write w = buffer.write();
-				float *fptr = (float *)w.ptr();
-				fptr[0] = 0.0;
-				fptr[1] = 0.0;
-				fptr[2] = 0.0;
-				fptr[3] = 0.0;
-			}
-			mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-		}
+{ //bones
+	PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(uint32_t) * 4);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		uint32_t *fptr = (uint32_t *)w.ptr();
+		fptr[0] = 0;
+		fptr[1] = 0;
+		fptr[2] = 0;
+		fptr[3] = 0;
 	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //weights
+	PoolVector<uint8_t> buffer;
+	buffer.resize(sizeof(float) * 4);
+	{
+		PoolVector<uint8_t>::Write w = buffer.write();
+		float *fptr = (float *)w.ptr();
+		fptr[0] = 0.0;
+		fptr[1] = 0.0;
+		fptr[2] = 0.0;
+		fptr[3] = 0.0;
+	}
+	mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+}
+
+{
+	Vector<String> sdf_versions;
+	sdf_versions.push_back(""); //one only
+	giprobe_sdf_shader.initialize(sdf_versions);
+	giprobe_sdf_shader_version = giprobe_sdf_shader.version_create();
+	giprobe_sdf_shader.version_set_compute_code(giprobe_sdf_shader_version, "", "", "", Vector<String>());
+	giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0);
+	giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader);
+}
 }
 
 RasterizerStorageRD::~RasterizerStorageRD() {

+ 9 - 0
servers/visual/rasterizer_rd/rasterizer_storage_rd.h

@@ -35,6 +35,7 @@
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer_rd/rasterizer_effects_rd.h"
 #include "servers/visual/rasterizer_rd/shader_compiler_rd.h"
+#include "servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h"
 #include "servers/visual/rendering_device.h"
 
 class RasterizerStorageRD : public RasterizerStorage {
@@ -407,6 +408,7 @@ private:
 
 		RID octree_buffer;
 		RID data_buffer;
+		RID sdf_texture;
 
 		uint32_t octree_buffer_size = 0;
 		uint32_t data_buffer_size = 0;
@@ -435,6 +437,11 @@ private:
 		RasterizerScene::InstanceDependency instance_dependency;
 	};
 
+	GiprobeSdfShaderRD giprobe_sdf_shader;
+	RID giprobe_sdf_shader_version;
+	RID giprobe_sdf_shader_version_shader;
+	RID giprobe_sdf_shader_pipeline;
+
 	mutable RID_Owner<GIProbe> gi_probe_owner;
 
 	/* RENDER TARGET */
@@ -999,6 +1006,8 @@ public:
 	RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
 	RID gi_probe_get_data_buffer(RID p_gi_probe) const;
 
+	RID gi_probe_get_sdf_texture(RID p_gi_probe);
+
 	/* LIGHTMAP CAPTURE */
 
 	void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}

+ 2 - 0
servers/visual/rasterizer_rd/shaders/SCsub

@@ -13,4 +13,6 @@ if 'RD_GLSL' in env['BUILDERS']:
     env.RD_GLSL('copy.glsl');
     env.RD_GLSL('giprobe.glsl');
     env.RD_GLSL('giprobe_debug.glsl');
+    env.RD_GLSL('giprobe_sdf.glsl');
+    
 

+ 345 - 80
servers/visual/rasterizer_rd/shaders/giprobe.glsl

@@ -4,8 +4,18 @@
 
 VERSION_DEFINES
 
+#ifdef MODE_DYNAMIC
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+#else
+
 layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
 
+#endif
+
+#ifndef MODE_DYNAMIC
+
 #define NO_CHILDREN 0xFFFFFFFF
 #define GREY_VEC vec3(0.33333,0.33333,0.33333)
 
@@ -28,11 +38,14 @@ layout(set=0,binding=2,std430) buffer CellDataBuffer {
     CellData data[];
 } cell_data;
 
+
+#endif // MODE DYNAMIC
+
 #define LIGHT_TYPE_DIRECTIONAL 0
 #define LIGHT_TYPE_OMNI 1
 #define LIGHT_TYPE_SPOT 2
 
-#ifdef MODE_COMPUTE_LIGHT
+#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING)
 
 struct Light {
 
@@ -64,7 +77,6 @@ layout(set=0,binding=3,std140) uniform Lights {
 #ifdef MODE_SECOND_BOUNCE
 
 layout (set=0,binding=5) uniform texture3D color_texture;
-layout (set=0,binding=6) uniform sampler texture_sampler;
 
 #ifdef MODE_ANISOTROPIC
 layout (set=0,binding=7) uniform texture3D aniso_pos_texture;
@@ -73,6 +85,7 @@ layout (set=0,binding=8) uniform texture3D aniso_neg_texture;
 
 #endif // MODE_SECOND_BOUNCE
 
+#ifndef MODE_DYNAMIC
 
 layout(push_constant, binding = 0, std430) uniform Params {
 
@@ -96,6 +109,11 @@ layout(set=0,binding=4,std430) buffer Outputs {
     vec4 data[];
 } outputs;
 
+#endif // MODE DYNAMIC
+
+layout (set=0,binding=9) uniform texture3D texture_sdf;
+layout (set=0,binding=10) uniform sampler texture_sampler;
+
 #ifdef MODE_WRITE_TEXTURE
 
 layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
@@ -111,63 +129,97 @@ layout (r16ui,set=0,binding=7) uniform restrict writeonly uimage3D aniso_neg_tex
 #endif
 
 
-#ifdef MODE_COMPUTE_LIGHT
+#ifdef MODE_DYNAMIC
 
-uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
+layout(push_constant, binding = 0, std430) uniform Params {
 
-	uint result = NO_CHILDREN;
+	ivec3 limits;
+	uint light_count;
+	ivec3 x_dir;
+	float z_base;
+	ivec3 y_dir;
+	float z_sign;
+	ivec3 z_dir;
+	float pos_multiplier;
+	ivec2 rect_pos;
+	ivec2 rect_size;
+	ivec2 prev_rect_ofs;
+	ivec2 prev_rect_size;
+	bool flip_x;
+	bool flip_y;
+	float dynamic_range;
+	bool keep_downsample_color;
 
-	ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z));
+} params;
 
-	while (distance > -distance_adv) { //use this to avoid precision errors
+#ifdef MODE_DYNAMIC_LIGHTING
 
-		uint cell = 0;
+layout (rgba8,set=0,binding=5) uniform restrict readonly image2D source_albedo;
+layout (rgba8,set=0,binding=6) uniform restrict readonly image2D source_normal;
+layout (rgba8,set=0,binding=7) uniform restrict readonly image2D source_orm;
+//layout (set=0,binding=8) uniform texture2D source_depth;
+layout (rgba16f,set=0,binding=11) uniform restrict image2D emission;
+layout (r32f,set=0,binding=12) uniform restrict image2D depth;
 
-		ivec3 pos = ivec3(from);
+#endif
 
-		if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) {
+#ifdef MODE_DYNAMIC_SHRINK
 
-			ivec3 ofs = ivec3(0);
-			ivec3 half_size = size / 2;
+layout (rgba16f,set=0,binding=5) uniform restrict readonly image2D source_light;
+layout (r32f,set=0,binding=6) uniform restrict readonly image2D source_depth;
 
-			for (int i = 0; i < params.stack_size - 1; i++) {
+#ifdef MODE_DYNAMIC_SHRINK_WRITE
 
-				bvec3 greater = greaterThanEqual(pos,ofs+half_size);
+layout (rgba16f,set=0,binding=7) uniform restrict writeonly image2D light;
+layout (r32f,set=0,binding=8) uniform restrict writeonly image2D depth;
 
-				ofs += mix(ivec3(0),half_size,greater);
+#endif // MODE_DYNAMIC_SHRINK_WRITE
 
-				uint child = 0; //wonder if this can be done faster
-				if (greater.x) {
-					child|=1;
-				}
-				if (greater.y) {
-					child|=2;
-				}
-				if (greater.z) {
-					child|=4;
-				}
+#ifdef MODE_DYNAMIC_SHRINK_PLOT
 
-				cell = cell_children.data[cell].children[child];
-				if (cell == NO_CHILDREN)
-					break;
+layout (rgba8,set=0,binding=11) uniform restrict image3D color_texture;
 
-				half_size >>= ivec3(1);
-			}
+#ifdef MODE_ANISOTROPIC
+
+layout (r16ui,set=0,binding=12) uniform restrict writeonly uimage3D aniso_pos_texture;
+layout (r16ui,set=0,binding=13) uniform restrict writeonly uimage3D aniso_neg_texture;
+
+#endif // MODE ANISOTROPIC
+
+#endif //MODE_DYNAMIC_SHRINK_PLOT
+
+#endif // MODE_DYNAMIC_SHRINK
+
+//layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
+
+
+#endif // MODE DYNAMIC
+
+#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING)
+
+float raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
 
-			if ( cell != NO_CHILDREN) {
-				return cell; //found cell!
-			}
 
+
+	vec3 cell_size = 1.0 / vec3(params.limits);
+
+	while (distance > 0.0) { //use this to avoid precision errors
+		float advance = texture(sampler3D(texture_sdf,texture_sampler),from * cell_size).r * 255.0 - 1.0;
+		if (advance<0.0) {
+			break;
 		}
 
-		from += direction * distance_adv;
-		distance -= distance_adv;
+		advance = max(distance_adv, advance - mod(advance, distance_adv)); //should always advance in multiples of distance_adv
+
+		from += direction * advance;
+		distance -= advance;
 	}
 
-	return NO_CHILDREN;
+	return max(0.0,distance);
+
 }
 
-bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
+bool compute_light_vector(uint light, vec3 pos,out float attenuation, out vec3 light_pos) {
 
 
 	if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
@@ -226,13 +278,84 @@ float get_normal_advance(vec3 p_normal) {
 	return 1.0 / dot(normal,unorm);
 }
 
-#endif
 
 
 
+void clip_segment(vec4 plane, vec3 begin, inout vec3 end) {
+
+	vec3 segment = begin - end;
+	float den = dot(plane.xyz,segment);
+
+	//printf("den is %i\n",den);
+	if (den < 0.0001) {
+		return;
+	}
+
+	float dist = (dot(plane.xyz,begin) - plane.w) / den;
+
+	if (dist < 0.0001 || dist > 1.0001) {
+		return;
+	}
+
+	end = begin + segment * -dist;
+}
+
+bool compute_light_at_pos(uint index, vec3 pos, vec3 normal, inout vec3 light, inout vec3 light_dir) {
+	float attenuation;
+	vec3 light_pos;
+
+	if (!compute_light_vector(index,pos,attenuation,light_pos)) {
+		return false;
+	}
+
+	light_dir = normalize(pos - light_pos);
+
+	if (attenuation < 0.01 || (length(normal) > 0.2 && dot(normal,light_dir)>=0)) {
+		return false; //not facing the light, or attenuation is near zero
+	}
+
+	if (lights.data[index].has_shadow) {
+
+		float distance_adv = get_normal_advance(light_dir);
+
+
+		vec3 to = pos;
+		to-= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
+
+		//clip
+		clip_segment(mix(vec4(-1.0,0.0,0.0,0.0),vec4(1.0,0.0,0.0,float(params.limits.x-1)),bvec4(light_dir.x < 0.0)),to,light_pos);
+		clip_segment(mix(vec4(0.0,-1.0,0.0,0.0),vec4(0.0,1.0,0.0,float(params.limits.y-1)),bvec4(light_dir.y < 0.0)),to,light_pos);
+		clip_segment(mix(vec4(0.0,0.0,-1.0,0.0),vec4(0.0,0.0,1.0,float(params.limits.z-1)),bvec4(light_dir.z < 0.0)),to,light_pos);
+
+
+		float distance = length(to-light_pos);
+		if (distance < 0.1) {
+			return false; // hit
+		}
+
+		distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always
+		light_pos = to - light_dir * distance;
+
+		//from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
+		float dist = raymarch(distance,distance_adv,light_pos,light_dir);
+
+		if (dist > distance_adv) {
+			return false;
+		}
+
+
+	}
+
+	light = lights.data[index].color * attenuation * lights.data[index].energy;
+	return true;
+}
+
+#endif // MODE COMPUTE LIGHT
 
 void main() {
 
+#ifndef MODE_DYNAMIC
+
 	uint cell_index = gl_GlobalInvocationID.x;;
 	if (cell_index >= params.cell_count) {
 		return;
@@ -242,6 +365,8 @@ void main() {
 	uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21);
 	vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo);
 
+#endif
+
 /////////////////COMPUTE LIGHT///////////////////////////////
 
 #ifdef MODE_COMPUTE_LIGHT
@@ -249,7 +374,7 @@ void main() {
 	vec3 pos = vec3(posu) + vec3(0.5);
 
 	vec3 emission = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
-	vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+	vec3 normal = unpackSnorm4x8(cell_data.data[cell_index].normal).xyz;
 
 #ifdef MODE_ANISOTROPIC
 	vec3 accum[6]=vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
@@ -260,41 +385,13 @@ void main() {
 
 	for(uint i=0;i<params.light_count;i++) {
 
-		float attenuation;
-		vec3 light_pos;
-
-		if (!compute_light_vector(i,cell_index,pos,attenuation,light_pos)) {
+		vec3 light;
+		vec3 light_dir;
+		if (!compute_light_at_pos(i,pos,normal.xyz,light,light_dir)) {
 			continue;
 		}
 
-		vec3 light_dir = pos - light_pos;
-		float distance = length(light_dir);
-		light_dir=normalize(light_dir);
-
-		if (attenuation < 0.01 || (length(normal.xyz) > 0.2 && dot(normal.xyz,light_dir)>=0)) {
-			continue; //not facing the light, or attenuation is near zero
-		}
-
-		if (lights.data[i].has_shadow) {
-
-			float distance_adv = get_normal_advance(light_dir);
-
-
-			distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always
-
-			vec3 from = pos - light_dir * distance; //approximate
-			from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion
-
-
-
-			uint result = raymarch(distance,distance_adv,from,light_dir);
-
-			if (result != cell_index) {
-				continue; //was occluded
-			}
-		}
-
-		vec3 light = lights.data[i].color * albedo.rgb * attenuation * lights.data[i].energy;
+		light*= albedo.rgb;
 
 #ifdef MODE_ANISOTROPIC
 		for(uint j=0;j<6;j++) {
@@ -302,11 +399,11 @@ void main() {
 			accum[j]+=max(0.0,dot(accum_dirs[j],-light_dir))*light;
 		}
 #else
-		if (length(normal.xyz) > 0.2) {
-			accum+=max(0.0,dot(normal.xyz,-light_dir))*light;
+		if (length(normal) > 0.2) {
+			accum+=max(0.0,dot(normal,-light_dir))*light;
 		} else {
 			//all directions
-			accum+=light+emission;
+			accum+=light;
 		}
 #endif
 	}
@@ -314,12 +411,17 @@ void main() {
 
 #ifdef MODE_ANISOTROPIC
 
-	outputs.data[cell_index*6+0]=vec4(accum[0] + emission,0.0);
-	outputs.data[cell_index*6+1]=vec4(accum[1] + emission,0.0);
-	outputs.data[cell_index*6+2]=vec4(accum[2] + emission,0.0);
-	outputs.data[cell_index*6+3]=vec4(accum[3] + emission,0.0);
-	outputs.data[cell_index*6+4]=vec4(accum[4] + emission,0.0);
-	outputs.data[cell_index*6+5]=vec4(accum[5] + emission,0.0);
+	for(uint i=0;i<6;i++) {
+		vec3 light = accum[i];
+		if (length(normal) > 0.2) {
+			light += max(0.0,dot(accum_dirs[i],-normal)) * emission;
+		} else {
+			light += emission;
+		}
+
+		outputs.data[cell_index*6+i] = vec4(light,0.0);
+	}
+
 #else
 	outputs.data[cell_index]=vec4(accum + emission,0.0);
 
@@ -540,4 +642,167 @@ void main() {
 
 	}
 #endif
+
+///////////////////DYNAMIC LIGHTING/////////////////////////////
+
+#ifdef MODE_DYNAMIC
+
+	ivec2 pos_xy = ivec2(gl_GlobalInvocationID.xy);
+	if (any(greaterThanEqual(pos_xy,params.rect_size))) {
+		return; //out of bounds
+	}
+
+	ivec2 uv_xy = pos_xy;
+	if (params.flip_x) {
+		uv_xy.x = params.rect_size.x - pos_xy.x - 1;
+	}
+	if (params.flip_y) {
+		uv_xy.y = params.rect_size.y - pos_xy.y - 1;
+	}
+
+
+#ifdef MODE_DYNAMIC_LIGHTING
+
+
+	{
+
+
+		float z = params.z_base + imageLoad(depth,uv_xy).x * params.z_sign;
+
+		ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) +  abs(params.z_dir) * int(z);
+
+		vec3 normal = imageLoad(source_normal,uv_xy).xyz * 2.0 - 1.0;
+		normal = vec3(params.x_dir) * normal.x * mix(1.0,-1.0,params.flip_x) + vec3(params.y_dir) * normal.y * mix(1.0,-1.0,params.flip_y) - vec3(params.z_dir) * normal.z;
+
+
+
+
+		vec4 albedo = imageLoad(source_albedo,uv_xy);
+
+		//determine the position in space
+
+		vec3 accum = vec3(0.0);
+		for(uint i=0;i<params.light_count;i++) {
+
+			vec3 light;
+			vec3 light_dir;
+			if (!compute_light_at_pos(i,vec3(pos) * params.pos_multiplier,normal,light,light_dir)) {
+				continue;
+			}
+
+			light*= albedo.rgb;
+
+			accum+=max(0.0,dot(normal,-light_dir))*light;
+
+		}
+
+		accum+=imageLoad(emission,uv_xy).xyz;
+
+		imageStore(emission,uv_xy,vec4(accum,albedo.a));
+		imageStore(depth,uv_xy,vec4(z));
+
+	}
+
+#endif // MODE DYNAMIC LIGHTING
+
+#ifdef MODE_DYNAMIC_SHRINK
+
+	{
+		vec4 accum = vec4(0.0);
+		float accum_z = 0.0;
+		float count = 0.0;
+
+		for(int i=0;i<4;i++) {
+			ivec2 ofs = pos_xy*2 + ivec2(i&1,i>>1) - params.prev_rect_ofs;
+			if (any(lessThan(ofs,ivec2(0))) || any(greaterThanEqual(ofs,params.prev_rect_size))) {
+				continue;
+			}
+			if (params.flip_x) {
+				ofs.x = params.prev_rect_size.x - ofs.x - 1;
+			}
+			if (params.flip_y) {
+				ofs.y = params.prev_rect_size.y - ofs.y - 1;
+			}
+
+			vec4 light = imageLoad(source_light,ofs);
+			if (light.a==0.0) { //ignore empty
+				continue;
+			}
+			accum += light;
+			float z = imageLoad(source_depth,ofs).x;
+			accum_z += z*0.5; //shrink half too
+			count+=1.0;
+		}
+
+
+		accum/=4.0;
+
+		if (count==0.0) {
+			accum_z=0.0; //avoid nan
+		} else {
+			accum_z/=count;
+		}
+
+#ifdef MODE_DYNAMIC_SHRINK_WRITE
+
+		imageStore(light,uv_xy,accum);
+		imageStore(depth,uv_xy,vec4(accum_z));
+#endif
+
+#ifdef MODE_DYNAMIC_SHRINK_PLOT
+
+
+		if (accum.a<0.001) {
+			return; //do not blit if alpha is too low
+		}
+
+		ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) +  abs(params.z_dir) * int(accum_z);
+
+		float z_frac = fract(accum_z);
+
+		for(int i = 0; i< 2; i++) {
+			ivec3 pos3d = pos + abs(params.z_dir) * i;
+			if (any(lessThan(pos3d,ivec3(0))) || any(greaterThanEqual(pos3d,params.limits))) {
+				//skip if offlimits
+				continue;
+			}
+			vec4 color_blit = accum * (i==0 ? 1.0 - z_frac : z_frac );
+			vec4 color = imageLoad(color_texture,pos3d);
+			color.rgb *=params.dynamic_range;
+
+#if 0
+			color.rgb = mix(color.rgb,color_blit.rgb,color_blit.a);
+			color.a+=color_blit.a;
+#else
+
+
+			float sa = 1.0 - color_blit.a;
+			vec4 result;
+			result.a = color.a * sa + color_blit.a;
+			if (result.a==0.0) {
+				result = vec4(0.0);
+			} else {
+				result.rgb = (color.rgb * color.a * sa + color_blit.rgb * color_blit.a) / result.a;
+				color = result;
+			}
+
+#endif
+			color.rgb /= params.dynamic_range;
+			imageStore(color_texture,pos3d,color);
+			//imageStore(color_texture,pos3d,vec4(1,1,1,1));
+
+#ifdef MODE_ANISOTROPIC
+			//do not care about anisotropy for dynamic objects, just store full lit in all directions
+			imageStore(aniso_pos_texture,pos3d,uvec4(0xFFFF));
+			imageStore(aniso_neg_texture,pos3d,uvec4(0xFFFF));
+
+#endif // ANISOTROPIC
+		}
+#endif // MODE_DYNAMIC_SHRINK_PLOT
+
+
+	}
+#endif
+
+#endif // MODE DYNAMIC
 }

+ 47 - 3
servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl

@@ -32,6 +32,8 @@ layout(push_constant, binding = 0, std430) uniform Params {
 	float dynamic_range;
 	float alpha;
 	uint level;
+	ivec3 bounds;
+	uint pad;
 
 } params;
 
@@ -80,10 +82,13 @@ void main() {
 
 
 	vec3 vertex = cube_triangles[gl_VertexIndex] * 0.5 + 0.5;
-
+#ifdef MODE_DEBUG_LIGHT_FULL
+	uvec3 posu = uvec3( gl_InstanceIndex % params.bounds.x, (gl_InstanceIndex  / params.bounds.x) % params.bounds.y,gl_InstanceIndex / (params.bounds.y * params.bounds.x)  );
+#else
 	uint cell_index = gl_InstanceIndex + params.cell_offset;
 
 	uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21);
+#endif
 
 #ifdef MODE_DEBUG_EMISSION
 	color_interp.xyz = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0);
@@ -138,16 +143,24 @@ void main() {
 	color_interp.xyz *= strength;
 
 #else
-	color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).xyz * params.dynamic_range;
+	color_interp = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level));
+	color_interp.xyz * params.dynamic_range;
 
 #endif
 
 #endif
 	float scale = (1<<params.level);
-	color_interp.a = params.alpha;
 
 	gl_Position = params.projection * vec4((vec3(posu)+vertex)*scale,1.0);
 
+#ifdef MODE_DEBUG_LIGHT_FULL
+	if (color_interp.a == 0.0) {
+		gl_Position = vec4(0.0); //force clip and not draw
+	}
+#else
+	color_interp.a = params.alpha;
+#endif
+
 }
 
 [fragment]
@@ -162,4 +175,35 @@ layout(location=0) out vec4 frag_color;
 void main() {
 
 	frag_color = color_interp;
+
+#ifdef MODE_DEBUG_LIGHT_FULL
+
+	//there really is no alpha, so use dither
+
+	int x = int(gl_FragCoord.x) % 4;
+	int y = int(gl_FragCoord.y) % 4;
+	int index = x + y * 4;
+	float limit = 0.0;
+	if (x < 8) {
+		if (index == 0) limit = 0.0625;
+		if (index == 1) limit = 0.5625;
+		if (index == 2) limit = 0.1875;
+		if (index == 3) limit = 0.6875;
+		if (index == 4) limit = 0.8125;
+		if (index == 5) limit = 0.3125;
+		if (index == 6) limit = 0.9375;
+		if (index == 7) limit = 0.4375;
+		if (index == 8) limit = 0.25;
+		if (index == 9) limit = 0.75;
+		if (index == 10) limit = 0.125;
+		if (index == 11) limit = 0.625;
+		if (index == 12) limit = 1.0;
+		if (index == 13) limit = 0.5;
+		if (index == 14) limit = 0.875;
+		if (index == 15) limit = 0.375;
+	}
+	if (frag_color.a < limit) {
+		discard;
+	}
+#endif
 }

+ 194 - 0
servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl

@@ -0,0 +1,194 @@
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
+
+#define MAX_DISTANCE 100000
+
+#define NO_CHILDREN 0xFFFFFFFF
+#define GREY_VEC vec3(0.33333,0.33333,0.33333)
+
+struct CellChildren {
+	uint children[8];
+};
+
+layout(set=0,binding=1,std430) buffer CellChildrenBuffer {
+    CellChildren data[];
+} cell_children;
+
+
+struct CellData {
+	uint position; // xyz 10 bits
+	uint albedo; //rgb albedo
+	uint emission; //rgb normalized with e as multiplier
+	uint normal; //RGB normal encoded
+};
+
+layout(set=0,binding=2,std430) buffer CellDataBuffer {
+    CellData data[];
+} cell_data;
+
+layout (r8ui,set=0,binding=3) uniform restrict writeonly uimage3D sdf_tex;
+
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+	uint offset;
+	uint end;
+	uint pad0;
+	uint pad1;
+} params;
+
+void main() {
+
+	vec3 pos = vec3(gl_GlobalInvocationID);
+	float closest_dist = 100000.0;
+
+	for(uint i=params.offset;i<params.end;i++) {
+		vec3 posu = vec3(uvec3(cell_data.data[i].position&0x7FF,(cell_data.data[i].position>>11)&0x3FF,cell_data.data[i].position>>21));
+		float dist = length(pos-posu);
+		if (dist < closest_dist) {
+			closest_dist = dist;
+		}
+	}
+
+	uint dist_8;
+
+	if (closest_dist<0.0001) { // same cell
+		dist_8=0; //equals to -1
+	} else {
+		dist_8 = clamp(uint(closest_dist),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid
+	}
+
+	imageStore(sdf_tex,ivec3(gl_GlobalInvocationID),uvec4(dist_8));
+	//imageStore(sdf_tex,pos,uvec4(pos*2,0));
+}
+
+
+#if 0
+layout(push_constant, binding = 0, std430) uniform Params {
+
+	ivec3 limits;
+	uint stack_size;
+} params;
+
+
+float distance_to_aabb(ivec3 pos, ivec3 aabb_pos, ivec3 aabb_size) {
+
+	vec3 delta = vec3(max(ivec3(0),max(aabb_pos - pos, pos - (aabb_pos + aabb_size - ivec3(1)))));
+	return length(delta);
+}
+
+void main() {
+
+	ivec3 pos = ivec3(gl_GlobalInvocationID);
+
+	uint stack[10]=uint[](0,0,0,0,0,0,0,0,0,0);
+	uint stack_indices[10]=uint[](0,0,0,0,0,0,0,0,0,0);
+	ivec3 stack_positions[10]=ivec3[](ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0));
+
+	const uint cell_orders[8]=uint[](
+		0x11f58d1,
+		0xe2e70a,
+		0xd47463,
+		0xbb829c,
+		0x8d11f5,
+		0x70ae2e,
+		0x463d47,
+		0x29cbb8
+	);
+
+	bool cell_found = false;
+	bool cell_found_exact = false;
+	ivec3 closest_cell_pos;
+	float closest_distance = MAX_DISTANCE;
+	int stack_pos = 0;
+
+	while(true) {
+
+		uint index = stack_indices[stack_pos]>>24;
+
+		if (index == 8) {
+			//go up
+			if (stack_pos==0) {
+				break; //done going through octree
+			}
+			stack_pos--;
+			continue;
+		}
+
+		stack_indices[stack_pos] = (stack_indices[stack_pos]&((1<<24)-1))|((index + 1)<<24);
+
+
+		uint cell_index = (stack_indices[stack_pos]>>(index*3))&0x7;
+		uint child_cell = cell_children.data[stack[stack_pos]].children[cell_index];
+
+		if (child_cell == NO_CHILDREN) {
+			continue;
+		}
+
+		ivec3 child_cell_size = params.limits >> (stack_pos+1);
+		ivec3 child_cell_pos = stack_positions[stack_pos];
+
+		child_cell_pos+=mix(ivec3(0),child_cell_size,bvec3(uvec3(index&1,index&2,index&4)!=uvec3(0)));
+
+		bool is_leaf = stack_pos == (params.stack_size-2);
+
+		if (child_cell_pos==pos && is_leaf) {
+			//we may actually end up in the exact cell.
+			//if this happens, just abort
+			cell_found_exact=true;
+			break;
+		}
+
+		if (cell_found) {
+			//discard by distance
+			float distance = distance_to_aabb(pos,child_cell_pos,child_cell_size);
+			if (distance >= closest_distance) {
+				continue; //pointless, just test next child
+			} else if (is_leaf) {
+				//closer than what we have AND end of stack, save and continue
+				closest_cell_pos = child_cell_pos;
+				closest_distance = distance;
+				continue;
+			}
+		} else if (is_leaf) {
+			//first solid cell we find, save and continue
+			closest_distance = distance_to_aabb(pos,child_cell_pos,child_cell_size);
+			closest_cell_pos = child_cell_pos;
+			cell_found=true;
+			continue;
+		}
+
+
+
+
+		bvec3 direction = greaterThan(( pos - ( child_cell_pos + (child_cell_size >>1) ) ) , ivec3(0) );
+		uint cell_order = 0;
+		cell_order|=mix(0,1,direction.x);
+		cell_order|=mix(0,2,direction.y);
+		cell_order|=mix(0,4,direction.z);
+
+		stack[stack_pos+1]=child_cell;
+		stack_indices[stack_pos+1]=cell_orders[cell_order]; //start counting
+		stack_positions[stack_pos+1]=child_cell_pos;
+		stack_pos++; //go up stack
+
+	}
+
+	uint dist_8;
+
+	if (cell_found_exact) {
+		dist_8=0; //equals to -1
+	} else {
+		float closest_distance = length(vec3(pos-closest_cell_pos));
+		dist_8 = clamp(uint(closest_distance),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid
+	}
+
+	imageStore(sdf_tex,pos,uvec4(dist_8));
+
+}
+#endif

+ 38 - 2
servers/visual/rasterizer_rd/shaders/scene_forward.glsl

@@ -344,17 +344,30 @@ FRAGMENT_SHADER_GLOBALS
 
 /* clang-format on */
 
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+layout(location = 0) out vec4 albedo_output_buffer;
+layout(location = 1) out vec4 normal_output_buffer;
+layout(location = 2) out vec4 orm_output_buffer;
+layout(location = 3) out vec4 emission_output_buffer;
+layout(location = 4) out float depth_output_buffer;
+
+#endif
+
+#else // RENDER DEPTH
+
 #ifdef MODE_MULTIPLE_RENDER_TARGETS
 
 layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
 layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
 #else
 
-#ifndef MODE_RENDER_DEPTH
 layout(location = 0) out vec4 frag_color;
 #endif
 
-#endif
+#endif // RENDER DEPTH
 
 
 
@@ -1668,6 +1681,29 @@ FRAGMENT_SHADER_CODE
 
 
 #ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+	albedo_output_buffer.rgb = albedo;
+	albedo_output_buffer.a = alpha;
+
+	normal_output_buffer.rgb = normal * 0.5 + 0.5;
+	normal_output_buffer.a = 0.0;
+	depth_output_buffer.r = -vertex.z;
+
+#if defined(AO_USED)
+	orm_output_buffer.r = ao;
+#else
+	orm_output_buffer.r = 0.0;
+#endif
+	orm_output_buffer.g = roughness;
+	orm_output_buffer.b = metallic;
+	orm_output_buffer.a = sss_strength;
+
+	emission_output_buffer.rgb = emission;
+	emission_output_buffer.a = 0.0;
+#endif
+
 //nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
 #else
 

+ 59 - 6
servers/visual/visual_server_scene.cpp

@@ -170,7 +170,12 @@ void *VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance
 		pinfo.geometry = A;
 		pinfo.L = geom->gi_probes.push_back(B);
 
-		List<InstanceGIProbeData::PairInfo>::Element *E = gi_probe->geometries.push_back(pinfo);
+		List<InstanceGIProbeData::PairInfo>::Element *E;
+		if (A->dynamic_gi) {
+			E = gi_probe->dynamic_geometries.push_back(pinfo);
+		} else {
+			E = gi_probe->geometries.push_back(pinfo);
+		}
 
 		geom->gi_probes_dirty = true;
 
@@ -240,7 +245,11 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance
 		List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element *>(udata);
 
 		geom->gi_probes.erase(E->get().L);
-		gi_probe->geometries.erase(E);
+		if (A->dynamic_gi) {
+			gi_probe->dynamic_geometries.erase(E);
+		} else {
+			gi_probe->geometries.erase(E);
+		}
 
 		geom->gi_probes_dirty = true;
 
@@ -842,12 +851,32 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF
 	Instance *instance = instance_owner.getornull(p_instance);
 	ERR_FAIL_COND(!instance);
 
+	ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK));
+
 	switch (p_flags) {
 
 		case VS::INSTANCE_FLAG_USE_BAKED_LIGHT: {
 
 			instance->baked_light = p_enabled;
 
+		} break;
+		case VS::INSTANCE_FLAG_USE_DYNAMIC_GI: {
+
+			if (p_enabled == instance->dynamic_gi) {
+				//bye, redundant
+				return;
+			}
+
+			if (instance->octree_id != 0) {
+				//remove from octree, it needs to be re-paired
+				instance->scenario->octree.erase(instance->octree_id);
+				instance->octree_id = 0;
+				_instance_queue_update(instance, true, true);
+			}
+
+			//once out of octree, can be changed
+			instance->dynamic_gi = p_enabled;
+
 		} break;
 		case VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: {
 
@@ -2431,7 +2460,7 @@ void VisualServerScene::render_probes() {
 			cache_count = idx;
 		}
 
-		bool update_probe = VSG::scene_render->gi_probe_needs_update(probe->probe_instance);
+		bool update_lights = VSG::scene_render->gi_probe_needs_update(probe->probe_instance);
 
 		if (cache_dirty) {
 			probe->light_cache.resize(cache_count);
@@ -2490,13 +2519,37 @@ void VisualServerScene::render_probes() {
 				}
 			}
 
-			update_probe = true;
+			update_lights = true;
 		}
 
-		if (update_probe) {
-			VSG::scene_render->gi_probe_update(probe->probe_instance, probe->light_instances);
+		instance_cull_count = 0;
+		for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) {
+			if (instance_cull_count < MAX_INSTANCE_CULL) {
+				Instance *ins = E->get().geometry;
+				InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data;
+
+				if (geom->gi_probes_dirty) {
+					//giprobes may be dirty, so update
+					int l = 0;
+					//only called when reflection probe AABB enter/exit this geometry
+					ins->gi_probe_instances.resize(geom->gi_probes.size());
+
+					for (List<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) {
+
+						InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data);
+
+						ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance;
+					}
+
+					geom->gi_probes_dirty = false;
+				}
+
+				instance_cull_result[instance_cull_count++] = E->get().geometry;
+			}
 		}
 
+		VSG::scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RasterizerScene::InstanceBase **)instance_cull_result);
+
 		gi_probe_update_list.remove(gi_probe);
 
 		gi_probe = next;

+ 1 - 2
servers/visual/visual_server_scene.h

@@ -156,8 +156,6 @@ public:
 
 		SelfList<Instance> update_item;
 
-		AABB aabb;
-		AABB transformed_aabb;
 		AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better?
 		float extra_margin;
 		uint32_t object_id;
@@ -316,6 +314,7 @@ public:
 		};
 
 		List<PairInfo> geometries;
+		List<PairInfo> dynamic_geometries;
 
 		Set<Instance *> lights;
 

+ 1 - 0
servers/visual_server.h

@@ -834,6 +834,7 @@ public:
 
 	enum InstanceFlags {
 		INSTANCE_FLAG_USE_BAKED_LIGHT,
+		INSTANCE_FLAG_USE_DYNAMIC_GI,
 		INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
 		INSTANCE_FLAG_MAX
 	};