Quellcode durchsuchen

GIProbes working.

Juan Linietsky vor 5 Jahren
Ursprung
Commit
acf0f6c8a7
51 geänderte Dateien mit 5027 neuen und 5047 gelöschten Zeilen
  1. 13 0
      core/class_db.cpp
  2. 1 0
      core/class_db.h
  3. 1 1
      core/io/resource_format_binary.cpp
  4. 2 1
      core/io/resource_loader.cpp
  5. 10 0
      core/math/vector3.h
  6. 25 0
      core/math/vector3i.cpp
  7. 242 0
      core/math/vector3i.h
  8. 234 122
      drivers/vulkan/rendering_device_vulkan.cpp
  9. 28 13
      drivers/vulkan/rendering_device_vulkan.h
  10. 5 0
      drivers/vulkan/vulkan_context.cpp
  11. 1 1
      editor/editor_node.cpp
  12. 2 0
      editor/plugins/baked_lightmap_editor_plugin.cpp
  13. 2 0
      editor/plugins/baked_lightmap_editor_plugin.h
  14. 65 38
      editor/plugins/spatial_editor_plugin.cpp
  15. 8 1
      editor/plugins/spatial_editor_plugin.h
  16. 2 2
      editor/spatial_editor_gizmos.cpp
  17. 2 1
      editor/spatial_editor_gizmos.h
  18. 6 4
      scene/3d/baked_lightmap.cpp
  19. 2 0
      scene/3d/baked_lightmap.h
  20. 125 218
      scene/3d/gi_probe.cpp
  21. 33 45
      scene/3d/gi_probe.h
  22. 0 2486
      scene/3d/voxel_light_baker.cpp
  23. 1108 0
      scene/3d/voxelizer.cpp
  24. 35 81
      scene/3d/voxelizer.h
  25. 6 0
      scene/main/viewport.h
  26. 2 2
      scene/register_scene_types.cpp
  27. 22 3
      scene/resources/mesh.cpp
  28. 1 1
      scene/resources/resource_format_text.cpp
  29. 28 37
      servers/visual/rasterizer.h
  30. 2 2
      servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
  31. 8 8
      servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
  32. 274 491
      servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
  33. 28 3
      servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
  34. 556 7
      servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
  35. 170 9
      servers/visual/rasterizer_rd/rasterizer_scene_rd.h
  36. 263 2
      servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
  37. 64 31
      servers/visual/rasterizer_rd/rasterizer_storage_rd.h
  38. 2 1
      servers/visual/rasterizer_rd/shaders/SCsub
  39. 543 0
      servers/visual/rasterizer_rd/shaders/giprobe.glsl
  40. 160 0
      servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
  41. 0 241
      servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl
  42. 353 0
      servers/visual/rasterizer_rd/shaders/giprobe_write.glsl
  43. 298 4
      servers/visual/rasterizer_rd/shaders/scene_forward.glsl
  44. 59 64
      servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
  45. 11 8
      servers/visual/rendering_device.h
  46. 15 15
      servers/visual/visual_server_raster.h
  47. 152 953
      servers/visual/visual_server_scene.cpp
  48. 8 112
      servers/visual/visual_server_scene.h
  49. 15 15
      servers/visual/visual_server_wrap_mt.h
  50. 8 0
      servers/visual_server.cpp
  51. 27 24
      servers/visual_server.h

+ 13 - 0
core/class_db.cpp

@@ -335,6 +335,19 @@ StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) {
 	return ti->inherits;
 }
 
+StringName ClassDB::get_compatibility_remapped_class(const StringName &p_class) {
+
+	if (classes.has(p_class)) {
+		return p_class;
+	}
+
+	if (compat_classes.has(p_class)) {
+		return compat_classes[p_class];
+	}
+
+	return p_class;
+}
+
 StringName ClassDB::get_parent_class(const StringName &p_class) {
 
 	OBJTYPE_RLOCK;

+ 1 - 0
core/class_db.h

@@ -218,6 +218,7 @@ public:
 	static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
 	static StringName get_parent_class_nocheck(const StringName &p_class);
 	static StringName get_parent_class(const StringName &p_class);
+	static StringName get_compatibility_remapped_class(const StringName &p_class);
 	static bool class_exists(const StringName &p_class);
 	static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
 	static bool can_instance(const StringName &p_class);

+ 1 - 1
core/io/resource_format_binary.cpp

@@ -1255,7 +1255,7 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const
 	ria->res_path = ria->local_path;
 	//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
 	String r = ria->recognize(f);
-	return r;
+	return ClassDB::get_compatibility_remapped_class(r);
 }
 
 ///////////////////////////////////////////////////////////

+ 2 - 1
core/io/resource_loader.cpp

@@ -729,8 +729,9 @@ String ResourceLoader::get_resource_type(const String &p_path) {
 	for (int i = 0; i < loader_count; i++) {
 
 		String result = loader[i]->get_resource_type(local_path);
-		if (result != "")
+		if (result != "") {
 			return result;
+		}
 	}
 
 	return "";

+ 10 - 0
core/math/vector3.h

@@ -32,6 +32,7 @@
 #define VECTOR3_H
 
 #include "core/math/math_funcs.h"
+#include "core/math/vector3i.h"
 #include "core/ustring.h"
 
 class Basis;
@@ -147,6 +148,15 @@ struct Vector3 {
 	_FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const;
 
 	operator String() const;
+	_FORCE_INLINE_ operator Vector3i() const {
+		return Vector3i(x, y, z);
+	}
+
+	_FORCE_INLINE_ Vector3(const Vector3i &p_ivec) {
+		x = p_ivec.x;
+		y = p_ivec.y;
+		z = p_ivec.z;
+	}
 
 	_FORCE_INLINE_ Vector3(real_t p_x, real_t p_y, real_t p_z) {
 		x = p_x;

+ 25 - 0
core/math/vector3i.cpp

@@ -0,0 +1,25 @@
+#include "vector3i.h"
+
+void Vector3i::set_axis(int p_axis, int32_t p_value) {
+	ERR_FAIL_INDEX(p_axis, 3);
+	coord[p_axis] = p_value;
+}
+int32_t Vector3i::get_axis(int p_axis) const {
+
+	ERR_FAIL_INDEX_V(p_axis, 3, 0);
+	return operator[](p_axis);
+}
+
+int Vector3i::min_axis() const {
+
+	return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2);
+}
+int Vector3i::max_axis() const {
+
+	return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
+}
+
+Vector3i::operator String() const {
+
+	return (itos(x) + ", " + itos(y) + ", " + itos(z));
+}

+ 242 - 0
core/math/vector3i.h

@@ -0,0 +1,242 @@
+#ifndef VECTOR3I_H
+#define VECTOR3I_H
+
+#include "core/typedefs.h"
+#include "core/ustring.h"
+
+struct Vector3i {
+
+	enum Axis {
+		AXIS_X,
+		AXIS_Y,
+		AXIS_Z,
+	};
+
+	union {
+		struct {
+			int32_t x;
+			int32_t y;
+			int32_t z;
+		};
+
+		int32_t coord[3];
+	};
+
+	_FORCE_INLINE_ const int32_t &operator[](int p_axis) const {
+
+		return coord[p_axis];
+	}
+
+	_FORCE_INLINE_ int32_t &operator[](int p_axis) {
+
+		return coord[p_axis];
+	}
+
+	void set_axis(int p_axis, int32_t p_value);
+	int32_t get_axis(int p_axis) const;
+
+	int min_axis() const;
+	int max_axis() const;
+
+	_FORCE_INLINE_ void zero();
+
+	_FORCE_INLINE_ Vector3i abs() const;
+	_FORCE_INLINE_ Vector3i sign() const;
+
+	/* Operators */
+
+	_FORCE_INLINE_ Vector3i &operator+=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator+(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator-=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator-(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator*=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const;
+	_FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v);
+	_FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const;
+
+	_FORCE_INLINE_ Vector3i &operator*=(int32_t p_scalar);
+	_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar) const;
+	_FORCE_INLINE_ Vector3i &operator/=(int32_t p_scalar);
+	_FORCE_INLINE_ Vector3i operator/(int32_t p_scalar) const;
+
+	_FORCE_INLINE_ Vector3i operator-() const;
+
+	_FORCE_INLINE_ bool operator==(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator!=(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator<(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator<=(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator>(const Vector3i &p_v) const;
+	_FORCE_INLINE_ bool operator>=(const Vector3i &p_v) const;
+
+	operator String() const;
+
+	_FORCE_INLINE_ Vector3i(int32_t p_x, int32_t p_y, int32_t p_z) {
+		x = p_x;
+		y = p_y;
+		z = p_z;
+	}
+	_FORCE_INLINE_ Vector3i() { x = y = z = 0; }
+};
+
+Vector3i Vector3i::abs() const {
+
+	return Vector3i(ABS(x), ABS(y), ABS(z));
+}
+
+Vector3i Vector3i::sign() const {
+
+	return Vector3i(SGN(x), SGN(y), SGN(z));
+}
+
+/* Operators */
+
+Vector3i &Vector3i::operator+=(const Vector3i &p_v) {
+
+	x += p_v.x;
+	y += p_v.y;
+	z += p_v.z;
+	return *this;
+}
+
+Vector3i Vector3i::operator+(const Vector3i &p_v) const {
+
+	return Vector3i(x + p_v.x, y + p_v.y, z + p_v.z);
+}
+
+Vector3i &Vector3i::operator-=(const Vector3i &p_v) {
+
+	x -= p_v.x;
+	y -= p_v.y;
+	z -= p_v.z;
+	return *this;
+}
+Vector3i Vector3i::operator-(const Vector3i &p_v) const {
+
+	return Vector3i(x - p_v.x, y - p_v.y, z - p_v.z);
+}
+
+Vector3i &Vector3i::operator*=(const Vector3i &p_v) {
+
+	x *= p_v.x;
+	y *= p_v.y;
+	z *= p_v.z;
+	return *this;
+}
+Vector3i Vector3i::operator*(const Vector3i &p_v) const {
+
+	return Vector3i(x * p_v.x, y * p_v.y, z * p_v.z);
+}
+
+Vector3i &Vector3i::operator/=(const Vector3i &p_v) {
+
+	x /= p_v.x;
+	y /= p_v.y;
+	z /= p_v.z;
+	return *this;
+}
+
+Vector3i Vector3i::operator/(const Vector3i &p_v) const {
+
+	return Vector3i(x / p_v.x, y / p_v.y, z / p_v.z);
+}
+
+Vector3i &Vector3i::operator*=(int32_t p_scalar) {
+
+	x *= p_scalar;
+	y *= p_scalar;
+	z *= p_scalar;
+	return *this;
+}
+
+_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar, const Vector3i &p_vec) {
+
+	return p_vec * p_scalar;
+}
+
+Vector3i Vector3i::operator*(int32_t p_scalar) const {
+
+	return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar);
+}
+
+Vector3i &Vector3i::operator/=(int32_t p_scalar) {
+
+	x /= p_scalar;
+	y /= p_scalar;
+	z /= p_scalar;
+	return *this;
+}
+
+Vector3i Vector3i::operator/(int32_t p_scalar) const {
+
+	return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar);
+}
+
+Vector3i Vector3i::operator-() const {
+
+	return Vector3i(-x, -y, -z);
+}
+
+bool Vector3i::operator==(const Vector3i &p_v) const {
+
+	return (x == p_v.x && y == p_v.y && z == p_v.z);
+}
+
+bool Vector3i::operator!=(const Vector3i &p_v) const {
+
+	return (x != p_v.x || y == p_v.y || z == p_v.z);
+}
+
+bool Vector3i::operator<(const Vector3i &p_v) const {
+
+	if (x == p_v.x) {
+		if (y == p_v.y)
+			return z < p_v.z;
+		else
+			return y < p_v.y;
+	} else {
+		return x < p_v.x;
+	}
+}
+
+bool Vector3i::operator>(const Vector3i &p_v) const {
+
+	if (x == p_v.x) {
+		if (y == p_v.y)
+			return z > p_v.z;
+		else
+			return y > p_v.y;
+	} else {
+		return x > p_v.x;
+	}
+}
+
+bool Vector3i::operator<=(const Vector3i &p_v) const {
+
+	if (x == p_v.x) {
+		if (y == p_v.y)
+			return z <= p_v.z;
+		else
+			return y < p_v.y;
+	} else {
+		return x < p_v.x;
+	}
+}
+
+bool Vector3i::operator>=(const Vector3i &p_v) const {
+
+	if (x == p_v.x) {
+		if (y == p_v.y)
+			return z >= p_v.z;
+		else
+			return y > p_v.y;
+	} else {
+		return x > p_v.x;
+	}
+}
+
+void Vector3i::zero() {
+
+	x = y = z = 0;
+}
+
+#endif // VECTOR3I_H

+ 234 - 122
drivers/vulkan/rendering_device_vulkan.cpp

@@ -1950,6 +1950,9 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
 	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),
 			"Can only create a cubemap slice from a cubemap or cubemap array mipmap");
 
+	ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(),
+			"Can only create a 3D slice from a 3D texture");
+
 	//create view
 
 	ERR_FAIL_INDEX_V(p_mipmap, src_texture->mipmaps, RID());
@@ -1976,7 +1979,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
 		VK_IMAGE_VIEW_TYPE_2D,
 	};
 
-	image_view_create_info.viewType = p_slice_type == TEXTURE_SLICE_CUBEMAP ? VK_IMAGE_VIEW_TYPE_CUBE : view_types[texture.type];
+	image_view_create_info.viewType = p_slice_type == TEXTURE_SLICE_CUBEMAP ? VK_IMAGE_VIEW_TYPE_CUBE : (p_slice_type == TEXTURE_SLICE_3D ? VK_IMAGE_VIEW_TYPE_3D : view_types[texture.type]);
 	if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
 		image_view_create_info.format = vulkan_formats[texture.format];
 	} else {
@@ -2676,6 +2679,94 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
 	return OK;
 }
 
+Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw) {
+
+	Texture *src_tex = texture_owner.getornull(p_texture);
+	ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
+
+	ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER,
+			"Source texture can't be cleared while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+
+	ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER);
+	ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER);
+
+	ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
+			"Source texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be cleared.");
+
+	uint32_t src_layer_count = src_tex->layers;
+	if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
+		src_layer_count *= 6;
+	}
+
+	ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER);
+	ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER);
+
+	VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer;
+
+	VkImageLayout layout = src_tex->layout;
+
+	if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state
+		VkImageMemoryBarrier image_memory_barrier;
+		image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+		image_memory_barrier.pNext = NULL;
+		image_memory_barrier.srcAccessMask = 0;
+		image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+		image_memory_barrier.oldLayout = src_tex->layout;
+		image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+
+		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		image_memory_barrier.image = src_tex->image;
+		image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask;
+		image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap;
+		image_memory_barrier.subresourceRange.levelCount = p_mipmaps;
+		image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer;
+		image_memory_barrier.subresourceRange.layerCount = p_layers;
+
+		layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+		vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+	}
+
+	VkClearColorValue clear_color;
+	clear_color.float32[0] = p_color.r;
+	clear_color.float32[1] = p_color.g;
+	clear_color.float32[2] = p_color.b;
+	clear_color.float32[3] = p_color.a;
+
+	VkImageSubresourceRange range;
+	range.aspectMask = src_tex->read_aspect_mask;
+	range.baseArrayLayer = p_base_layer;
+	range.layerCount = p_layers;
+	range.baseMipLevel = p_base_mipmap;
+	range.levelCount = p_mipmaps;
+
+	vkCmdClearColorImage(command_buffer, src_tex->image, layout, &clear_color, 1, &range);
+
+	if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state
+
+		VkImageMemoryBarrier image_memory_barrier;
+		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.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+		image_memory_barrier.newLayout = src_tex->layout;
+
+		image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+		image_memory_barrier.image = src_tex->image;
+		image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask;
+		image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap;
+		image_memory_barrier.subresourceRange.levelCount = p_mipmaps;
+		image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer;
+		image_memory_barrier.subresourceRange.layerCount = p_layers;
+
+		vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+	}
+
+	return OK;
+}
+
 bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const {
 	ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
 
@@ -2719,7 +2810,7 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
 /**** ATTACHMENT ****/
 /********************/
 
-VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, int *r_color_attachment_count) {
+VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count) {
 
 	Vector<VkAttachmentDescription> attachments;
 	Vector<VkAttachmentReference> color_references;
@@ -2739,17 +2830,18 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
 		ERR_FAIL_COND_V_MSG(!(p_format[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)), VK_NULL_HANDLE,
 				"Texture format for index (" + itos(i) + ") requires an attachment (depth, stencil or resolve) bit set.");
 
+		bool is_depth_stencil = p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
 		bool is_sampled = p_format[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT;
 		bool is_storage = p_format[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT;
 
-		switch (p_initial_action) {
+		switch (is_depth_stencil ? p_initial_depth_action : p_initial_color_action) {
 
 			case INITIAL_ACTION_CLEAR: {
 				description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 				description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 				description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
 			} break;
-			case INITIAL_ACTION_KEEP_COLOR: {
+			case INITIAL_ACTION_KEEP: {
 				if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
 					description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
 					description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
@@ -2764,22 +2856,6 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
 					description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
 				}
 			} break;
-			case INITIAL_ACTION_KEEP_COLOR_AND_DEPTH: {
-
-				if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-					description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-					description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-				} else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-					description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-					description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-					description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-				} else {
-					description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-					description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-					description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
-				}
-
-			} break;
 			case INITIAL_ACTION_CONTINUE: {
 				if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
 					description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
@@ -2800,8 +2876,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
 			}
 		}
 
-		switch (p_final_action) {
-			case FINAL_ACTION_READ_COLOR_AND_DEPTH: {
+		switch (is_depth_stencil ? p_final_depth_action : p_final_color_action) {
+			case FINAL_ACTION_READ: {
 
 				if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
 					description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@@ -2817,59 +2893,42 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
 					description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 					description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
 				}
-				break;
-				case FINAL_ACTION_READ_COLOR_DISCARD_DEPTH: {
-					if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-					} else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-
-						description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
-					}
-				} break;
-				case FINAL_ACTION_DISCARD: {
-					if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-					} else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-
-						description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
-					}
-				} break;
-				case FINAL_ACTION_CONTINUE: {
-					if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
-						description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-						description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-					} else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-
-						description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
-						description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-					} else {
-						description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-						description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
-					}
+			} break;
+			case FINAL_ACTION_DISCARD: {
+				if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+					description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+					description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+					description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+				} else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+
+					description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+					description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+					description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+				} else {
+					description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+					description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+					description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+				}
+			} break;
+			case FINAL_ACTION_CONTINUE: {
+				if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+					description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+					description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+					description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+				} else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
 
-				} break;
-				default: {
-					ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
+					description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+					description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+					description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+				} else {
+					description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+					description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+					description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
 				}
+
+			} break;
+			default: {
+				ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
 			}
 		}
 
@@ -2945,7 +3004,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
 	}
 
 	int color_references;
-	VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, &color_references); //actions don't matter for this use case
+	VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, &color_references); //actions don't matter for this use case
 
 	if (render_pass == VK_NULL_HANDLE) { //was likely invalid
 		return INVALID_ID;
@@ -5240,17 +5299,19 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in
 	return ID_TYPE_DRAW_LIST;
 }
 
-Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass) {
+Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass) {
 
 	Framebuffer::VersionKey vk;
-	vk.initial_action = p_initial_action;
-	vk.final_action = p_final_action;
+	vk.initial_color_action = p_initial_color_action;
+	vk.final_color_action = p_final_color_action;
+	vk.initial_depth_action = p_initial_depth_action;
+	vk.final_depth_action = p_final_depth_action;
 
 	if (!p_framebuffer->framebuffers.has(vk)) {
 		//need to create this version
 		Framebuffer::Version version;
 
-		version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_action, p_final_action);
+		version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action);
 
 		VkFramebufferCreateInfo framebuffer_create_info;
 		framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
@@ -5283,7 +5344,7 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
 	return OK;
 }
 
-Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_colors, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents) {
+Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents) {
 
 	VkRenderPassBeginInfo render_pass_begin;
 	render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@@ -5297,12 +5358,15 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
 	render_pass_begin.renderArea.offset.y = viewport_offset.y;
 
 	Vector<VkClearValue> clear_values;
-	if (p_initial_action == INITIAL_ACTION_CLEAR) {
+	clear_values.resize(framebuffer->texture_ids.size());
+
+	{
 		int color_index = 0;
 		for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
 			Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]);
 			VkClearValue clear_value;
-			if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+
+			if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
 				ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); //a bug
 				Color clear_color = p_clear_colors[color_index];
 				clear_value.color.float32[0] = clear_color.r;
@@ -5311,15 +5375,15 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
 				clear_value.color.float32[3] = clear_color.a;
 				color_index++;
 			} else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
-				clear_value.depthStencil.depth = 1.0;
-				clear_value.depthStencil.stencil = 0;
+				clear_value.depthStencil.depth = p_clear_depth;
+				clear_value.depthStencil.stencil = p_clear_stencil;
 			} else {
 				clear_value.color.float32[0] = 0;
 				clear_value.color.float32[1] = 0;
 				clear_value.color.float32[2] = 0;
 				clear_value.color.float32[3] = 0;
 			}
-			clear_values.push_back(clear_value);
+			clear_values.write[i] = clear_value;
 		}
 	}
 
@@ -5330,7 +5394,9 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
 
 	//mark textures as bound
 	draw_list_bound_textures.clear();
-	draw_list_unbind_textures = p_final_action != FINAL_ACTION_CONTINUE;
+	draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE;
+	draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE;
+
 	for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
 		Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]);
 		texture->bound = true;
@@ -5340,13 +5406,13 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
 	return OK;
 }
 
-void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, const Vector<Color> &p_clear_colors) {
+void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) {
 	Vector<VkClearAttachment> clear_attachments;
 	int color_index = 0;
 	for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
 		Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]);
 		VkClearAttachment clear_at;
-		if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+		if (p_clear_color && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
 			ERR_FAIL_INDEX(color_index, p_clear_colors.size()); //a bug
 			Color clear_color = p_clear_colors[color_index];
 			clear_at.clearValue.color.float32[0] = clear_color.r;
@@ -5355,10 +5421,10 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list,
 			clear_at.clearValue.color.float32[3] = clear_color.a;
 			clear_at.colorAttachment = color_index++;
 			clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-		} else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+		} else if (p_clear_depth && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
 
-			clear_at.clearValue.depthStencil.depth = 1.0;
-			clear_at.clearValue.depthStencil.stencil = 0;
+			clear_at.clearValue.depthStencil.depth = p_depth;
+			clear_at.clearValue.depthStencil.stencil = p_stencil;
 			clear_at.colorAttachment = 0;
 			clear_at.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
 			if (format_has_stencil(texture->format)) {
@@ -5381,7 +5447,7 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list,
 	vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr);
 }
 
-RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_colors, const Rect2 &p_region) {
+RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) {
 
 	_THREAD_SAFE_METHOD_
 
@@ -5393,7 +5459,8 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
 
 	Point2i viewport_offset;
 	Point2i viewport_size = framebuffer->size;
-	bool needs_clear_region = false;
+	bool needs_clear_color = false;
+	bool needs_clear_depth = false;
 
 	if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region
 		Rect2i viewport(viewport_offset, viewport_size);
@@ -5407,27 +5474,31 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
 		viewport_offset = regioni.position;
 		viewport_size = regioni.size;
 
-		if (p_initial_action == INITIAL_ACTION_CLEAR) {
-			p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH;
-			needs_clear_region = true;
+		if (p_initial_color_action == INITIAL_ACTION_CLEAR) {
+			needs_clear_color = true;
+			p_initial_color_action = INITIAL_ACTION_KEEP;
+		}
+		if (p_initial_depth_action == INITIAL_ACTION_CLEAR) {
+			needs_clear_depth = true;
+			p_initial_depth_action = INITIAL_ACTION_KEEP;
 		}
 	}
 
-	if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values
+	if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values
 
 		int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments;
-		ERR_FAIL_COND_V_MSG(p_clear_colors.size() != color_attachments, INVALID_ID,
-				"Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ").");
+		ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, INVALID_ID,
+				"Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ").");
 	}
 
 	VkFramebuffer vkframebuffer;
 	VkRenderPass render_pass;
 
-	Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_action, p_final_action, &vkframebuffer, &render_pass);
+	Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass);
 	ERR_FAIL_COND_V(err != OK, INVALID_ID);
 
 	VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
-	err = _draw_list_render_pass_begin(framebuffer, p_initial_action, p_final_action, p_clear_colors, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE);
+	err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE);
 
 	if (err != OK) {
 		return INVALID_ID;
@@ -5441,8 +5512,8 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
 	draw_list_count = 0;
 	draw_list_split = false;
 
-	if (needs_clear_region) {
-		_draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, p_clear_colors);
+	if (needs_clear_color || needs_clear_depth) {
+		_draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
 	}
 
 	VkViewport viewport;
@@ -5467,7 +5538,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
 	return ID_TYPE_DRAW_LIST;
 }
 
-Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_colors, const Rect2 &p_region) {
+Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) {
 
 	_THREAD_SAFE_METHOD_
 
@@ -5479,7 +5550,8 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
 	Point2i viewport_offset;
 	Point2i viewport_size = framebuffer->size;
 
-	bool needs_clear_region = false;
+	bool needs_clear_color = false;
+	bool needs_clear_depth = false;
 
 	if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region
 		Rect2i viewport(viewport_offset, viewport_size);
@@ -5493,17 +5565,21 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
 		viewport_offset = regioni.position;
 		viewport_size = regioni.size;
 
-		if (p_initial_action == INITIAL_ACTION_CLEAR) {
-			p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH;
-			needs_clear_region = true;
+		if (p_initial_color_action == INITIAL_ACTION_CLEAR) {
+			needs_clear_color = true;
+			p_initial_color_action = INITIAL_ACTION_KEEP;
+		}
+		if (p_initial_depth_action == INITIAL_ACTION_CLEAR) {
+			needs_clear_depth = true;
+			p_initial_depth_action = INITIAL_ACTION_KEEP;
 		}
 	}
 
-	if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values
+	if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values
 
 		int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments;
-		ERR_FAIL_COND_V_MSG(p_clear_colors.size() != color_attachments, ERR_INVALID_PARAMETER,
-				"Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ").");
+		ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, ERR_INVALID_PARAMETER,
+				"Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ").");
 	}
 
 	if (p_splits > (uint32_t)split_draw_list_allocators.size()) {
@@ -5543,11 +5619,11 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
 	VkFramebuffer vkframebuffer;
 	VkRenderPass render_pass;
 
-	Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_action, p_final_action, &vkframebuffer, &render_pass);
+	Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass);
 	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
 
 	VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer;
-	err = _draw_list_render_pass_begin(framebuffer, p_initial_action, p_final_action, p_clear_colors, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
+	err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
 
 	if (err != OK) {
 		return ERR_CANT_CREATE;
@@ -5596,8 +5672,9 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
 #ifdef DEBUG_ENABLED
 		draw_list[i].validation.framebuffer_format = framebuffer->format_id;
 #endif
-		if (i == 0 && needs_clear_region) {
-			_draw_list_insert_clear_region(&draw_list[i], framebuffer, viewport_offset, viewport_size, p_clear_colors);
+
+		if (i == 0 && (needs_clear_color || needs_clear_depth)) {
+			_draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
 		}
 
 		VkViewport viewport;
@@ -5626,6 +5703,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
 }
 
 RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) {
+
 	if (p_id < 0) {
 		return NULL;
 	}
@@ -5841,7 +5919,7 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void
 #endif
 }
 
-void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances) {
+void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) {
 
 	DrawList *dl = _get_draw_list_ptr(p_list);
 	ERR_FAIL_COND(!dl);
@@ -5902,8 +5980,12 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
 	if (p_use_indices) {
 
 #ifdef DEBUG_ENABLED
+		ERR_FAIL_COND_MSG(p_procedural_vertices > 0,
+				"Procedural vertices can't be used together with indices.");
+
 		ERR_FAIL_COND_MSG(!dl->validation.index_array_size,
 				"Draw command requested indices, but no index buffer was set.");
+
 		if (dl->validation.pipeline_vertex_format != INVALID_ID) {
 			//uses vertices, do some vertex validations
 			ERR_FAIL_COND_MSG(dl->validation.vertex_array_size < dl->validation.index_array_max_index,
@@ -5924,11 +6006,23 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
 #endif
 		vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0);
 	} else {
+
+		uint32_t to_draw;
+
+		if (p_procedural_vertices > 0) {
 #ifdef DEBUG_ENABLED
 		ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID,
-				"Draw command lacks indices, but pipeline format does not use vertices.");
+				"Procedural vertices requested, but pipeline expects a vertex array.");
 #endif
-		uint32_t to_draw = dl->validation.vertex_array_size;
+			to_draw = p_procedural_vertices;
+		} else {
+
+#ifdef DEBUG_ENABLED
+			ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID,
+					"Draw command lacks indices, but pipeline format does not use vertices.");
+#endif
+			to_draw = dl->validation.vertex_array_size;
+		}
 
 #ifdef DEBUG_ENABLED
 		ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum,
@@ -5937,6 +6031,7 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
 		ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0,
 				"Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ").");
 #endif
+
 		vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0);
 	}
 }
@@ -6005,13 +6100,17 @@ void RenderingDeviceVulkan::draw_list_end() {
 		draw_list = NULL;
 	}
 
-	if (draw_list_unbind_textures) {
-		for (int i = 0; i < draw_list_bound_textures.size(); i++) {
-			Texture *texture = texture_owner.getornull(draw_list_bound_textures[i]);
-			ERR_CONTINUE(!texture); //wtf
+	for (int i = 0; i < draw_list_bound_textures.size(); i++) {
+		Texture *texture = texture_owner.getornull(draw_list_bound_textures[i]);
+		ERR_CONTINUE(!texture); //wtf
+		if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+			texture->bound = false;
+		}
+		if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
 			texture->bound = false;
 		}
 	}
+
 	draw_list_bound_textures.clear();
 
 	// To ensure proper synchronization, we must make sure rendering is done before:
@@ -6168,7 +6267,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
 			image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
 			image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
 			image_memory_barrier.image = textures_to_storage[i]->image;
-			image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask;
+			image_memory_barrier.subresourceRange.aspectMask = textures_to_storage[i]->read_aspect_mask;
 			image_memory_barrier.subresourceRange.baseMipLevel = 0;
 			image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps;
 			image_memory_barrier.subresourceRange.baseArrayLayer = 0;
@@ -6197,6 +6296,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
 	}
 #endif
 }
+
 void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) {
 	ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
 	ERR_FAIL_COND(!compute_list);
@@ -6223,6 +6323,10 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
 	ComputeList *cl = compute_list;
 
 #ifdef DEBUG_ENABLED
+	ERR_FAIL_COND(p_x_groups > limits.maxComputeWorkGroupCount[0]);
+	ERR_FAIL_COND(p_y_groups > limits.maxComputeWorkGroupCount[1]);
+	ERR_FAIL_COND(p_z_groups > limits.maxComputeWorkGroupCount[2]);
+
 	ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
 #endif
 
@@ -6267,6 +6371,11 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
 
 	vkCmdDispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups);
 }
+
+void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {
+	_memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, true);
+}
+
 void RenderingDeviceVulkan::compute_list_end() {
 	ERR_FAIL_COND(!compute_list);
 
@@ -6295,6 +6404,9 @@ void RenderingDeviceVulkan::compute_list_end() {
 	}
 
 	memdelete(compute_list);
+	compute_list = NULL;
+
+	_memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true);
 }
 
 #if 0

+ 28 - 13
drivers/vulkan/rendering_device_vulkan.h

@@ -259,7 +259,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
 		}
 	};
 
-	VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, int *r_color_attachment_count = NULL);
+	VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = NULL);
 
 	// This is a cache and it's never freed, it ensures
 	// IDs for a given format are always unique.
@@ -276,13 +276,23 @@ class RenderingDeviceVulkan : public RenderingDevice {
 	struct Framebuffer {
 		FramebufferFormatID format_id;
 		struct VersionKey {
-			InitialAction initial_action;
-			FinalAction final_action;
+			InitialAction initial_color_action;
+			FinalAction final_color_action;
+			InitialAction initial_depth_action;
+			FinalAction final_depth_action;
 			bool operator<(const VersionKey &p_key) const {
-				if (initial_action == p_key.initial_action) {
-					return final_action < p_key.final_action;
+				if (initial_color_action == p_key.initial_color_action) {
+					if (final_color_action == p_key.final_color_action) {
+						if (initial_depth_action == p_key.initial_depth_action) {
+							return final_depth_action < p_key.final_depth_action;
+						} else {
+							return initial_depth_action < p_key.initial_depth_action;
+						}
+					} else {
+						return final_color_action < p_key.final_color_action;
+					}
 				} else {
-					return initial_action < p_key.initial_action;
+					return initial_color_action < p_key.initial_color_action;
 				}
 			}
 		};
@@ -806,11 +816,12 @@ class RenderingDeviceVulkan : public RenderingDevice {
 	uint32_t draw_list_count;
 	bool draw_list_split;
 	Vector<RID> draw_list_bound_textures;
-	bool draw_list_unbind_textures;
+	bool draw_list_unbind_color_textures;
+	bool draw_list_unbind_depth_textures;
 
-	void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, const Vector<Color> &p_clear_colors);
-	Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass);
-	Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_colors, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents);
+	void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
+	Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass);
+	Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents);
 	_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
 
 	/**********************/
@@ -966,6 +977,7 @@ public:
 	virtual bool texture_is_valid(RID p_texture);
 
 	virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false);
+	virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false);
 
 	/*********************/
 	/**** FRAMEBUFFER ****/
@@ -1046,8 +1058,9 @@ public:
 	/********************/
 
 	virtual DrawListID draw_list_begin_for_screen(int p_screen = 0, const Color &p_clear_color = Color());
-	virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_colors = Vector<Color>(), const Rect2 &p_region = Rect2());
-	virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_colors = Vector<Color>(), const Rect2 &p_region = Rect2());
+
+	virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
+	virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
 
 	virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
 	virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index);
@@ -1056,7 +1069,7 @@ public:
 	virtual void draw_list_set_line_width(DrawListID p_list, float p_width);
 	virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size);
 
-	virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1);
+	virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0);
 
 	virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
 	virtual void draw_list_disable_scissor(DrawListID p_list);
@@ -1071,6 +1084,8 @@ public:
 	virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline);
 	virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index);
 	virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size);
+	virtual void compute_list_add_barrier(ComputeListID p_list);
+
 	virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
 	virtual void compute_list_end();
 

+ 5 - 0
drivers/vulkan/vulkan_context.cpp

@@ -53,6 +53,11 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(VkDebugU
 			strstr(pCallbackData->pMessage, "can result in undefined behavior if this memory is used by the device") != NULL) {
 		return VK_FALSE;
 	}
+	// This needs to be ignored because Validator is wrong here
+	if (strstr(pCallbackData->pMessage, "SPIR-V module not valid: Pointer operand") != NULL &&
+			strstr(pCallbackData->pMessage, "must be a memory object") != NULL) {
+		return VK_FALSE;
+	}
 
 	if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
 		strcat(prefix, "VERBOSE : ");

+ 1 - 1
editor/editor_node.cpp

@@ -6682,7 +6682,7 @@ EditorNode::EditorNode() {
 	add_editor_plugin(memnew(TextureRegionEditorPlugin(this)));
 	add_editor_plugin(memnew(Particles2DEditorPlugin(this)));
 	add_editor_plugin(memnew(GIProbeEditorPlugin(this)));
-	add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
+	//	add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
 	add_editor_plugin(memnew(Path2DEditorPlugin(this)));
 	add_editor_plugin(memnew(PathEditorPlugin(this)));
 	add_editor_plugin(memnew(Line2DEditorPlugin(this)));

+ 2 - 0
editor/plugins/baked_lightmap_editor_plugin.cpp

@@ -28,6 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
+#if 0
 #include "baked_lightmap_editor_plugin.h"
 
 void BakedLightmapEditorPlugin::_bake() {
@@ -124,3 +125,4 @@ BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
 
 BakedLightmapEditorPlugin::~BakedLightmapEditorPlugin() {
 }
+#endif

+ 2 - 0
editor/plugins/baked_lightmap_editor_plugin.h

@@ -28,6 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
+#if 0
 #ifndef BAKED_LIGHTMAP_EDITOR_PLUGIN_H
 #define BAKED_LIGHTMAP_EDITOR_PLUGIN_H
 
@@ -67,3 +68,4 @@ public:
 };
 
 #endif // BAKED_LIGHTMAP_EDITOR_PLUGIN_H
+#endif

+ 65 - 38
editor/plugins/spatial_editor_plugin.cpp

@@ -2759,43 +2759,60 @@ void SpatialEditorViewport::_menu_option(int p_option) {
 			view_menu->get_popup()->set_item_checked(idx, !current);
 
 		} break;
-		case VIEW_DISPLAY_NORMAL: {
-
-			viewport->set_debug_draw(Viewport::DEBUG_DRAW_DISABLED);
-
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false);
-		} break;
-		case VIEW_DISPLAY_WIREFRAME: {
-
-			viewport->set_debug_draw(Viewport::DEBUG_DRAW_WIREFRAME);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), true);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false);
-
-		} break;
-		case VIEW_DISPLAY_OVERDRAW: {
-
-			viewport->set_debug_draw(Viewport::DEBUG_DRAW_OVERDRAW);
-			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_OVERDRAW);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), true);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false);
-
-		} break;
-		case VIEW_DISPLAY_SHADELESS: {
-
-			viewport->set_debug_draw(Viewport::DEBUG_DRAW_UNSHADED);
-			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_SHADELESS);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false);
-			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), true);
+		case VIEW_DISPLAY_NORMAL:
+		case VIEW_DISPLAY_WIREFRAME:
+		case VIEW_DISPLAY_OVERDRAW:
+		case VIEW_DISPLAY_SHADELESS:
+		case VIEW_DISPLAY_LIGHTING:
+		case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS:
+		case VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS:
+		case VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO:
+		case VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING: {
+
+			static const int display_options[] = {
+				VIEW_DISPLAY_NORMAL,
+				VIEW_DISPLAY_WIREFRAME,
+				VIEW_DISPLAY_OVERDRAW,
+				VIEW_DISPLAY_SHADELESS,
+				VIEW_DISPLAY_LIGHTING,
+				VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
+				VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
+				VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO,
+				VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING,
+				VIEW_MAX
+			};
+			static const Viewport::DebugDraw debug_draw_modes[] = {
+				Viewport::DEBUG_DRAW_DISABLED,
+				Viewport::DEBUG_DRAW_WIREFRAME,
+				Viewport::DEBUG_DRAW_OVERDRAW,
+				Viewport::DEBUG_DRAW_UNSHADED,
+				Viewport::DEBUG_DRAW_LIGHTING,
+				Viewport::DEBUG_DRAW_WIREFRAME,
+				Viewport::DEBUG_DRAW_SHADOW_ATLAS,
+				Viewport::DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
+				Viewport::DEBUG_DRAW_GI_PROBE_LIGHTING,
+				Viewport::DEBUG_DRAW_GI_PROBE_ALBEDO
+			};
+
+			int idx = 0;
+
+			while (display_options[idx] != VIEW_MAX) {
+
+				int id = display_options[idx];
+				int item_idx = view_menu->get_popup()->get_item_index(id);
+				if (item_idx != -1) {
+					view_menu->get_popup()->set_item_checked(item_idx, id == p_option);
+				}
+				item_idx = display_submenu->get_item_index(id);
+				if (item_idx != -1) {
+					display_submenu->set_item_checked(item_idx, id == p_option);
+				}
 
+				if (id == p_option) {
+					viewport->set_debug_draw(debug_draw_modes[idx]);
+				}
+				idx++;
+			}
 		} break;
 	}
 }
@@ -3590,6 +3607,9 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
 	vbox->add_child(view_menu);
 	view_menu->set_h_size_flags(0);
 
+	display_submenu = memnew(PopupMenu);
+	view_menu->get_popup()->add_child(display_submenu);
+
 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
@@ -3608,6 +3628,13 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
 	view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW);
 	view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS);
 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
+	display_submenu->add_radio_check_item(TTR("Shadow Atlas"), VIEW_DISPLAY_DEBUG_SHADOW_ATLAS);
+	display_submenu->add_radio_check_item(TTR("Directional Shadow"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS);
+	display_submenu->add_separator();
+	display_submenu->add_radio_check_item(TTR("GIProbe Lighting"), VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING);
+	display_submenu->add_radio_check_item(TTR("GIProbe Albedo"), VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO);
+	display_submenu->set_name("display_advanced");
+	view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced");
 	view_menu->get_popup()->add_separator();
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT);
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
@@ -3630,7 +3657,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_transform_with_view"), VIEW_ALIGN_TRANSFORM_WITH_VIEW);
 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_rotation_with_view"), VIEW_ALIGN_ROTATION_WITH_VIEW);
 	view_menu->get_popup()->connect("id_pressed", this, "_menu_option");
-
+	display_submenu->connect("id_pressed", this, "_menu_option");
 	view_menu->set_disable_shortcuts(true);
 
 	if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
@@ -5587,7 +5614,7 @@ void SpatialEditor::_register_all_gizmos() {
 	add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin)));
 	add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
 	add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
-	add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
+	//	add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
 	add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin)));
 	add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));
 	add_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin)));

+ 8 - 1
editor/plugins/spatial_editor_plugin.h

@@ -167,8 +167,14 @@ class SpatialEditorViewport : public Control {
 		VIEW_DISPLAY_WIREFRAME,
 		VIEW_DISPLAY_OVERDRAW,
 		VIEW_DISPLAY_SHADELESS,
+		VIEW_DISPLAY_LIGHTING,
+		VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
+		VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
+		VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO,
+		VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING,
 		VIEW_LOCK_ROTATION,
-		VIEW_CINEMATIC_PREVIEW
+		VIEW_CINEMATIC_PREVIEW,
+		VIEW_MAX
 	};
 
 public:
@@ -205,6 +211,7 @@ private:
 	ViewportContainer *viewport_container;
 
 	MenuButton *view_menu;
+	PopupMenu *display_submenu;
 
 	Control *surface;
 	Viewport *viewport;

+ 2 - 2
editor/spatial_editor_gizmos.cpp

@@ -2904,7 +2904,7 @@ void GIProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
 }
 
 ////
-
+#if 0
 BakedIndirectLightGizmoPlugin::BakedIndirectLightGizmoPlugin() {
 	Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
 
@@ -3033,7 +3033,7 @@ void BakedIndirectLightGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
 	p_gizmo->add_unscaled_billboard(icon, 0.05);
 	p_gizmo->add_handles(handles, get_material("handles"));
 }
-
+#endif
 ////
 
 CollisionShapeSpatialGizmoPlugin::CollisionShapeSpatialGizmoPlugin() {

+ 2 - 1
editor/spatial_editor_gizmos.h

@@ -303,6 +303,7 @@ public:
 	GIProbeGizmoPlugin();
 };
 
+#if 0
 class BakedIndirectLightGizmoPlugin : public EditorSpatialGizmoPlugin {
 
 	GDCLASS(BakedIndirectLightGizmoPlugin, EditorSpatialGizmoPlugin);
@@ -320,7 +321,7 @@ public:
 
 	BakedIndirectLightGizmoPlugin();
 };
-
+#endif
 class CollisionShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
 
 	GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);

+ 6 - 4
scene/3d/baked_lightmap.cpp

@@ -28,6 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
+#if 0
 #include "baked_lightmap.h"
 #include "core/io/config_file.h"
 #include "core/io/resource_saver.h"
@@ -368,7 +369,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
 	Ref<BakedLightmapData> new_light_data;
 	new_light_data.instance();
 
-	VoxelLightBaker baker;
+	Voxelizer baker;
 
 	int bake_subdiv;
 	int capture_subdiv;
@@ -413,7 +414,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
 	}
 
 	pmc = 0;
-	baker.begin_bake_light(VoxelLightBaker::BakeQuality(bake_quality), VoxelLightBaker::BakeMode(bake_mode), propagation, energy);
+	baker.begin_bake_light(Voxelizer::BakeQuality(bake_quality), Voxelizer::BakeMode(bake_mode), propagation, energy);
 
 	for (List<PlotLight>::Element *E = light_list.front(); E; E = E->next()) {
 
@@ -465,7 +466,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
 		used_mesh_names.insert(mesh_name);
 
 		pmc++;
-		VoxelLightBaker::LightMapData lm;
+		Voxelizer::LightMapData lm;
 
 		Error err;
 		if (bake_step_function) {
@@ -626,7 +627,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
 
 	if (p_create_visual_debug) {
 		MultiMeshInstance *mmi = memnew(MultiMeshInstance);
-		mmi->set_multimesh(baker.create_debug_multimesh(VoxelLightBaker::DEBUG_LIGHT));
+		mmi->set_multimesh(baker.create_debug_multimesh(Voxelizer::DEBUG_LIGHT));
 		add_child(mmi);
 #ifdef TOOLS_ENABLED
 		if (get_tree()->get_edited_scene_root() == this) {
@@ -860,3 +861,4 @@ BakedLightmap::BakedLightmap() {
 	image_path = ".";
 	set_disable_scale(true);
 }
+#endif

+ 2 - 0
scene/3d/baked_lightmap.h

@@ -28,6 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
+#if 0
 #ifndef BAKED_INDIRECT_LIGHT_H
 #define BAKED_INDIRECT_LIGHT_H
 
@@ -211,4 +212,5 @@ VARIANT_ENUM_CAST(BakedLightmap::BakeQuality);
 VARIANT_ENUM_CAST(BakedLightmap::BakeMode);
 VARIANT_ENUM_CAST(BakedLightmap::BakeError);
 
+#endif
 #endif // BAKED_INDIRECT_LIGHT_H

+ 125 - 218
scene/3d/gi_probe.cpp

@@ -32,116 +32,135 @@
 
 #include "core/os/os.h"
 
+#include "core/method_bind_ext.gen.inc"
 #include "mesh_instance.h"
-#include "voxel_light_baker.h"
+#include "voxelizer.h"
 
-void GIProbeData::set_bounds(const AABB &p_bounds) {
+void GIProbeData::_set_data(const Dictionary &p_data) {
+	ERR_FAIL_COND(!p_data.has("bounds"));
+	ERR_FAIL_COND(!p_data.has("octree_size"));
+	ERR_FAIL_COND(!p_data.has("octree_cells"));
+	ERR_FAIL_COND(!p_data.has("octree_data"));
+	ERR_FAIL_COND(!p_data.has("level_counts"));
+	ERR_FAIL_COND(!p_data.has("to_cell_xform"));
 
-	VS::get_singleton()->gi_probe_set_bounds(probe, p_bounds);
-}
-
-AABB GIProbeData::get_bounds() const {
+	AABB bounds = p_data["bounds"];
+	Vector3 octree_size = p_data["octree_size"];
+	PoolVector<uint8_t> octree_cells = p_data["octree_cells"];
+	PoolVector<uint8_t> octree_data = p_data["octree_data"];
+	PoolVector<int> octree_levels = p_data["level_counts"];
+	Transform to_cell_xform = p_data["to_cell_xform"];
 
-	return VS::get_singleton()->gi_probe_get_bounds(probe);
+	allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_levels);
 }
 
-void GIProbeData::set_cell_size(float p_size) {
-
-	VS::get_singleton()->gi_probe_set_cell_size(probe, p_size);
+Dictionary GIProbeData::_get_data() const {
+	Dictionary d;
+	d["bounds"] = get_bounds();
+	d["octree_size"] = get_octree_size();
+	d["octree_cells"] = get_octree_cells();
+	d["octree_data"] = get_data_cells();
+	d["level_counts"] = get_level_counts();
+	d["to_cell_xform"] = get_to_cell_xform();
+	return d;
 }
 
-float GIProbeData::get_cell_size() const {
-
-	return VS::get_singleton()->gi_probe_get_cell_size(probe);
+void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) {
+	VS::get_singleton()->gi_probe_allocate(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_level_counts);
+	bounds = p_aabb;
+	to_cell_xform = p_to_cell_xform;
+	octree_size = p_octree_size;
 }
 
-void GIProbeData::set_to_cell_xform(const Transform &p_xform) {
-
-	VS::get_singleton()->gi_probe_set_to_cell_xform(probe, p_xform);
+AABB GIProbeData::get_bounds() const {
+	return bounds;
+}
+Vector3 GIProbeData::get_octree_size() const {
+	return octree_size;
+}
+PoolVector<uint8_t> GIProbeData::get_octree_cells() const {
+	return VS::get_singleton()->gi_probe_get_octree_cells(probe);
+}
+PoolVector<uint8_t> GIProbeData::get_data_cells() const {
+	return VS::get_singleton()->gi_probe_get_data_cells(probe);
+}
+PoolVector<int> GIProbeData::get_level_counts() const {
+	return VS::get_singleton()->gi_probe_get_level_counts(probe);
 }
-
 Transform GIProbeData::get_to_cell_xform() const {
-
-	return VS::get_singleton()->gi_probe_get_to_cell_xform(probe);
+	return to_cell_xform;
 }
 
-void GIProbeData::set_dynamic_data(const PoolVector<int> &p_data) {
+void GIProbeData::set_dynamic_range(float p_range) {
+	VS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range);
+	dynamic_range = p_range;
+}
 
-	VS::get_singleton()->gi_probe_set_dynamic_data(probe, p_data);
+float GIProbeData::get_dynamic_range() const {
+	return dynamic_range;
 }
-PoolVector<int> GIProbeData::get_dynamic_data() const {
 
-	return VS::get_singleton()->gi_probe_get_dynamic_data(probe);
+void GIProbeData::set_propagation(float p_propagation) {
+	VS::get_singleton()->gi_probe_set_propagation(probe, p_propagation);
+	propagation = p_propagation;
 }
 
-void GIProbeData::set_dynamic_range(int p_range) {
+float GIProbeData::get_propagation() const {
+	return propagation;
+}
 
-	VS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range);
+void GIProbeData::set_anisotropy_strength(float p_anisotropy_strength) {
+	VS::get_singleton()->gi_probe_set_anisotropy_strength(probe, p_anisotropy_strength);
+	anisotropy_strength = p_anisotropy_strength;
 }
 
-void GIProbeData::set_energy(float p_range) {
+float GIProbeData::get_anisotropy_strength() const {
+	return anisotropy_strength;
+}
 
-	VS::get_singleton()->gi_probe_set_energy(probe, p_range);
+void GIProbeData::set_energy(float p_energy) {
+	VS::get_singleton()->gi_probe_set_energy(probe, p_energy);
+	energy = p_energy;
 }
 
 float GIProbeData::get_energy() const {
-
-	return VS::get_singleton()->gi_probe_get_energy(probe);
+	return energy;
 }
 
-void GIProbeData::set_bias(float p_range) {
-
-	VS::get_singleton()->gi_probe_set_bias(probe, p_range);
+void GIProbeData::set_bias(float p_bias) {
+	VS::get_singleton()->gi_probe_set_bias(probe, p_bias);
+	bias = p_bias;
 }
 
 float GIProbeData::get_bias() const {
-
-	return VS::get_singleton()->gi_probe_get_bias(probe);
+	return bias;
 }
 
-void GIProbeData::set_normal_bias(float p_range) {
-
-	VS::get_singleton()->gi_probe_set_normal_bias(probe, p_range);
+void GIProbeData::set_normal_bias(float p_normal_bias) {
+	VS::get_singleton()->gi_probe_set_normal_bias(probe, p_normal_bias);
+	normal_bias = p_normal_bias;
 }
 
 float GIProbeData::get_normal_bias() const {
-
-	return VS::get_singleton()->gi_probe_get_normal_bias(probe);
-}
-
-void GIProbeData::set_propagation(float p_range) {
-
-	VS::get_singleton()->gi_probe_set_propagation(probe, p_range);
-}
-
-float GIProbeData::get_propagation() const {
-
-	return VS::get_singleton()->gi_probe_get_propagation(probe);
+	return normal_bias;
 }
 
 void GIProbeData::set_interior(bool p_enable) {
-
 	VS::get_singleton()->gi_probe_set_interior(probe, p_enable);
+	interior = p_enable;
 }
 
 bool GIProbeData::is_interior() const {
-
-	return VS::get_singleton()->gi_probe_is_interior(probe);
-}
-
-bool GIProbeData::is_compressed() const {
-
-	return VS::get_singleton()->gi_probe_is_compressed(probe);
+	return interior;
 }
 
-void GIProbeData::set_compress(bool p_enable) {
-
-	VS::get_singleton()->gi_probe_set_compress(probe, p_enable);
+void GIProbeData::set_use_two_bounces(bool p_enable) {
+	VS::get_singleton()->gi_probe_set_use_two_bounces(probe, p_enable);
+	use_two_bounces = p_enable;
 }
 
-int GIProbeData::get_dynamic_range() const {
-
-	return VS::get_singleton()->gi_probe_get_dynamic_range(probe);
+bool GIProbeData::is_using_two_bounces() const {
+	return use_two_bounces;
 }
 
 RID GIProbeData::get_rid() const {
@@ -149,19 +168,25 @@ RID GIProbeData::get_rid() const {
 	return probe;
 }
 
-void GIProbeData::_bind_methods() {
+void GIProbeData::_validate_property(PropertyInfo &property) const {
+	if (property.name == "anisotropy_strength") {
+		bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/quality/gi_probes/anisotropic");
+		if (!anisotropy_enabled) {
+			property.usage = PROPERTY_USAGE_NOEDITOR;
+		}
+	}
+}
 
-	ClassDB::bind_method(D_METHOD("set_bounds", "bounds"), &GIProbeData::set_bounds);
-	ClassDB::bind_method(D_METHOD("get_bounds"), &GIProbeData::get_bounds);
+void GIProbeData::_bind_methods() {
 
-	ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &GIProbeData::set_cell_size);
-	ClassDB::bind_method(D_METHOD("get_cell_size"), &GIProbeData::get_cell_size);
+	ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "octree_data", "octree_level_count"), &GIProbeData::allocate);
 
-	ClassDB::bind_method(D_METHOD("set_to_cell_xform", "to_cell_xform"), &GIProbeData::set_to_cell_xform);
+	ClassDB::bind_method(D_METHOD("get_bounds"), &GIProbeData::get_bounds);
+	ClassDB::bind_method(D_METHOD("get_octree_size"), &GIProbeData::get_octree_size);
 	ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &GIProbeData::get_to_cell_xform);
-
-	ClassDB::bind_method(D_METHOD("set_dynamic_data", "dynamic_data"), &GIProbeData::set_dynamic_data);
-	ClassDB::bind_method(D_METHOD("get_dynamic_data"), &GIProbeData::get_dynamic_data);
+	ClassDB::bind_method(D_METHOD("get_octree_cells"), &GIProbeData::get_octree_cells);
+	ClassDB::bind_method(D_METHOD("get_data_cells"), &GIProbeData::get_data_cells);
+	ClassDB::bind_method(D_METHOD("get_level_counts"), &GIProbeData::get_level_counts);
 
 	ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &GIProbeData::set_dynamic_range);
 	ClassDB::bind_method(D_METHOD("get_dynamic_range"), &GIProbeData::get_dynamic_range);
@@ -178,28 +203,40 @@ void GIProbeData::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &GIProbeData::set_propagation);
 	ClassDB::bind_method(D_METHOD("get_propagation"), &GIProbeData::get_propagation);
 
+	ClassDB::bind_method(D_METHOD("set_anisotropy_strength", "strength"), &GIProbeData::set_anisotropy_strength);
+	ClassDB::bind_method(D_METHOD("get_anisotropy_strength"), &GIProbeData::get_anisotropy_strength);
+
 	ClassDB::bind_method(D_METHOD("set_interior", "interior"), &GIProbeData::set_interior);
 	ClassDB::bind_method(D_METHOD("is_interior"), &GIProbeData::is_interior);
 
-	ClassDB::bind_method(D_METHOD("set_compress", "compress"), &GIProbeData::set_compress);
-	ClassDB::bind_method(D_METHOD("is_compressed"), &GIProbeData::is_compressed);
+	ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &GIProbeData::set_use_two_bounces);
+	ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &GIProbeData::is_using_two_bounces);
+
+	ClassDB::bind_method(D_METHOD("_set_data", "data"), &GIProbeData::_set_data);
+	ClassDB::bind_method(D_METHOD("_get_data"), &GIProbeData::_get_data);
 
-	ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_size", "get_cell_size");
-	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "to_cell_xform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_to_cell_xform", "get_to_cell_xform");
+	ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
 
-	ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "dynamic_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_dynamic_data", "get_dynamic_data");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_dynamic_range", "get_dynamic_range");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_energy", "get_energy");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bias", "get_bias");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_normal_bias", "get_normal_bias");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_propagation", "get_propagation");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_interior", "is_interior");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_compress", "is_compressed");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_range", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_dynamic_range", "get_dynamic_range");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_energy", "get_energy");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_bias", "get_bias");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_normal_bias", "get_normal_bias");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy_strength", "get_anisotropy_strength");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_two_bounces"), "set_use_two_bounces", "is_using_two_bounces");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
 }
 
 GIProbeData::GIProbeData() {
 
+	dynamic_range = 4;
+	energy = 1.0;
+	bias = 1.5;
+	normal_bias = 0.0;
+	propagation = 0.7;
+	anisotropy_strength = 0.5;
+	interior = false;
+
 	probe = VS::get_singleton()->gi_probe_create();
 }
 
@@ -251,89 +288,6 @@ Vector3 GIProbe::get_extents() const {
 	return extents;
 }
 
-void GIProbe::set_dynamic_range(int p_dynamic_range) {
-
-	dynamic_range = p_dynamic_range;
-}
-int GIProbe::get_dynamic_range() const {
-
-	return dynamic_range;
-}
-
-void GIProbe::set_energy(float p_energy) {
-
-	energy = p_energy;
-	if (probe_data.is_valid()) {
-		probe_data->set_energy(energy);
-	}
-}
-float GIProbe::get_energy() const {
-
-	return energy;
-}
-
-void GIProbe::set_bias(float p_bias) {
-
-	bias = p_bias;
-	if (probe_data.is_valid()) {
-		probe_data->set_bias(bias);
-	}
-}
-float GIProbe::get_bias() const {
-
-	return bias;
-}
-
-void GIProbe::set_normal_bias(float p_normal_bias) {
-
-	normal_bias = p_normal_bias;
-	if (probe_data.is_valid()) {
-		probe_data->set_normal_bias(normal_bias);
-	}
-}
-float GIProbe::get_normal_bias() const {
-
-	return normal_bias;
-}
-
-void GIProbe::set_propagation(float p_propagation) {
-
-	propagation = p_propagation;
-	if (probe_data.is_valid()) {
-		probe_data->set_propagation(propagation);
-	}
-}
-float GIProbe::get_propagation() const {
-
-	return propagation;
-}
-
-void GIProbe::set_interior(bool p_enable) {
-
-	interior = p_enable;
-	if (probe_data.is_valid()) {
-		probe_data->set_interior(p_enable);
-	}
-}
-
-bool GIProbe::is_interior() const {
-
-	return interior;
-}
-
-void GIProbe::set_compress(bool p_enable) {
-
-	compress = p_enable;
-	if (probe_data.is_valid()) {
-		probe_data->set_compress(p_enable);
-	}
-}
-
-bool GIProbe::is_compressed() const {
-
-	return compress;
-}
-
 void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
 
 	MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node);
@@ -397,9 +351,9 @@ GIProbe::BakeEndFunc GIProbe::bake_end_function = NULL;
 
 void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
 
-	static const int subdiv_value[SUBDIV_MAX] = { 7, 8, 9, 10 };
+	static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
 
-	VoxelLightBaker baker;
+	Voxelizer baker;
 
 	baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0));
 
@@ -431,8 +385,6 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
 
 	//create the data for visual server
 
-	PoolVector<int> data = baker.create_gi_probe_data();
-
 	if (p_create_visual_debug) {
 		MultiMeshInstance *mmi = memnew(MultiMeshInstance);
 		mmi->set_multimesh(baker.create_debug_multimesh());
@@ -454,17 +406,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
 		if (probe_data.is_null())
 			probe_data.instance();
 
-		probe_data->set_bounds(AABB(-extents, extents * 2.0));
-		probe_data->set_cell_size(baker.get_cell_size());
-		probe_data->set_dynamic_data(data);
-		probe_data->set_dynamic_range(dynamic_range);
-		probe_data->set_energy(energy);
-		probe_data->set_bias(bias);
-		probe_data->set_normal_bias(normal_bias);
-		probe_data->set_propagation(propagation);
-		probe_data->set_interior(interior);
-		probe_data->set_compress(compress);
-		probe_data->set_to_cell_xform(baker.get_to_cell_space_xform());
+		probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_giprobe_octree_size(), baker.get_giprobe_octree_cells(), baker.get_giprobe_data_cells(), baker.get_giprobe_level_cell_count());
 
 		set_probe_data(probe_data);
 	}
@@ -508,40 +450,12 @@ void GIProbe::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GIProbe::set_extents);
 	ClassDB::bind_method(D_METHOD("get_extents"), &GIProbe::get_extents);
 
-	ClassDB::bind_method(D_METHOD("set_dynamic_range", "max"), &GIProbe::set_dynamic_range);
-	ClassDB::bind_method(D_METHOD("get_dynamic_range"), &GIProbe::get_dynamic_range);
-
-	ClassDB::bind_method(D_METHOD("set_energy", "max"), &GIProbe::set_energy);
-	ClassDB::bind_method(D_METHOD("get_energy"), &GIProbe::get_energy);
-
-	ClassDB::bind_method(D_METHOD("set_bias", "max"), &GIProbe::set_bias);
-	ClassDB::bind_method(D_METHOD("get_bias"), &GIProbe::get_bias);
-
-	ClassDB::bind_method(D_METHOD("set_normal_bias", "max"), &GIProbe::set_normal_bias);
-	ClassDB::bind_method(D_METHOD("get_normal_bias"), &GIProbe::get_normal_bias);
-
-	ClassDB::bind_method(D_METHOD("set_propagation", "max"), &GIProbe::set_propagation);
-	ClassDB::bind_method(D_METHOD("get_propagation"), &GIProbe::get_propagation);
-
-	ClassDB::bind_method(D_METHOD("set_interior", "enable"), &GIProbe::set_interior);
-	ClassDB::bind_method(D_METHOD("is_interior"), &GIProbe::is_interior);
-
-	ClassDB::bind_method(D_METHOD("set_compress", "enable"), &GIProbe::set_compress);
-	ClassDB::bind_method(D_METHOD("is_compressed"), &GIProbe::is_compressed);
-
 	ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &GIProbe::bake, DEFVAL(Variant()), DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("debug_bake"), &GIProbe::_debug_bake);
 	ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
 
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_range", PROPERTY_HINT_RANGE, "1,16,1"), "set_dynamic_range", "get_dynamic_range");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_bias", "get_bias");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_normal_bias", "get_normal_bias");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compress"), "set_compress", "is_compressed");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data");
 
 	BIND_ENUM_CONSTANT(SUBDIV_64);
@@ -554,14 +468,7 @@ void GIProbe::_bind_methods() {
 GIProbe::GIProbe() {
 
 	subdiv = SUBDIV_128;
-	dynamic_range = 4;
-	energy = 1.0;
-	bias = 1.5;
-	normal_bias = 0.0;
-	propagation = 0.7;
 	extents = Vector3(10, 10, 10);
-	interior = false;
-	compress = false;
 
 	gi_probe = VS::get_singleton()->gi_probe_create();
 	set_disable_scale(true);

+ 33 - 45
scene/3d/gi_probe.h

@@ -40,42 +40,58 @@ class GIProbeData : public Resource {
 
 	RID probe;
 
+	void _set_data(const Dictionary &p_data);
+	Dictionary _get_data() const;
+
+	Transform to_cell_xform;
+	AABB bounds;
+	Vector3 octree_size;
+
+	float dynamic_range;
+	float energy;
+	float bias;
+	float normal_bias;
+	float propagation;
+	float anisotropy_strength;
+	bool interior;
+	bool use_two_bounces;
+
 protected:
 	static void _bind_methods();
+	void _validate_property(PropertyInfo &property) const;
 
 public:
-	void set_bounds(const AABB &p_bounds);
+	void allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts);
 	AABB get_bounds() const;
-
-	void set_cell_size(float p_size);
-	float get_cell_size() const;
-
-	void set_to_cell_xform(const Transform &p_xform);
+	Vector3 get_octree_size() const;
+	PoolVector<uint8_t> get_octree_cells() const;
+	PoolVector<uint8_t> get_data_cells() const;
+	PoolVector<int> get_level_counts() const;
 	Transform get_to_cell_xform() const;
 
-	void set_dynamic_data(const PoolVector<int> &p_data);
-	PoolVector<int> get_dynamic_data() const;
+	void set_dynamic_range(float p_range);
+	float get_dynamic_range() const;
 
-	void set_dynamic_range(int p_range);
-	int get_dynamic_range() const;
-
-	void set_propagation(float p_range);
+	void set_propagation(float p_propagation);
 	float get_propagation() const;
 
-	void set_energy(float p_range);
+	void set_anisotropy_strength(float p_anisotropy_strength);
+	float get_anisotropy_strength() const;
+
+	void set_energy(float p_energy);
 	float get_energy() const;
 
-	void set_bias(float p_range);
+	void set_bias(float p_bias);
 	float get_bias() const;
 
-	void set_normal_bias(float p_range);
+	void set_normal_bias(float p_normal_bias);
 	float get_normal_bias() const;
 
 	void set_interior(bool p_enable);
 	bool is_interior() const;
 
-	void set_compress(bool p_enable);
-	bool is_compressed() const;
+	void set_use_two_bounces(bool p_enable);
+	bool is_using_two_bounces() const;
 
 	virtual RID get_rid() const;
 
@@ -107,13 +123,6 @@ private:
 
 	Subdiv subdiv;
 	Vector3 extents;
-	int dynamic_range;
-	float energy;
-	float bias;
-	float normal_bias;
-	float propagation;
-	bool interior;
-	bool compress;
 
 	struct PlotMesh {
 		Ref<Material> override_material;
@@ -142,27 +151,6 @@ public:
 	void set_extents(const Vector3 &p_extents);
 	Vector3 get_extents() const;
 
-	void set_dynamic_range(int p_dynamic_range);
-	int get_dynamic_range() const;
-
-	void set_energy(float p_energy);
-	float get_energy() const;
-
-	void set_bias(float p_bias);
-	float get_bias() const;
-
-	void set_normal_bias(float p_normal_bias);
-	float get_normal_bias() const;
-
-	void set_propagation(float p_propagation);
-	float get_propagation() const;
-
-	void set_interior(bool p_enable);
-	bool is_interior() const;
-
-	void set_compress(bool p_enable);
-	bool is_compressed() const;
-
 	void bake(Node *p_from_node = NULL, bool p_create_visual_debug = false);
 
 	virtual AABB get_aabb() const;

+ 0 - 2486
scene/3d/voxel_light_baker.cpp

@@ -1,2486 +0,0 @@
-/*************************************************************************/
-/*  voxel_light_baker.cpp                                                */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "voxel_light_baker.h"
-
-#include "core/os/os.h"
-#include "core/os/threaded_array_processor.h"
-
-#include <stdlib.h>
-
-#define FINDMINMAX(x0, x1, x2, min, max) \
-	min = max = x0;                      \
-	if (x1 < min) min = x1;              \
-	if (x1 > max) max = x1;              \
-	if (x2 < min) min = x2;              \
-	if (x2 > max) max = x2;
-
-static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) {
-	int q;
-	Vector3 vmin, vmax;
-	for (q = 0; q <= 2; q++) {
-		if (normal[q] > 0.0f) {
-			vmin[q] = -maxbox[q];
-			vmax[q] = maxbox[q];
-		} else {
-			vmin[q] = maxbox[q];
-			vmax[q] = -maxbox[q];
-		}
-	}
-	if (normal.dot(vmin) + d > 0.0f) return false;
-	if (normal.dot(vmax) + d >= 0.0f) return true;
-
-	return false;
-}
-
-/*======================== X-tests ========================*/
-#define AXISTEST_X01(a, b, fa, fb)                 \
-	p0 = a * v0.y - b * v0.z;                      \
-	p2 = a * v2.y - b * v2.z;                      \
-	if (p0 < p2) {                                 \
-		min = p0;                                  \
-		max = p2;                                  \
-	} else {                                       \
-		min = p2;                                  \
-		max = p0;                                  \
-	}                                              \
-	rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
-	if (min > rad || max < -rad) return false;
-
-#define AXISTEST_X2(a, b, fa, fb)                  \
-	p0 = a * v0.y - b * v0.z;                      \
-	p1 = a * v1.y - b * v1.z;                      \
-	if (p0 < p1) {                                 \
-		min = p0;                                  \
-		max = p1;                                  \
-	} else {                                       \
-		min = p1;                                  \
-		max = p0;                                  \
-	}                                              \
-	rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
-	if (min > rad || max < -rad) return false;
-
-/*======================== Y-tests ========================*/
-#define AXISTEST_Y02(a, b, fa, fb)                 \
-	p0 = -a * v0.x + b * v0.z;                     \
-	p2 = -a * v2.x + b * v2.z;                     \
-	if (p0 < p2) {                                 \
-		min = p0;                                  \
-		max = p2;                                  \
-	} else {                                       \
-		min = p2;                                  \
-		max = p0;                                  \
-	}                                              \
-	rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
-	if (min > rad || max < -rad) return false;
-
-#define AXISTEST_Y1(a, b, fa, fb)                  \
-	p0 = -a * v0.x + b * v0.z;                     \
-	p1 = -a * v1.x + b * v1.z;                     \
-	if (p0 < p1) {                                 \
-		min = p0;                                  \
-		max = p1;                                  \
-	} else {                                       \
-		min = p1;                                  \
-		max = p0;                                  \
-	}                                              \
-	rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
-	if (min > rad || max < -rad) return false;
-
-/*======================== Z-tests ========================*/
-
-#define AXISTEST_Z12(a, b, fa, fb)                 \
-	p1 = a * v1.x - b * v1.y;                      \
-	p2 = a * v2.x - b * v2.y;                      \
-	if (p2 < p1) {                                 \
-		min = p2;                                  \
-		max = p1;                                  \
-	} else {                                       \
-		min = p1;                                  \
-		max = p2;                                  \
-	}                                              \
-	rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
-	if (min > rad || max < -rad) return false;
-
-#define AXISTEST_Z0(a, b, fa, fb)                  \
-	p0 = a * v0.x - b * v0.y;                      \
-	p1 = a * v1.x - b * v1.y;                      \
-	if (p0 < p1) {                                 \
-		min = p0;                                  \
-		max = p1;                                  \
-	} else {                                       \
-		min = p1;                                  \
-		max = p0;                                  \
-	}                                              \
-	rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
-	if (min > rad || max < -rad) return false;
-
-static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) {
-
-	/*    use separating axis theorem to test overlap between triangle and box */
-	/*    need to test for overlap in these directions: */
-	/*    1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
-	/*       we do not even need to test these) */
-	/*    2) normal of the triangle */
-	/*    3) crossproduct(edge from tri, {x,y,z}-directin) */
-	/*       this gives 3x3=9 more tests */
-	Vector3 v0, v1, v2;
-	float min, max, d, p0, p1, p2, rad, fex, fey, fez;
-	Vector3 normal, e0, e1, e2;
-
-	/* This is the fastest branch on Sun */
-	/* move everything so that the boxcenter is in (0,0,0) */
-
-	v0 = triverts[0] - boxcenter;
-	v1 = triverts[1] - boxcenter;
-	v2 = triverts[2] - boxcenter;
-
-	/* compute triangle edges */
-	e0 = v1 - v0; /* tri edge 0 */
-	e1 = v2 - v1; /* tri edge 1 */
-	e2 = v0 - v2; /* tri edge 2 */
-
-	/* Bullet 3:  */
-	/*  test the 9 tests first (this was faster) */
-	fex = Math::abs(e0.x);
-	fey = Math::abs(e0.y);
-	fez = Math::abs(e0.z);
-	AXISTEST_X01(e0.z, e0.y, fez, fey);
-	AXISTEST_Y02(e0.z, e0.x, fez, fex);
-	AXISTEST_Z12(e0.y, e0.x, fey, fex);
-
-	fex = Math::abs(e1.x);
-	fey = Math::abs(e1.y);
-	fez = Math::abs(e1.z);
-	AXISTEST_X01(e1.z, e1.y, fez, fey);
-	AXISTEST_Y02(e1.z, e1.x, fez, fex);
-	AXISTEST_Z0(e1.y, e1.x, fey, fex);
-
-	fex = Math::abs(e2.x);
-	fey = Math::abs(e2.y);
-	fez = Math::abs(e2.z);
-	AXISTEST_X2(e2.z, e2.y, fez, fey);
-	AXISTEST_Y1(e2.z, e2.x, fez, fex);
-	AXISTEST_Z12(e2.y, e2.x, fey, fex);
-
-	/* Bullet 1: */
-	/*  first test overlap in the {x,y,z}-directions */
-	/*  find min, max of the triangle each direction, and test for overlap in */
-	/*  that direction -- this is equivalent to testing a minimal AABB around */
-	/*  the triangle against the AABB */
-
-	/* test in X-direction */
-	FINDMINMAX(v0.x, v1.x, v2.x, min, max);
-	if (min > boxhalfsize.x || max < -boxhalfsize.x) return false;
-
-	/* test in Y-direction */
-	FINDMINMAX(v0.y, v1.y, v2.y, min, max);
-	if (min > boxhalfsize.y || max < -boxhalfsize.y) return false;
-
-	/* test in Z-direction */
-	FINDMINMAX(v0.z, v1.z, v2.z, min, max);
-	if (min > boxhalfsize.z || max < -boxhalfsize.z) return false;
-
-	/* Bullet 2: */
-	/*  test if the box intersects the plane of the triangle */
-	/*  compute plane equation of triangle: normal*x+d=0 */
-	normal = e0.cross(e1);
-	d = -normal.dot(v0); /* plane eq: normal.x+d=0 */
-	return planeBoxOverlap(normal, d, boxhalfsize); /* if true, box and triangle overlaps */
-}
-
-static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) {
-
-	if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) {
-		r_uv = p_uv[0];
-		r_normal = p_normal[0];
-		return;
-	}
-	if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) {
-		r_uv = p_uv[1];
-		r_normal = p_normal[1];
-		return;
-	}
-	if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) {
-		r_uv = p_uv[2];
-		r_normal = p_normal[2];
-		return;
-	}
-
-	Vector3 v0 = p_vtx[1] - p_vtx[0];
-	Vector3 v1 = p_vtx[2] - p_vtx[0];
-	Vector3 v2 = p_pos - p_vtx[0];
-
-	float d00 = v0.dot(v0);
-	float d01 = v0.dot(v1);
-	float d11 = v1.dot(v1);
-	float d20 = v2.dot(v0);
-	float d21 = v2.dot(v1);
-	float denom = (d00 * d11 - d01 * d01);
-	if (denom == 0) {
-		r_uv = p_uv[0];
-		r_normal = p_normal[0];
-		return;
-	}
-	float v = (d11 * d20 - d01 * d21) / denom;
-	float w = (d00 * d21 - d01 * d20) / denom;
-	float u = 1.0f - v - w;
-
-	r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w;
-	r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized();
-}
-
-void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
-
-	if (p_level == cell_subdiv - 1) {
-		//plot the face by guessing its albedo and emission value
-
-		//find best axis to map to, for scanning values
-		int closest_axis = 0;
-		float closest_dot = 0;
-
-		Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]);
-		Vector3 normal = plane.normal;
-
-		for (int i = 0; i < 3; i++) {
-
-			Vector3 axis;
-			axis[i] = 1.0;
-			float dot = ABS(normal.dot(axis));
-			if (i == 0 || dot > closest_dot) {
-				closest_axis = i;
-				closest_dot = dot;
-			}
-		}
-
-		Vector3 axis;
-		axis[closest_axis] = 1.0;
-		Vector3 t1;
-		t1[(closest_axis + 1) % 3] = 1.0;
-		Vector3 t2;
-		t2[(closest_axis + 2) % 3] = 1.0;
-
-		t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width);
-		t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width);
-
-		Color albedo_accum;
-		Color emission_accum;
-		Vector3 normal_accum;
-
-		float alpha = 0.0;
-
-		//map to a grid average in the best axis for this face
-		for (int i = 0; i < color_scan_cell_width; i++) {
-
-			Vector3 ofs_i = float(i) * t1;
-
-			for (int j = 0; j < color_scan_cell_width; j++) {
-
-				Vector3 ofs_j = float(j) * t2;
-
-				Vector3 from = p_aabb.position + ofs_i + ofs_j;
-				Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
-				Vector3 half = (to - from) * 0.5;
-
-				//is in this cell?
-				if (!fast_tri_box_overlap(from + half, half, p_vtx)) {
-					continue; //face does not span this cell
-				}
-
-				//go from -size to +size*2 to avoid skipping collisions
-				Vector3 ray_from = from + (t1 + t2) * 0.5 - axis * p_aabb.size[closest_axis];
-				Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis] * 2;
-
-				if (normal.dot(ray_from - ray_to) < 0) {
-					SWAP(ray_from, ray_to);
-				}
-
-				Vector3 intersection;
-
-				if (!plane.intersects_segment(ray_from, ray_to, &intersection)) {
-					if (ABS(plane.distance_to(ray_from)) < ABS(plane.distance_to(ray_to))) {
-						intersection = plane.project(ray_from);
-					} else {
-
-						intersection = plane.project(ray_to);
-					}
-				}
-
-				intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection);
-
-				Vector2 uv;
-				Vector3 lnormal;
-				get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal);
-				if (lnormal == Vector3()) //just in case normal as nor provided
-					lnormal = normal;
-
-				int uv_x = CLAMP(int(Math::fposmod(uv.x, 1.0f) * bake_texture_size), 0, bake_texture_size - 1);
-				int uv_y = CLAMP(int(Math::fposmod(uv.y, 1.0f) * bake_texture_size), 0, bake_texture_size - 1);
-
-				int ofs = uv_y * bake_texture_size + uv_x;
-				albedo_accum.r += p_material.albedo[ofs].r;
-				albedo_accum.g += p_material.albedo[ofs].g;
-				albedo_accum.b += p_material.albedo[ofs].b;
-				albedo_accum.a += p_material.albedo[ofs].a;
-
-				emission_accum.r += p_material.emission[ofs].r;
-				emission_accum.g += p_material.emission[ofs].g;
-				emission_accum.b += p_material.emission[ofs].b;
-
-				normal_accum += lnormal;
-
-				alpha += 1.0;
-			}
-		}
-
-		if (alpha == 0) {
-			//could not in any way get texture information.. so use closest point to center
-
-			Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]);
-			Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5);
-
-			Vector3 lnormal;
-			Vector2 uv;
-			get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal);
-			if (lnormal == Vector3()) //just in case normal as nor provided
-				lnormal = normal;
-
-			int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
-			int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
-
-			int ofs = uv_y * bake_texture_size + uv_x;
-
-			alpha = 1.0 / (color_scan_cell_width * color_scan_cell_width);
-
-			albedo_accum.r = p_material.albedo[ofs].r * alpha;
-			albedo_accum.g = p_material.albedo[ofs].g * alpha;
-			albedo_accum.b = p_material.albedo[ofs].b * alpha;
-			albedo_accum.a = p_material.albedo[ofs].a * alpha;
-
-			emission_accum.r = p_material.emission[ofs].r * alpha;
-			emission_accum.g = p_material.emission[ofs].g * alpha;
-			emission_accum.b = p_material.emission[ofs].b * alpha;
-
-			normal_accum = lnormal * alpha;
-
-		} else {
-
-			float accdiv = 1.0 / (color_scan_cell_width * color_scan_cell_width);
-			alpha *= accdiv;
-
-			albedo_accum.r *= accdiv;
-			albedo_accum.g *= accdiv;
-			albedo_accum.b *= accdiv;
-			albedo_accum.a *= accdiv;
-
-			emission_accum.r *= accdiv;
-			emission_accum.g *= accdiv;
-			emission_accum.b *= accdiv;
-
-			normal_accum *= accdiv;
-		}
-
-		//put this temporarily here, corrected in a later step
-		bake_cells.write[p_idx].albedo[0] += albedo_accum.r;
-		bake_cells.write[p_idx].albedo[1] += albedo_accum.g;
-		bake_cells.write[p_idx].albedo[2] += albedo_accum.b;
-		bake_cells.write[p_idx].emission[0] += emission_accum.r;
-		bake_cells.write[p_idx].emission[1] += emission_accum.g;
-		bake_cells.write[p_idx].emission[2] += emission_accum.b;
-		bake_cells.write[p_idx].normal[0] += normal_accum.x;
-		bake_cells.write[p_idx].normal[1] += normal_accum.y;
-		bake_cells.write[p_idx].normal[2] += normal_accum.z;
-		bake_cells.write[p_idx].alpha += alpha;
-
-	} else {
-		//go down
-
-		int half = (1 << (cell_subdiv - 1)) >> (p_level + 1);
-		for (int i = 0; i < 8; i++) {
-
-			AABB aabb = p_aabb;
-			aabb.size *= 0.5;
-
-			int nx = p_x;
-			int ny = p_y;
-			int nz = p_z;
-
-			if (i & 1) {
-				aabb.position.x += aabb.size.x;
-				nx += half;
-			}
-			if (i & 2) {
-				aabb.position.y += aabb.size.y;
-				ny += half;
-			}
-			if (i & 4) {
-				aabb.position.z += aabb.size.z;
-				nz += half;
-			}
-			//make sure to not plot beyond limits
-			if (nx < 0 || nx >= axis_cell_size[0] || ny < 0 || ny >= axis_cell_size[1] || nz < 0 || nz >= axis_cell_size[2])
-				continue;
-
-			{
-				AABB test_aabb = aabb;
-				//test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
-				Vector3 qsize = test_aabb.size * 0.5; //quarter size, for fast aabb test
-
-				if (!fast_tri_box_overlap(test_aabb.position + qsize, qsize, p_vtx)) {
-					//if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
-					//does not fit in child, go on
-					continue;
-				}
-			}
-
-			if (bake_cells[p_idx].children[i] == CHILD_EMPTY) {
-				//sub cell must be created
-
-				uint32_t child_idx = bake_cells.size();
-				bake_cells.write[p_idx].children[i] = child_idx;
-				bake_cells.resize(bake_cells.size() + 1);
-				bake_cells.write[child_idx].level = p_level + 1;
-			}
-
-			_plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb);
-		}
-	}
-}
-
-Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) {
-
-	Vector<Color> ret;
-
-	if (p_image.is_null() || p_image->empty()) {
-
-		ret.resize(bake_texture_size * bake_texture_size);
-		for (int i = 0; i < bake_texture_size * bake_texture_size; i++) {
-			ret.write[i] = p_color_add;
-		}
-
-		return ret;
-	}
-	p_image = p_image->duplicate();
-
-	if (p_image->is_compressed()) {
-		p_image->decompress();
-	}
-	p_image->convert(Image::FORMAT_RGBA8);
-	p_image->resize(bake_texture_size, bake_texture_size, Image::INTERPOLATE_CUBIC);
-
-	PoolVector<uint8_t>::Read r = p_image->get_data().read();
-	ret.resize(bake_texture_size * bake_texture_size);
-
-	for (int i = 0; i < bake_texture_size * bake_texture_size; i++) {
-		Color c;
-		c.r = (r[i * 4 + 0] / 255.0) * p_color_mul.r + p_color_add.r;
-		c.g = (r[i * 4 + 1] / 255.0) * p_color_mul.g + p_color_add.g;
-		c.b = (r[i * 4 + 2] / 255.0) * p_color_mul.b + p_color_add.b;
-
-		c.a = r[i * 4 + 3] / 255.0;
-
-		ret.write[i] = c;
-	}
-
-	return ret;
-}
-
-VoxelLightBaker::MaterialCache VoxelLightBaker::_get_material_cache(Ref<Material> p_material) {
-
-	//this way of obtaining materials is inaccurate and also does not support some compressed formats very well
-	Ref<StandardMaterial3D> mat = p_material;
-
-	Ref<Material> material = mat; //hack for now
-
-	if (material_cache.has(material)) {
-		return material_cache[material];
-	}
-
-	MaterialCache mc;
-
-	if (mat.is_valid()) {
-
-		Ref<Texture2D> albedo_tex = mat->get_texture(StandardMaterial3D::TEXTURE_ALBEDO);
-
-		Ref<Image> img_albedo;
-		if (albedo_tex.is_valid()) {
-
-			img_albedo = albedo_tex->get_data();
-			mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative
-		} else {
-			mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive
-		}
-
-		Ref<Texture2D> emission_tex = mat->get_texture(StandardMaterial3D::TEXTURE_EMISSION);
-
-		Color emission_col = mat->get_emission();
-		float emission_energy = mat->get_emission_energy();
-
-		Ref<Image> img_emission;
-
-		if (emission_tex.is_valid()) {
-
-			img_emission = emission_tex->get_data();
-		}
-
-		if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) {
-			mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy);
-		} else {
-			mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0));
-		}
-
-	} else {
-		Ref<Image> empty;
-
-		mc.albedo = _get_bake_texture(empty, Color(0, 0, 0), Color(1, 1, 1));
-		mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0));
-	}
-
-	material_cache[p_material] = mc;
-	return mc;
-}
-
-void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) {
-
-	for (int i = 0; i < p_mesh->get_surface_count(); i++) {
-
-		if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
-			continue; //only triangles
-
-		Ref<Material> src_material;
-
-		if (p_override_material.is_valid()) {
-			src_material = p_override_material;
-		} else if (i < p_materials.size() && p_materials[i].is_valid()) {
-			src_material = p_materials[i];
-		} else {
-			src_material = p_mesh->surface_get_material(i);
-		}
-		MaterialCache material = _get_material_cache(src_material);
-
-		Array a = p_mesh->surface_get_arrays(i);
-
-		PoolVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
-		PoolVector<Vector3>::Read vr = vertices.read();
-		PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
-		PoolVector<Vector2>::Read uvr;
-		PoolVector<Vector3> normals = a[Mesh::ARRAY_NORMAL];
-		PoolVector<Vector3>::Read nr;
-		PoolVector<int> index = a[Mesh::ARRAY_INDEX];
-
-		bool read_uv = false;
-		bool read_normals = false;
-
-		if (uv.size()) {
-
-			uvr = uv.read();
-			read_uv = true;
-		}
-
-		if (normals.size()) {
-			read_normals = true;
-			nr = normals.read();
-		}
-
-		if (index.size()) {
-
-			int facecount = index.size() / 3;
-			PoolVector<int>::Read ir = index.read();
-
-			for (int j = 0; j < facecount; j++) {
-
-				Vector3 vtxs[3];
-				Vector2 uvs[3];
-				Vector3 normal[3];
-
-				for (int k = 0; k < 3; k++) {
-					vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]);
-				}
-
-				if (read_uv) {
-					for (int k = 0; k < 3; k++) {
-						uvs[k] = uvr[ir[j * 3 + k]];
-					}
-				}
-
-				if (read_normals) {
-					for (int k = 0; k < 3; k++) {
-						normal[k] = nr[ir[j * 3 + k]];
-					}
-				}
-
-				//test against original bounds
-				if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
-					continue;
-				//plot
-				_plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
-			}
-
-		} else {
-
-			int facecount = vertices.size() / 3;
-
-			for (int j = 0; j < facecount; j++) {
-
-				Vector3 vtxs[3];
-				Vector2 uvs[3];
-				Vector3 normal[3];
-
-				for (int k = 0; k < 3; k++) {
-					vtxs[k] = p_xform.xform(vr[j * 3 + k]);
-				}
-
-				if (read_uv) {
-					for (int k = 0; k < 3; k++) {
-						uvs[k] = uvr[j * 3 + k];
-					}
-				}
-
-				if (read_normals) {
-					for (int k = 0; k < 3; k++) {
-						normal[k] = nr[j * 3 + k];
-					}
-				}
-
-				//test against original bounds
-				if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
-					continue;
-				//plot face
-				_plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
-			}
-		}
-	}
-
-	max_original_cells = bake_cells.size();
-}
-
-void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent) {
-
-	bake_light.write[p_idx].x = p_x;
-	bake_light.write[p_idx].y = p_y;
-	bake_light.write[p_idx].z = p_z;
-
-	if (p_level == cell_subdiv - 1) {
-
-		bake_light.write[p_idx].next_leaf = first_leaf;
-		first_leaf = p_idx;
-	} else {
-
-		//go down
-		int half = (1 << (cell_subdiv - 1)) >> (p_level + 1);
-		for (int i = 0; i < 8; i++) {
-
-			uint32_t child = bake_cells[p_idx].children[i];
-
-			if (child == CHILD_EMPTY)
-				continue;
-
-			int nx = p_x;
-			int ny = p_y;
-			int nz = p_z;
-
-			if (i & 1)
-				nx += half;
-			if (i & 2)
-				ny += half;
-			if (i & 4)
-				nz += half;
-
-			_init_light_plot(child, p_level + 1, nx, ny, nz, p_idx);
-		}
-	}
-}
-
-void VoxelLightBaker::begin_bake_light(BakeQuality p_quality, BakeMode p_bake_mode, float p_propagation, float p_energy) {
-	_check_init_light();
-	propagation = p_propagation;
-	bake_quality = p_quality;
-	bake_mode = p_bake_mode;
-	energy = p_energy;
-}
-
-void VoxelLightBaker::_check_init_light() {
-	if (bake_light.size() == 0) {
-
-		direct_lights_baked = false;
-		leaf_voxel_count = 0;
-		_fixup_plot(0, 0); //pre fixup, so normal, albedo, emission, etc. work for lighting.
-		bake_light.resize(bake_cells.size());
-		print_line("bake light size: " + itos(bake_light.size()));
-		//zeromem(bake_light.ptrw(), bake_light.size() * sizeof(Light));
-		first_leaf = -1;
-		_init_light_plot(0, 0, 0, 0, 0, CHILD_EMPTY);
-	}
-}
-
-static float _get_normal_advance(const Vector3 &p_normal) {
-
-	Vector3 normal = p_normal;
-	Vector3 unorm = normal.abs();
-
-	if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
-		// x code
-		unorm = normal.x > 0.0 ? Vector3(1.0, 0.0, 0.0) : Vector3(-1.0, 0.0, 0.0);
-	} else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
-		// y code
-		unorm = normal.y > 0.0 ? Vector3(0.0, 1.0, 0.0) : Vector3(0.0, -1.0, 0.0);
-	} else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
-		// z code
-		unorm = normal.z > 0.0 ? Vector3(0.0, 0.0, 1.0) : Vector3(0.0, 0.0, -1.0);
-	} else {
-		// oh-no we messed up code
-		// has to be
-		unorm = Vector3(1.0, 0.0, 0.0);
-	}
-
-	return 1.0 / normal.dot(unorm);
-}
-
-static const Vector3 aniso_normal[6] = {
-	Vector3(-1, 0, 0),
-	Vector3(1, 0, 0),
-	Vector3(0, -1, 0),
-	Vector3(0, 1, 0),
-	Vector3(0, 0, -1),
-	Vector3(0, 0, 1)
-};
-
-uint32_t VoxelLightBaker::_find_cell_at_pos(const Cell *cells, int x, int y, int z) {
-
-	uint32_t cell = 0;
-
-	int ofs_x = 0;
-	int ofs_y = 0;
-	int ofs_z = 0;
-	int size = 1 << (cell_subdiv - 1);
-	int half = size / 2;
-
-	if (x < 0 || x >= size)
-		return -1;
-	if (y < 0 || y >= size)
-		return -1;
-	if (z < 0 || z >= size)
-		return -1;
-
-	for (int i = 0; i < cell_subdiv - 1; i++) {
-
-		const Cell *bc = &cells[cell];
-
-		int child = 0;
-		if (x >= ofs_x + half) {
-			child |= 1;
-			ofs_x += half;
-		}
-		if (y >= ofs_y + half) {
-			child |= 2;
-			ofs_y += half;
-		}
-		if (z >= ofs_z + half) {
-			child |= 4;
-			ofs_z += half;
-		}
-
-		cell = bc->children[child];
-		if (cell == CHILD_EMPTY)
-			return CHILD_EMPTY;
-
-		half >>= 1;
-	}
-
-	return cell;
-}
-void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct) {
-
-	_check_init_light();
-
-	float max_len = Vector3(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]).length() * 1.1;
-
-	if (p_direct)
-		direct_lights_baked = true;
-
-	Vector3 light_axis = p_direction;
-	Plane clip[3];
-	int clip_planes = 0;
-
-	Light *light_data = bake_light.ptrw();
-	const Cell *cells = bake_cells.ptr();
-
-	for (int i = 0; i < 3; i++) {
-
-		if (Math::is_zero_approx(light_axis[i]))
-			continue;
-		clip[clip_planes].normal[i] = 1.0;
-
-		if (light_axis[i] < 0) {
-
-			clip[clip_planes].d = axis_cell_size[i] + 1;
-		} else {
-			clip[clip_planes].d -= 1.0;
-		}
-
-		clip_planes++;
-	}
-
-	float distance_adv = _get_normal_advance(light_axis);
-
-	int success_count = 0;
-
-	Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy;
-
-	int idx = first_leaf;
-	while (idx >= 0) {
-
-		Light *light = &light_data[idx];
-
-		Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
-		to += -light_axis.sign() * 0.47; //make it more likely to receive a ray
-
-		Vector3 from = to - max_len * light_axis;
-
-		for (int j = 0; j < clip_planes; j++) {
-
-			clip[j].intersects_segment(from, to, &from);
-		}
-
-		float distance = (to - from).length();
-		distance += distance_adv - Math::fmod(distance, distance_adv); //make it reach the center of the box always
-		from = to - light_axis * distance;
-
-		uint32_t result = 0xFFFFFFFF;
-
-		while (distance > -distance_adv) { //use this to avoid precision errors
-
-			result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z)));
-			if (result != 0xFFFFFFFF) {
-				break;
-			}
-
-			from += light_axis * distance_adv;
-			distance -= distance_adv;
-		}
-
-		if (result == (uint32_t)idx) {
-			//cell hit itself! hooray!
-
-			Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]);
-			if (normal == Vector3()) {
-				for (int i = 0; i < 6; i++) {
-					light->accum[i][0] += light_energy.x * cells[idx].albedo[0];
-					light->accum[i][1] += light_energy.y * cells[idx].albedo[1];
-					light->accum[i][2] += light_energy.z * cells[idx].albedo[2];
-				}
-
-			} else {
-
-				for (int i = 0; i < 6; i++) {
-					float s = MAX(0.0, aniso_normal[i].dot(-normal));
-					light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s;
-					light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s;
-					light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s;
-				}
-			}
-
-			if (p_direct) {
-				for (int i = 0; i < 6; i++) {
-					float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
-					light->direct_accum[i][0] += light_energy.x * s;
-					light->direct_accum[i][1] += light_energy.y * s;
-					light->direct_accum[i][2] += light_energy.z * s;
-				}
-			}
-			success_count++;
-		}
-
-		idx = light_data[idx].next_leaf;
-	}
-}
-
-void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct) {
-
-	_check_init_light();
-
-	if (p_direct)
-		direct_lights_baked = true;
-
-	Plane clip[3];
-	int clip_planes = 0;
-
-	// uint64_t us = OS::get_singleton()->get_ticks_usec();
-
-	Vector3 light_pos = to_cell_space.xform(p_pos) + Vector3(0.5, 0.5, 0.5);
-	//Vector3 spot_axis = -light_cache.transform.basis.get_axis(2).normalized();
-
-	float local_radius = to_cell_space.basis.xform(Vector3(0, 0, 1)).length() * p_radius;
-
-	Light *light_data = bake_light.ptrw();
-	const Cell *cells = bake_cells.ptr();
-	Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy;
-
-	int idx = first_leaf;
-	while (idx >= 0) {
-
-		Light *light = &light_data[idx];
-
-		Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
-		to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray
-
-		Vector3 light_axis = (to - light_pos).normalized();
-		float distance_adv = _get_normal_advance(light_axis);
-
-		Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]);
-
-		if (normal != Vector3() && normal.dot(-light_axis) < 0.001) {
-			idx = light_data[idx].next_leaf;
-			continue;
-		}
-
-		float att = 1.0;
-		{
-			float d = light_pos.distance_to(to);
-			if (d + distance_adv > local_radius) {
-				idx = light_data[idx].next_leaf;
-				continue; // too far away
-			}
-
-			float dt = CLAMP((d + distance_adv) / local_radius, 0, 1);
-			att *= powf(1.0 - dt, p_attenutation);
-		}
-
-		clip_planes = 0;
-
-		for (int c = 0; c < 3; c++) {
-
-			if (Math::is_zero_approx(light_axis[c]))
-				continue;
-			clip[clip_planes].normal[c] = 1.0;
-
-			if (light_axis[c] < 0) {
-
-				clip[clip_planes].d = (1 << (cell_subdiv - 1)) + 1;
-			} else {
-				clip[clip_planes].d -= 1.0;
-			}
-
-			clip_planes++;
-		}
-
-		Vector3 from = light_pos;
-
-		for (int j = 0; j < clip_planes; j++) {
-
-			clip[j].intersects_segment(from, to, &from);
-		}
-
-		float distance = (to - from).length();
-
-		distance -= Math::fmod(distance, distance_adv); //make it reach the center of the box always, but this tame make it closer
-		from = to - light_axis * distance;
-		to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray
-
-		uint32_t result = 0xFFFFFFFF;
-
-		while (distance > -distance_adv) { //use this to avoid precision errors
-
-			result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z)));
-			if (result != 0xFFFFFFFF) {
-				break;
-			}
-
-			from += light_axis * distance_adv;
-			distance -= distance_adv;
-		}
-
-		if (result == (uint32_t)idx) {
-			//cell hit itself! hooray!
-
-			if (normal == Vector3()) {
-				for (int i = 0; i < 6; i++) {
-					light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * att;
-					light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * att;
-					light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * att;
-				}
-
-			} else {
-
-				for (int i = 0; i < 6; i++) {
-					float s = MAX(0.0, aniso_normal[i].dot(-normal));
-					light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s * att;
-					light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s * att;
-					light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s * att;
-				}
-			}
-
-			if (p_direct) {
-				for (int i = 0; i < 6; i++) {
-					float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
-					light->direct_accum[i][0] += light_energy.x * s * att;
-					light->direct_accum[i][1] += light_energy.y * s * att;
-					light->direct_accum[i][2] += light_energy.z * s * att;
-				}
-			}
-		}
-
-		idx = light_data[idx].next_leaf;
-	}
-}
-
-void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct) {
-
-	_check_init_light();
-
-	if (p_direct)
-		direct_lights_baked = true;
-
-	Plane clip[3];
-	int clip_planes = 0;
-
-	// uint64_t us = OS::get_singleton()->get_ticks_usec();
-
-	Vector3 light_pos = to_cell_space.xform(p_pos) + Vector3(0.5, 0.5, 0.5);
-	Vector3 spot_axis = to_cell_space.basis.xform(p_axis).normalized();
-
-	float local_radius = to_cell_space.basis.xform(Vector3(0, 0, 1)).length() * p_radius;
-
-	Light *light_data = bake_light.ptrw();
-	const Cell *cells = bake_cells.ptr();
-	Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy;
-
-	int idx = first_leaf;
-	while (idx >= 0) {
-
-		Light *light = &light_data[idx];
-
-		Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
-
-		Vector3 light_axis = (to - light_pos).normalized();
-		float distance_adv = _get_normal_advance(light_axis);
-
-		Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]);
-
-		if (normal != Vector3() && normal.dot(-light_axis) < 0.001) {
-			idx = light_data[idx].next_leaf;
-			continue;
-		}
-
-		float angle = Math::rad2deg(Math::acos(light_axis.dot(-spot_axis)));
-		if (angle > p_spot_angle) {
-			idx = light_data[idx].next_leaf;
-			continue; // too far away
-		}
-
-		float att = Math::pow(1.0f - angle / p_spot_angle, p_spot_attenuation);
-
-		{
-			float d = light_pos.distance_to(to);
-			if (d + distance_adv > local_radius) {
-				idx = light_data[idx].next_leaf;
-				continue; // too far away
-			}
-
-			float dt = CLAMP((d + distance_adv) / local_radius, 0, 1);
-			att *= powf(1.0 - dt, p_attenutation);
-		}
-
-		clip_planes = 0;
-
-		for (int c = 0; c < 3; c++) {
-
-			if (Math::is_zero_approx(light_axis[c]))
-				continue;
-			clip[clip_planes].normal[c] = 1.0;
-
-			if (light_axis[c] < 0) {
-
-				clip[clip_planes].d = (1 << (cell_subdiv - 1)) + 1;
-			} else {
-				clip[clip_planes].d -= 1.0;
-			}
-
-			clip_planes++;
-		}
-
-		Vector3 from = light_pos;
-
-		for (int j = 0; j < clip_planes; j++) {
-
-			clip[j].intersects_segment(from, to, &from);
-		}
-
-		float distance = (to - from).length();
-
-		distance -= Math::fmod(distance, distance_adv); //make it reach the center of the box always, but this tame make it closer
-		from = to - light_axis * distance;
-
-		uint32_t result = 0xFFFFFFFF;
-
-		while (distance > -distance_adv) { //use this to avoid precision errors
-
-			result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z)));
-			if (result != 0xFFFFFFFF) {
-				break;
-			}
-
-			from += light_axis * distance_adv;
-			distance -= distance_adv;
-		}
-
-		if (result == (uint32_t)idx) {
-			//cell hit itself! hooray!
-
-			if (normal == Vector3()) {
-				for (int i = 0; i < 6; i++) {
-					light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * att;
-					light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * att;
-					light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * att;
-				}
-
-			} else {
-
-				for (int i = 0; i < 6; i++) {
-					float s = MAX(0.0, aniso_normal[i].dot(-normal));
-					light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s * att;
-					light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s * att;
-					light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s * att;
-				}
-			}
-
-			if (p_direct) {
-				for (int i = 0; i < 6; i++) {
-					float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
-					light->direct_accum[i][0] += light_energy.x * s * att;
-					light->direct_accum[i][1] += light_energy.y * s * att;
-					light->direct_accum[i][2] += light_energy.z * s * att;
-				}
-			}
-		}
-
-		idx = light_data[idx].next_leaf;
-	}
-}
-
-void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
-
-	if (p_level == cell_subdiv - 1) {
-
-		leaf_voxel_count++;
-		float alpha = bake_cells[p_idx].alpha;
-
-		bake_cells.write[p_idx].albedo[0] /= alpha;
-		bake_cells.write[p_idx].albedo[1] /= alpha;
-		bake_cells.write[p_idx].albedo[2] /= alpha;
-
-		//transfer emission to light
-		bake_cells.write[p_idx].emission[0] /= alpha;
-		bake_cells.write[p_idx].emission[1] /= alpha;
-		bake_cells.write[p_idx].emission[2] /= alpha;
-
-		bake_cells.write[p_idx].normal[0] /= alpha;
-		bake_cells.write[p_idx].normal[1] /= alpha;
-		bake_cells.write[p_idx].normal[2] /= alpha;
-
-		Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]);
-		if (n.length() < 0.01) {
-			//too much fight over normal, zero it
-			bake_cells.write[p_idx].normal[0] = 0;
-			bake_cells.write[p_idx].normal[1] = 0;
-			bake_cells.write[p_idx].normal[2] = 0;
-		} else {
-			n.normalize();
-			bake_cells.write[p_idx].normal[0] = n.x;
-			bake_cells.write[p_idx].normal[1] = n.y;
-			bake_cells.write[p_idx].normal[2] = n.z;
-		}
-
-		bake_cells.write[p_idx].alpha = 1.0;
-
-		/*if (bake_light.size()) {
-			for(int i=0;i<6;i++) {
-
-			}
-		}*/
-
-	} else {
-
-		//go down
-
-		bake_cells.write[p_idx].emission[0] = 0;
-		bake_cells.write[p_idx].emission[1] = 0;
-		bake_cells.write[p_idx].emission[2] = 0;
-		bake_cells.write[p_idx].normal[0] = 0;
-		bake_cells.write[p_idx].normal[1] = 0;
-		bake_cells.write[p_idx].normal[2] = 0;
-		bake_cells.write[p_idx].albedo[0] = 0;
-		bake_cells.write[p_idx].albedo[1] = 0;
-		bake_cells.write[p_idx].albedo[2] = 0;
-		if (bake_light.size()) {
-			for (int j = 0; j < 6; j++) {
-				bake_light.write[p_idx].accum[j][0] = 0;
-				bake_light.write[p_idx].accum[j][1] = 0;
-				bake_light.write[p_idx].accum[j][2] = 0;
-			}
-		}
-
-		float alpha_average = 0;
-		int children_found = 0;
-
-		for (int i = 0; i < 8; i++) {
-
-			uint32_t child = bake_cells[p_idx].children[i];
-
-			if (child == CHILD_EMPTY)
-				continue;
-
-			_fixup_plot(child, p_level + 1);
-			alpha_average += bake_cells[child].alpha;
-
-			if (bake_light.size() > 0) {
-				for (int j = 0; j < 6; j++) {
-					bake_light.write[p_idx].accum[j][0] += bake_light[child].accum[j][0];
-					bake_light.write[p_idx].accum[j][1] += bake_light[child].accum[j][1];
-					bake_light.write[p_idx].accum[j][2] += bake_light[child].accum[j][2];
-				}
-				bake_cells.write[p_idx].emission[0] += bake_cells[child].emission[0];
-				bake_cells.write[p_idx].emission[1] += bake_cells[child].emission[1];
-				bake_cells.write[p_idx].emission[2] += bake_cells[child].emission[2];
-			}
-
-			children_found++;
-		}
-
-		bake_cells.write[p_idx].alpha = alpha_average / 8.0;
-		if (bake_light.size() && children_found) {
-			float divisor = Math::lerp(8, children_found, propagation);
-			for (int j = 0; j < 6; j++) {
-				bake_light.write[p_idx].accum[j][0] /= divisor;
-				bake_light.write[p_idx].accum[j][1] /= divisor;
-				bake_light.write[p_idx].accum[j][2] /= divisor;
-			}
-			bake_cells.write[p_idx].emission[0] /= divisor;
-			bake_cells.write[p_idx].emission[1] /= divisor;
-			bake_cells.write[p_idx].emission[2] /= divisor;
-		}
-	}
-}
-
-//make sure any cell (save for the root) has an empty cell previous to it, so it can be interpolated into
-
-void VoxelLightBaker::_plot_triangle(Vector2 *vertices, Vector3 *positions, Vector3 *normals, LightMap *pixels, int width, int height) {
-
-	int x[3];
-	int y[3];
-
-	for (int j = 0; j < 3; j++) {
-
-		x[j] = vertices[j].x * width;
-		y[j] = vertices[j].y * height;
-		//x[j] = CLAMP(x[j], 0, bt.width - 1);
-		//y[j] = CLAMP(y[j], 0, bt.height - 1);
-	}
-
-	// sort the points vertically
-	if (y[1] > y[2]) {
-		SWAP(x[1], x[2]);
-		SWAP(y[1], y[2]);
-		SWAP(positions[1], positions[2]);
-		SWAP(normals[1], normals[2]);
-	}
-	if (y[0] > y[1]) {
-		SWAP(x[0], x[1]);
-		SWAP(y[0], y[1]);
-		SWAP(positions[0], positions[1]);
-		SWAP(normals[0], normals[1]);
-	}
-	if (y[1] > y[2]) {
-		SWAP(x[1], x[2]);
-		SWAP(y[1], y[2]);
-		SWAP(positions[1], positions[2]);
-		SWAP(normals[1], normals[2]);
-	}
-
-	double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1);
-	double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1);
-	double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1);
-	double xf = x[0];
-	double xt = x[0] + dx_upper; // if y[0] == y[1], special case
-	for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) {
-		if (yi >= 0) {
-			for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) {
-				//pixels[int(x + y * width)] = color;
-
-				Vector2 v0 = Vector2(x[1] - x[0], y[1] - y[0]);
-				Vector2 v1 = Vector2(x[2] - x[0], y[2] - y[0]);
-				//vertices[2] - vertices[0];
-				Vector2 v2 = Vector2(xi - x[0], yi - y[0]);
-				float d00 = v0.dot(v0);
-				float d01 = v0.dot(v1);
-				float d11 = v1.dot(v1);
-				float d20 = v2.dot(v0);
-				float d21 = v2.dot(v1);
-				float denom = (d00 * d11 - d01 * d01);
-				Vector3 pos;
-				Vector3 normal;
-				if (denom == 0) {
-					pos = positions[0];
-					normal = normals[0];
-				} else {
-					float v = (d11 * d20 - d01 * d21) / denom;
-					float w = (d00 * d21 - d01 * d20) / denom;
-					float u = 1.0f - v - w;
-					pos = positions[0] * u + positions[1] * v + positions[2] * w;
-					normal = normals[0] * u + normals[1] * v + normals[2] * w;
-				}
-
-				int ofs = yi * width + xi;
-				pixels[ofs].normal = normal;
-				pixels[ofs].pos = pos;
-			}
-
-			for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) {
-				//pixels[int(x + y * width)] = color;
-				Vector2 v0 = Vector2(x[1] - x[0], y[1] - y[0]);
-				Vector2 v1 = Vector2(x[2] - x[0], y[2] - y[0]);
-				//vertices[2] - vertices[0];
-				Vector2 v2 = Vector2(xi - x[0], yi - y[0]);
-				float d00 = v0.dot(v0);
-				float d01 = v0.dot(v1);
-				float d11 = v1.dot(v1);
-				float d20 = v2.dot(v0);
-				float d21 = v2.dot(v1);
-				float denom = (d00 * d11 - d01 * d01);
-				Vector3 pos;
-				Vector3 normal;
-				if (denom == 0) {
-					pos = positions[0];
-					normal = normals[0];
-				} else {
-					float v = (d11 * d20 - d01 * d21) / denom;
-					float w = (d00 * d21 - d01 * d20) / denom;
-					float u = 1.0f - v - w;
-					pos = positions[0] * u + positions[1] * v + positions[2] * w;
-					normal = normals[0] * u + normals[1] * v + normals[2] * w;
-				}
-
-				int ofs = yi * width + xi;
-				pixels[ofs].normal = normal;
-				pixels[ofs].pos = pos;
-			}
-		}
-		xf += dx_far;
-		if (yi < y[1])
-			xt += dx_upper;
-		else
-			xt += dx_low;
-	}
-}
-
-void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha) {
-
-	int size = 1 << (cell_subdiv - 1);
-
-	int clamp_v = size - 1;
-	//first of all, clamp
-	Vector3 pos;
-	pos.x = CLAMP(p_posf.x, 0, clamp_v);
-	pos.y = CLAMP(p_posf.y, 0, clamp_v);
-	pos.z = CLAMP(p_posf.z, 0, clamp_v);
-
-	float level = (cell_subdiv - 1) - p_level;
-
-	int target_level;
-	float level_filter;
-	if (level <= 0.0) {
-		level_filter = 0;
-		target_level = 0;
-	} else {
-		target_level = Math::ceil(level);
-		level_filter = target_level - level;
-	}
-
-	const Cell *cells = bake_cells.ptr();
-	const Light *light = bake_light.ptr();
-
-	Vector3 color[2][8];
-	float alpha[2][8];
-	zeromem(alpha, sizeof(float) * 2 * 8);
-
-	//find cell at given level first
-
-	for (int c = 0; c < 2; c++) {
-
-		int current_level = MAX(0, target_level - c);
-		int level_cell_size = (1 << (cell_subdiv - 1)) >> current_level;
-
-		for (int n = 0; n < 8; n++) {
-
-			int x = int(pos.x);
-			int y = int(pos.y);
-			int z = int(pos.z);
-
-			if (n & 1)
-				x += level_cell_size;
-			if (n & 2)
-				y += level_cell_size;
-			if (n & 4)
-				z += level_cell_size;
-
-			int ofs_x = 0;
-			int ofs_y = 0;
-			int ofs_z = 0;
-
-			x = CLAMP(x, 0, clamp_v);
-			y = CLAMP(y, 0, clamp_v);
-			z = CLAMP(z, 0, clamp_v);
-
-			int half = size / 2;
-			uint32_t cell = 0;
-			for (int i = 0; i < current_level; i++) {
-
-				const Cell *bc = &cells[cell];
-
-				int child = 0;
-				if (x >= ofs_x + half) {
-					child |= 1;
-					ofs_x += half;
-				}
-				if (y >= ofs_y + half) {
-					child |= 2;
-					ofs_y += half;
-				}
-				if (z >= ofs_z + half) {
-					child |= 4;
-					ofs_z += half;
-				}
-
-				cell = bc->children[child];
-				if (cell == CHILD_EMPTY)
-					break;
-
-				half >>= 1;
-			}
-
-			if (cell == CHILD_EMPTY) {
-				alpha[c][n] = 0;
-			} else {
-				alpha[c][n] = cells[cell].alpha;
-
-				for (int i = 0; i < 6; i++) {
-					//anisotropic read light
-					float amount = p_direction.dot(aniso_normal[i]);
-					if (amount < 0)
-						amount = 0;
-					color[c][n].x += light[cell].accum[i][0] * amount;
-					color[c][n].y += light[cell].accum[i][1] * amount;
-					color[c][n].z += light[cell].accum[i][2] * amount;
-				}
-
-				color[c][n].x += cells[cell].emission[0];
-				color[c][n].y += cells[cell].emission[1];
-				color[c][n].z += cells[cell].emission[2];
-			}
-		}
-	}
-
-	float target_level_size = size >> target_level;
-	Vector3 pos_fract[2];
-
-	pos_fract[0].x = Math::fmod(pos.x, target_level_size) / target_level_size;
-	pos_fract[0].y = Math::fmod(pos.y, target_level_size) / target_level_size;
-	pos_fract[0].z = Math::fmod(pos.z, target_level_size) / target_level_size;
-
-	target_level_size = size >> MAX(0, target_level - 1);
-
-	pos_fract[1].x = Math::fmod(pos.x, target_level_size) / target_level_size;
-	pos_fract[1].y = Math::fmod(pos.y, target_level_size) / target_level_size;
-	pos_fract[1].z = Math::fmod(pos.z, target_level_size) / target_level_size;
-
-	float alpha_interp[2];
-	Vector3 color_interp[2];
-
-	for (int i = 0; i < 2; i++) {
-
-		Vector3 color_x00 = color[i][0].linear_interpolate(color[i][1], pos_fract[i].x);
-		Vector3 color_xy0 = color[i][2].linear_interpolate(color[i][3], pos_fract[i].x);
-		Vector3 blend_z0 = color_x00.linear_interpolate(color_xy0, pos_fract[i].y);
-
-		Vector3 color_x0z = color[i][4].linear_interpolate(color[i][5], pos_fract[i].x);
-		Vector3 color_xyz = color[i][6].linear_interpolate(color[i][7], pos_fract[i].x);
-		Vector3 blend_z1 = color_x0z.linear_interpolate(color_xyz, pos_fract[i].y);
-
-		color_interp[i] = blend_z0.linear_interpolate(blend_z1, pos_fract[i].z);
-
-		float alpha_x00 = Math::lerp(alpha[i][0], alpha[i][1], pos_fract[i].x);
-		float alpha_xy0 = Math::lerp(alpha[i][2], alpha[i][3], pos_fract[i].x);
-		float alpha_z0 = Math::lerp(alpha_x00, alpha_xy0, pos_fract[i].y);
-
-		float alpha_x0z = Math::lerp(alpha[i][4], alpha[i][5], pos_fract[i].x);
-		float alpha_xyz = Math::lerp(alpha[i][6], alpha[i][7], pos_fract[i].x);
-		float alpha_z1 = Math::lerp(alpha_x0z, alpha_xyz, pos_fract[i].y);
-
-		alpha_interp[i] = Math::lerp(alpha_z0, alpha_z1, pos_fract[i].z);
-	}
-
-	r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter);
-	r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter);
-}
-
-Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture) {
-
-	float bias = 2.5;
-	float max_distance = (Vector3(1, 1, 1) * (1 << (cell_subdiv - 1))).length();
-
-	float dist = bias;
-	float alpha = 0.0;
-	Vector3 color;
-
-	Vector3 scolor;
-	float salpha;
-
-	while (dist < max_distance && alpha < 0.95) {
-		float diameter = MAX(1.0, 2.0 * p_aperture * dist);
-		_sample_baked_octree_filtered_and_anisotropic(p_pos + dist * p_normal, p_normal, log2(diameter), scolor, salpha);
-		float a = (1.0 - alpha);
-		color += scolor * a;
-		alpha += a * salpha;
-		dist += diameter * 0.5;
-	}
-
-	/*if (blend_ambient) {
-		color.rgb = mix(ambient,color.rgb,min(1.0,alpha/0.95));
-	}*/
-
-	return color;
-}
-
-Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) {
-
-	//find arbitrary tangent and bitangent, then build a matrix
-	Vector3 v0 = Math::abs(p_normal.z) < 0.999 ? Vector3(0, 0, 1) : Vector3(0, 1, 0);
-	Vector3 tangent = v0.cross(p_normal).normalized();
-	Vector3 bitangent = tangent.cross(p_normal).normalized();
-	Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed();
-
-	const Vector3 *cone_dirs = NULL;
-	const float *cone_weights = NULL;
-	int cone_dir_count = 0;
-	float cone_aperture = 0;
-
-	switch (bake_quality) {
-		case BAKE_QUALITY_LOW: {
-			//default quality
-			static const Vector3 dirs[4] = {
-				Vector3(Math_SQRT12, 0, Math_SQRT12),
-				Vector3(0, Math_SQRT12, Math_SQRT12),
-				Vector3(-Math_SQRT12, 0, Math_SQRT12),
-				Vector3(0, -Math_SQRT12, Math_SQRT12)
-			};
-
-			static const float weights[4] = { 0.25, 0.25, 0.25, 0.25 };
-
-			cone_dirs = dirs;
-			cone_dir_count = 4;
-			cone_aperture = 1.0; // tan(angle) 90 degrees
-			cone_weights = weights;
-		} break;
-		case BAKE_QUALITY_MEDIUM: {
-			//default quality
-			static const Vector3 dirs[6] = {
-				Vector3(0, 0, 1),
-				Vector3(0.866025, 0, 0.5),
-				Vector3(0.267617, 0.823639, 0.5),
-				Vector3(-0.700629, 0.509037, 0.5),
-				Vector3(-0.700629, -0.509037, 0.5),
-				Vector3(0.267617, -0.823639, 0.5)
-			};
-			static const float weights[6] = { 0.25f, 0.15f, 0.15f, 0.15f, 0.15f, 0.15f };
-			//
-			cone_dirs = dirs;
-			cone_dir_count = 6;
-			cone_aperture = 0.577; // tan(angle) 60 degrees
-			cone_weights = weights;
-		} break;
-		case BAKE_QUALITY_HIGH: {
-
-			//high qualily
-			static const Vector3 dirs[10] = {
-				Vector3(0.8781648411741658, 0.0, 0.478358141694643),
-				Vector3(0.5369754325592234, 0.6794204427701518, 0.5000452447267606),
-				Vector3(-0.19849436573466497, 0.8429904390140635, 0.49996710542041645),
-				Vector3(-0.7856196499811189, 0.3639120321329737, 0.5003696617825604),
-				Vector3(-0.7856196499811189, -0.3639120321329737, 0.5003696617825604),
-				Vector3(-0.19849436573466497, -0.8429904390140635, 0.49996710542041645),
-				Vector3(0.5369754325592234, -0.6794204427701518, 0.5000452447267606),
-				Vector3(-0.4451656858129485, 0.0, 0.8954482185892644),
-				Vector3(0.19124006749743122, 0.39355745585016605, 0.8991883926788214),
-				Vector3(0.19124006749743122, -0.39355745585016605, 0.8991883926788214),
-			};
-			static const float weights[10] = { 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.133333f, 0.133333f, 0.13333f };
-			cone_dirs = dirs;
-			cone_dir_count = 10;
-			cone_aperture = 0.404; // tan(angle) 45 degrees
-			cone_weights = weights;
-		} break;
-	}
-
-	Vector3 accum;
-
-	for (int i = 0; i < cone_dir_count; i++) {
-		Vector3 dir = normal_xform.xform(cone_dirs[i]).normalized(); //normal may not completely correct when transformed to cell
-		accum += _voxel_cone_trace(p_pos, dir, cone_aperture) * cone_weights[i];
-	}
-
-	return accum;
-}
-
-_ALWAYS_INLINE_ uint32_t xorshift32(uint32_t *state) {
-	/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
-	uint32_t x = *state;
-	x ^= x << 13;
-	x ^= x >> 17;
-	x ^= x << 5;
-	*state = x;
-	return x;
-}
-
-Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) {
-
-	int samples_per_quality[3] = { 48, 128, 512 };
-
-	int samples = samples_per_quality[bake_quality];
-
-	//create a basis in Z
-	Vector3 v0 = Math::abs(p_normal.z) < 0.999 ? Vector3(0, 0, 1) : Vector3(0, 1, 0);
-	Vector3 tangent = v0.cross(p_normal).normalized();
-	Vector3 bitangent = tangent.cross(p_normal).normalized();
-	Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed();
-
-	float bias = 1.5;
-	int max_level = cell_subdiv - 1;
-	int size = 1 << max_level;
-
-	Vector3 accum;
-	float spread = Math::deg2rad(80.0);
-
-	const Light *light = bake_light.ptr();
-	const Cell *cells = bake_cells.ptr();
-
-	uint32_t local_rng_state = rand(); //needs to be fixed again
-
-	for (int i = 0; i < samples; i++) {
-
-		float random_angle1 = (((xorshift32(&local_rng_state) % 65535) / 65535.0) * 2.0 - 1.0) * spread;
-		Vector3 axis(0, sin(random_angle1), cos(random_angle1));
-		float random_angle2 = ((xorshift32(&local_rng_state) % 65535) / 65535.0) * Math_PI * 2.0;
-		Basis rot(Vector3(0, 0, 1), random_angle2);
-		axis = rot.xform(axis);
-
-		Vector3 direction = normal_xform.xform(axis).normalized();
-
-		Vector3 advance = direction * _get_normal_advance(direction);
-
-		Vector3 pos = p_pos /*+ Vector3(0.5, 0.5, 0.5)*/ + advance * bias;
-
-		uint32_t cell = CHILD_EMPTY;
-
-		while (cell == CHILD_EMPTY) {
-
-			int x = int(pos.x);
-			int y = int(pos.y);
-			int z = int(pos.z);
-
-			int ofs_x = 0;
-			int ofs_y = 0;
-			int ofs_z = 0;
-			int half = size / 2;
-
-			if (x < 0 || x >= size)
-				break;
-			if (y < 0 || y >= size)
-				break;
-			if (z < 0 || z >= size)
-				break;
-
-			//int level_limit = max_level;
-
-			cell = 0; //start from root
-			for (int j = 0; j < max_level; j++) {
-
-				const Cell *bc = &cells[cell];
-
-				int child = 0;
-				if (x >= ofs_x + half) {
-					child |= 1;
-					ofs_x += half;
-				}
-				if (y >= ofs_y + half) {
-					child |= 2;
-					ofs_y += half;
-				}
-				if (z >= ofs_z + half) {
-					child |= 4;
-					ofs_z += half;
-				}
-
-				cell = bc->children[child];
-				if (unlikely(cell == CHILD_EMPTY))
-					break;
-
-				half >>= 1;
-			}
-
-			pos += advance;
-		}
-
-		if (unlikely(cell != CHILD_EMPTY)) {
-			for (int j = 0; j < 6; j++) {
-				//anisotropic read light
-				float amount = direction.dot(aniso_normal[j]);
-				if (amount <= 0)
-					continue;
-				accum.x += light[cell].accum[j][0] * amount;
-				accum.y += light[cell].accum[j][1] * amount;
-				accum.z += light[cell].accum[j][2] * amount;
-			}
-			accum.x += cells[cell].emission[0];
-			accum.y += cells[cell].emission[1];
-			accum.z += cells[cell].emission[2];
-		}
-	}
-
-	// Make sure we don't reset this thread's RNG state
-
-	return accum / samples;
-}
-
-void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) {
-
-	LightMap *pixel = &p_line[p_x];
-	if (pixel->pos == Vector3())
-		return;
-	switch (bake_mode) {
-		case BAKE_MODE_CONE_TRACE: {
-			pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy;
-		} break;
-		case BAKE_MODE_RAY_TRACE: {
-			pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy;
-		} break;
-	}
-}
-
-Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, float default_texels_per_unit, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) {
-
-	//transfer light information to a lightmap
-	Ref<Mesh> mesh = p_mesh;
-
-	//step 1 - create lightmap
-	int width;
-	int height;
-	Vector<LightMap> lightmap;
-	Transform xform = to_cell_space * p_xform;
-	if (mesh->get_lightmap_size_hint() == Size2()) {
-		double area = 0;
-		double uv_area = 0;
-		for (int i = 0; i < mesh->get_surface_count(); i++) {
-			Array arrays = mesh->surface_get_arrays(i);
-			PoolVector<Vector3> vertices = arrays[Mesh::ARRAY_VERTEX];
-			PoolVector<Vector2> uv2 = arrays[Mesh::ARRAY_TEX_UV2];
-			PoolVector<int> indices = arrays[Mesh::ARRAY_INDEX];
-
-			ERR_FAIL_COND_V(vertices.size() == 0, ERR_INVALID_PARAMETER);
-			ERR_FAIL_COND_V(uv2.size() == 0, ERR_INVALID_PARAMETER);
-
-			int vc = vertices.size();
-			PoolVector<Vector3>::Read vr = vertices.read();
-			PoolVector<Vector2>::Read u2r = uv2.read();
-			PoolVector<int>::Read ir;
-			int ic = 0;
-
-			if (indices.size()) {
-				ic = indices.size();
-				ir = indices.read();
-			}
-
-			int faces = ic ? ic / 3 : vc / 3;
-			for (int j = 0; j < faces; j++) {
-				Vector3 vertex[3];
-				Vector2 uv[3];
-
-				for (int k = 0; k < 3; k++) {
-					int idx = ic ? ir[j * 3 + k] : j * 3 + k;
-					vertex[k] = xform.xform(vr[idx]);
-					uv[k] = u2r[idx];
-				}
-
-				Vector3 p1 = vertex[0];
-				Vector3 p2 = vertex[1];
-				Vector3 p3 = vertex[2];
-				double a = p1.distance_to(p2);
-				double b = p2.distance_to(p3);
-				double c = p3.distance_to(p1);
-				double halfPerimeter = (a + b + c) / 2.0;
-				area += sqrt(halfPerimeter * (halfPerimeter - a) * (halfPerimeter - b) * (halfPerimeter - c));
-
-				Vector2 uv_p1 = uv[0];
-				Vector2 uv_p2 = uv[1];
-				Vector2 uv_p3 = uv[2];
-				double uv_a = uv_p1.distance_to(uv_p2);
-				double uv_b = uv_p2.distance_to(uv_p3);
-				double uv_c = uv_p3.distance_to(uv_p1);
-				double uv_halfPerimeter = (uv_a + uv_b + uv_c) / 2.0;
-				uv_area += sqrt(uv_halfPerimeter * (uv_halfPerimeter - uv_a) * (uv_halfPerimeter - uv_b) * (uv_halfPerimeter - uv_c));
-			}
-		}
-
-		if (uv_area < 0.0001f) {
-			uv_area = 1.0;
-		}
-
-		int pixels = (ceil((1.0 / sqrt(uv_area)) * sqrt(area * default_texels_per_unit)));
-		width = height = CLAMP(pixels, 2, 4096);
-	} else {
-		width = mesh->get_lightmap_size_hint().x;
-		height = mesh->get_lightmap_size_hint().y;
-	}
-
-	lightmap.resize(width * height);
-
-	//step 2 plot faces to lightmap
-	for (int i = 0; i < mesh->get_surface_count(); i++) {
-		Array arrays = mesh->surface_get_arrays(i);
-		PoolVector<Vector3> vertices = arrays[Mesh::ARRAY_VERTEX];
-		PoolVector<Vector3> normals = arrays[Mesh::ARRAY_NORMAL];
-		PoolVector<Vector2> uv2 = arrays[Mesh::ARRAY_TEX_UV2];
-		PoolVector<int> indices = arrays[Mesh::ARRAY_INDEX];
-
-		ERR_FAIL_COND_V(vertices.size() == 0, ERR_INVALID_PARAMETER);
-		ERR_FAIL_COND_V(normals.size() == 0, ERR_INVALID_PARAMETER);
-		ERR_FAIL_COND_V(uv2.size() == 0, ERR_INVALID_PARAMETER);
-
-		int vc = vertices.size();
-		PoolVector<Vector3>::Read vr = vertices.read();
-		PoolVector<Vector3>::Read nr = normals.read();
-		PoolVector<Vector2>::Read u2r = uv2.read();
-		PoolVector<int>::Read ir;
-		int ic = 0;
-
-		if (indices.size()) {
-			ic = indices.size();
-			ir = indices.read();
-		}
-
-		int faces = ic ? ic / 3 : vc / 3;
-		for (int j = 0; j < faces; j++) {
-			Vector3 vertex[3];
-			Vector3 normal[3];
-			Vector2 uv[3];
-
-			for (int k = 0; k < 3; k++) {
-				int idx = ic ? ir[j * 3 + k] : j * 3 + k;
-				vertex[k] = xform.xform(vr[idx]);
-				normal[k] = xform.basis.xform(nr[idx]).normalized();
-				uv[k] = u2r[idx];
-			}
-
-			_plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height);
-		}
-	}
-
-	//step 3 perform voxel cone trace on lightmap pixels
-	{
-		LightMap *lightmap_ptr = lightmap.ptrw();
-		uint64_t begin_time = OS::get_singleton()->get_ticks_usec();
-		volatile int lines = 0;
-
-		// make sure our OS-level rng is seeded
-
-		for (int i = 0; i < height; i++) {
-
-			thread_process_array(width, this, &VoxelLightBaker::_lightmap_bake_point, &lightmap_ptr[i * width]);
-
-			lines = MAX(lines, i); //for multithread
-			if (p_bake_time_func) {
-				uint64_t elapsed = OS::get_singleton()->get_ticks_usec() - begin_time;
-				float elapsed_sec = double(elapsed) / 1000000.0;
-				float remaining = lines < 1 ? 0 : (elapsed_sec / lines) * (height - lines - 1);
-				if (p_bake_time_func(p_bake_time_ud, remaining, lines / float(height))) {
-					return ERR_SKIP;
-				}
-			}
-		}
-
-		if (bake_mode == BAKE_MODE_RAY_TRACE) {
-			//blur
-			//gauss kernel, 7 step sigma 2
-			static const float gauss_kernel[4] = { 0.214607f, 0.189879f, 0.131514f, 0.071303f };
-			//horizontal pass
-			for (int i = 0; i < height; i++) {
-				for (int j = 0; j < width; j++) {
-					if (lightmap_ptr[i * width + j].normal == Vector3()) {
-						continue; //empty
-					}
-					float gauss_sum = gauss_kernel[0];
-					Vector3 accum = lightmap_ptr[i * width + j].light * gauss_kernel[0];
-					for (int k = 1; k < 4; k++) {
-						int new_x = j + k;
-						if (new_x >= width || lightmap_ptr[i * width + new_x].normal == Vector3())
-							break;
-						gauss_sum += gauss_kernel[k];
-						accum += lightmap_ptr[i * width + new_x].light * gauss_kernel[k];
-					}
-					for (int k = 1; k < 4; k++) {
-						int new_x = j - k;
-						if (new_x < 0 || lightmap_ptr[i * width + new_x].normal == Vector3())
-							break;
-						gauss_sum += gauss_kernel[k];
-						accum += lightmap_ptr[i * width + new_x].light * gauss_kernel[k];
-					}
-
-					lightmap_ptr[i * width + j].pos = accum /= gauss_sum;
-				}
-			}
-			//vertical pass
-			for (int i = 0; i < height; i++) {
-				for (int j = 0; j < width; j++) {
-					if (lightmap_ptr[i * width + j].normal == Vector3())
-						continue; //empty, don't write over it anyway
-					float gauss_sum = gauss_kernel[0];
-					Vector3 accum = lightmap_ptr[i * width + j].pos * gauss_kernel[0];
-					for (int k = 1; k < 4; k++) {
-						int new_y = i + k;
-						if (new_y >= height || lightmap_ptr[new_y * width + j].normal == Vector3())
-							break;
-						gauss_sum += gauss_kernel[k];
-						accum += lightmap_ptr[new_y * width + j].pos * gauss_kernel[k];
-					}
-					for (int k = 1; k < 4; k++) {
-						int new_y = i - k;
-						if (new_y < 0 || lightmap_ptr[new_y * width + j].normal == Vector3())
-							break;
-						gauss_sum += gauss_kernel[k];
-						accum += lightmap_ptr[new_y * width + j].pos * gauss_kernel[k];
-					}
-
-					lightmap_ptr[i * width + j].light = accum /= gauss_sum;
-				}
-			}
-		}
-
-		//add directional light (do this after blur)
-		{
-			const Cell *cells = bake_cells.ptr();
-			const Light *light = bake_light.ptr();
-#ifdef _OPENMP
-#pragma omp parallel
-#endif
-			for (int i = 0; i < height; i++) {
-#ifdef _OPENMP
-#pragma omp parallel for schedule(dynamic, 1)
-#endif
-				for (int j = 0; j < width; j++) {
-
-					//if (i == 125 && j == 280) {
-
-					LightMap *pixel = &lightmap_ptr[i * width + j];
-					if (pixel->pos == Vector3())
-						continue; //unused, skipe
-
-					int x = int(pixel->pos.x) - 1;
-					int y = int(pixel->pos.y) - 1;
-					int z = int(pixel->pos.z) - 1;
-					Color accum;
-					int size = 1 << (cell_subdiv - 1);
-
-					int found = 0;
-
-					for (int k = 0; k < 8; k++) {
-
-						int ofs_x = x;
-						int ofs_y = y;
-						int ofs_z = z;
-
-						if (k & 1)
-							ofs_x++;
-						if (k & 2)
-							ofs_y++;
-						if (k & 4)
-							ofs_z++;
-
-						if (x < 0 || x >= size)
-							continue;
-						if (y < 0 || y >= size)
-							continue;
-						if (z < 0 || z >= size)
-							continue;
-
-						uint32_t cell = _find_cell_at_pos(cells, ofs_x, ofs_y, ofs_z);
-
-						if (cell == CHILD_EMPTY)
-							continue;
-						for (int l = 0; l < 6; l++) {
-							float s = pixel->normal.dot(aniso_normal[l]);
-							if (s < 0)
-								s = 0;
-							accum.r += light[cell].direct_accum[l][0] * s;
-							accum.g += light[cell].direct_accum[l][1] * s;
-							accum.b += light[cell].direct_accum[l][2] * s;
-						}
-						found++;
-					}
-					if (found) {
-						accum /= found;
-						pixel->light.x += accum.r;
-						pixel->light.y += accum.g;
-						pixel->light.z += accum.b;
-					}
-				}
-			}
-		}
-
-		{
-			//fill gaps with neighbour vertices to avoid filter fades to black on edges
-
-			for (int i = 0; i < height; i++) {
-				for (int j = 0; j < width; j++) {
-					if (lightmap_ptr[i * width + j].normal != Vector3()) {
-						continue; //filled, skip
-					}
-
-					//this can't be made separatable..
-
-					int closest_i = -1, closest_j = 1;
-					float closest_dist = 1e20;
-
-					const int margin = 3;
-					for (int y = i - margin; y <= i + margin; y++) {
-						for (int x = j - margin; x <= j + margin; x++) {
-
-							if (x == j && y == i)
-								continue;
-							if (x < 0 || x >= width)
-								continue;
-							if (y < 0 || y >= height)
-								continue;
-							if (lightmap_ptr[y * width + x].normal == Vector3())
-								continue; //also ensures that blitted stuff is not reused
-
-							float dist = Vector2(i - y, j - x).length();
-							if (dist > closest_dist)
-								continue;
-
-							closest_dist = dist;
-							closest_i = y;
-							closest_j = x;
-						}
-					}
-
-					if (closest_i != -1) {
-						lightmap_ptr[i * width + j].light = lightmap_ptr[closest_i * width + closest_j].light;
-					}
-				}
-			}
-		}
-
-		{
-			//fill the lightmap data
-			r_lightmap.width = width;
-			r_lightmap.height = height;
-			r_lightmap.light.resize(lightmap.size() * 3);
-			PoolVector<float>::Write w = r_lightmap.light.write();
-			for (int i = 0; i < lightmap.size(); i++) {
-				w[i * 3 + 0] = lightmap[i].light.x;
-				w[i * 3 + 1] = lightmap[i].light.y;
-				w[i * 3 + 2] = lightmap[i].light.z;
-			}
-		}
-
-#if 0 // Enable for debugging.
-		{
-			PoolVector<uint8_t> img;
-			int ls = lightmap.size();
-			img.resize(ls * 3);
-			{
-				PoolVector<uint8_t>::Write w = img.write();
-				for (int i = 0; i < ls; i++) {
-					w[i * 3 + 0] = CLAMP(lightmap_ptr[i].light.x * 255, 0, 255);
-					w[i * 3 + 1] = CLAMP(lightmap_ptr[i].light.y * 255, 0, 255);
-					w[i * 3 + 2] = CLAMP(lightmap_ptr[i].light.z * 255, 0, 255);
-					//w[i * 3 + 0] = CLAMP(lightmap_ptr[i].normal.x * 255, 0, 255);
-					//w[i * 3 + 1] = CLAMP(lightmap_ptr[i].normal.y * 255, 0, 255);
-					//w[i * 3 + 2] = CLAMP(lightmap_ptr[i].normal.z * 255, 0, 255);
-					//w[i * 3 + 0] = CLAMP(lightmap_ptr[i].pos.x / (1 << (cell_subdiv - 1)) * 255, 0, 255);
-					//w[i * 3 + 1] = CLAMP(lightmap_ptr[i].pos.y / (1 << (cell_subdiv - 1)) * 255, 0, 255);
-					//w[i * 3 + 2] = CLAMP(lightmap_ptr[i].pos.z / (1 << (cell_subdiv - 1)) * 255, 0, 255);
-				}
-			}
-
-			Ref<Image> image;
-			image.instance();
-			image->create(width, height, false, Image::FORMAT_RGB8, img);
-
-			String name = p_mesh->get_name();
-			if (name == "") {
-				name = "Mesh" + itos(p_mesh->get_instance_id());
-			}
-			image->save_png(name + ".png");
-		}
-#endif
-	}
-
-	return OK;
-}
-
-void VoxelLightBaker::begin_bake(int p_subdiv, const AABB &p_bounds) {
-
-	original_bounds = p_bounds;
-	cell_subdiv = p_subdiv;
-	bake_cells.resize(1);
-	material_cache.clear();
-
-	//find out the actual real bounds, power of 2, which gets the highest subdivision
-	po2_bounds = p_bounds;
-	int longest_axis = po2_bounds.get_longest_axis_index();
-	axis_cell_size[longest_axis] = (1 << (cell_subdiv - 1));
-	leaf_voxel_count = 0;
-
-	for (int i = 0; i < 3; i++) {
-
-		if (i == longest_axis)
-			continue;
-
-		axis_cell_size[i] = axis_cell_size[longest_axis];
-		float axis_size = po2_bounds.size[longest_axis];
-
-		//shrink until fit subdiv
-		while (axis_size / 2.0 >= po2_bounds.size[i]) {
-			axis_size /= 2.0;
-			axis_cell_size[i] >>= 1;
-		}
-
-		po2_bounds.size[i] = po2_bounds.size[longest_axis];
-	}
-
-	Transform to_bounds;
-	to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis]));
-	to_bounds.origin = po2_bounds.position;
-
-	Transform to_grid;
-	to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis]));
-
-	to_cell_space = to_grid * to_bounds.affine_inverse();
-
-	cell_size = po2_bounds.size[longest_axis] / axis_cell_size[longest_axis];
-}
-
-void VoxelLightBaker::end_bake() {
-	_fixup_plot(0, 0);
-}
-
-//create the data for visual server
-
-PoolVector<int> VoxelLightBaker::create_gi_probe_data() {
-
-	PoolVector<int> data;
-
-	data.resize(16 + (8 + 1 + 1 + 1 + 1) * bake_cells.size()); //4 for header, rest for rest.
-
-	{
-		PoolVector<int>::Write w = data.write();
-
-		uint32_t *w32 = (uint32_t *)w.ptr();
-
-		w32[0] = 0; //version
-		w32[1] = cell_subdiv; //subdiv
-		w32[2] = axis_cell_size[0];
-		w32[3] = axis_cell_size[1];
-		w32[4] = axis_cell_size[2];
-		w32[5] = bake_cells.size();
-		w32[6] = leaf_voxel_count;
-
-		int ofs = 16;
-
-		for (int i = 0; i < bake_cells.size(); i++) {
-
-			for (int j = 0; j < 8; j++) {
-				w32[ofs++] = bake_cells[i].children[j];
-			}
-
-			{ //albedo
-				uint32_t rgba = uint32_t(CLAMP(bake_cells[i].albedo[0] * 255.0, 0, 255)) << 16;
-				rgba |= uint32_t(CLAMP(bake_cells[i].albedo[1] * 255.0, 0, 255)) << 8;
-				rgba |= uint32_t(CLAMP(bake_cells[i].albedo[2] * 255.0, 0, 255)) << 0;
-
-				w32[ofs++] = rgba;
-			}
-			{ //emission
-
-				Vector3 e(bake_cells[i].emission[0], bake_cells[i].emission[1], bake_cells[i].emission[2]);
-				float l = e.length();
-				if (l > 0) {
-					e.normalize();
-					l = CLAMP(l / 8.0, 0, 1.0);
-				}
-
-				uint32_t em = uint32_t(CLAMP(e[0] * 255, 0, 255)) << 24;
-				em |= uint32_t(CLAMP(e[1] * 255, 0, 255)) << 16;
-				em |= uint32_t(CLAMP(e[2] * 255, 0, 255)) << 8;
-				em |= uint32_t(CLAMP(l * 255, 0, 255));
-
-				w32[ofs++] = em;
-			}
-
-			//w32[ofs++]=bake_cells[i].used_sides;
-			{ //normal
-
-				Vector3 n(bake_cells[i].normal[0], bake_cells[i].normal[1], bake_cells[i].normal[2]);
-				n = n * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-				uint32_t norm = 0;
-
-				norm |= uint32_t(CLAMP(n.x * 255.0, 0, 255)) << 16;
-				norm |= uint32_t(CLAMP(n.y * 255.0, 0, 255)) << 8;
-				norm |= uint32_t(CLAMP(n.z * 255.0, 0, 255)) << 0;
-
-				w32[ofs++] = norm;
-			}
-
-			{
-				uint16_t alpha = MIN(uint32_t(bake_cells[i].alpha * 65535.0), 65535);
-				uint16_t level = bake_cells[i].level;
-
-				w32[ofs++] = (uint32_t(level) << 16) | uint32_t(alpha);
-			}
-		}
-	}
-
-	return data;
-}
-
-void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode) {
-
-	if (p_level == cell_subdiv - 1) {
-
-		Vector3 center = p_aabb.position + p_aabb.size * 0.5;
-		Transform xform;
-		xform.origin = center;
-		xform.basis.scale(p_aabb.size * 0.5);
-		p_multimesh->set_instance_transform(idx, xform);
-		Color col;
-		if (p_mode == DEBUG_ALBEDO) {
-			col = Color(bake_cells[p_idx].albedo[0], bake_cells[p_idx].albedo[1], bake_cells[p_idx].albedo[2]);
-		} else if (p_mode == DEBUG_LIGHT) {
-			for (int i = 0; i < 6; i++) {
-				col.r += bake_light[p_idx].accum[i][0];
-				col.g += bake_light[p_idx].accum[i][1];
-				col.b += bake_light[p_idx].accum[i][2];
-				col.r += bake_light[p_idx].direct_accum[i][0];
-				col.g += bake_light[p_idx].direct_accum[i][1];
-				col.b += bake_light[p_idx].direct_accum[i][2];
-			}
-		}
-		//Color col = Color(bake_cells[p_idx].emission[0], bake_cells[p_idx].emission[1], bake_cells[p_idx].emission[2]);
-		p_multimesh->set_instance_color(idx, col);
-
-		idx++;
-
-	} else {
-
-		for (int i = 0; i < 8; i++) {
-
-			uint32_t child = bake_cells[p_idx].children[i];
-
-			if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells)
-				continue;
-
-			AABB aabb = p_aabb;
-			aabb.size *= 0.5;
-
-			if (i & 1)
-				aabb.position.x += aabb.size.x;
-			if (i & 2)
-				aabb.position.y += aabb.size.y;
-			if (i & 4)
-				aabb.position.z += aabb.size.z;
-
-			_debug_mesh(bake_cells[p_idx].children[i], p_level + 1, aabb, p_multimesh, idx, p_mode);
-		}
-	}
-}
-
-Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
-
-	Ref<MultiMesh> mm;
-
-	ERR_FAIL_COND_V(p_mode == DEBUG_LIGHT && bake_light.size() == 0, mm);
-	mm.instance();
-
-	mm->set_transform_format(MultiMesh::TRANSFORM_3D);
-	mm->set_use_colors(true);
-	mm->set_instance_count(leaf_voxel_count);
-
-	Ref<ArrayMesh> mesh;
-	mesh.instance();
-
-	{
-		Array arr;
-		arr.resize(Mesh::ARRAY_MAX);
-
-		PoolVector<Vector3> vertices;
-		PoolVector<Color> colors;
-#define ADD_VTX(m_idx)                      \
-	;                                       \
-	vertices.push_back(face_points[m_idx]); \
-	colors.push_back(Color(1, 1, 1, 1));
-
-		for (int i = 0; i < 6; i++) {
-
-			Vector3 face_points[4];
-
-			for (int j = 0; j < 4; j++) {
-
-				float v[3];
-				v[0] = 1.0;
-				v[1] = 1 - 2 * ((j >> 1) & 1);
-				v[2] = v[1] * (1 - 2 * (j & 1));
-
-				for (int k = 0; k < 3; k++) {
-
-					if (i < 3)
-						face_points[j][(i + k) % 3] = v[k];
-					else
-						face_points[3 - j][(i + k) % 3] = -v[k];
-				}
-			}
-
-			//tri 1
-			ADD_VTX(0);
-			ADD_VTX(1);
-			ADD_VTX(2);
-			//tri 2
-			ADD_VTX(2);
-			ADD_VTX(3);
-			ADD_VTX(0);
-		}
-
-		arr[Mesh::ARRAY_VERTEX] = vertices;
-		arr[Mesh::ARRAY_COLOR] = colors;
-		mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr);
-	}
-
-	{
-		Ref<StandardMaterial3D> fsm;
-		fsm.instance();
-		fsm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
-		fsm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-		fsm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
-		fsm->set_albedo(Color(1, 1, 1, 1));
-
-		mesh->surface_set_material(0, fsm);
-	}
-
-	mm->set_mesh(mesh);
-
-	int idx = 0;
-	_debug_mesh(0, 0, po2_bounds, mm, idx, p_mode);
-
-	return mm;
-}
-
-struct VoxelLightBakerOctree {
-
-	enum {
-		CHILD_EMPTY = 0xFFFFFFFF
-	};
-
-	uint16_t light[6][3]; //anisotropic light
-	float alpha;
-	uint32_t children[8];
-};
-
-PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) {
-
-	p_subdiv = MIN(p_subdiv, cell_subdiv); // use the smaller one
-
-	Vector<uint32_t> remap;
-	int bc = bake_cells.size();
-	remap.resize(bc);
-	Vector<uint32_t> demap;
-
-	int new_size = 0;
-	for (int i = 0; i < bc; i++) {
-		uint32_t c = CHILD_EMPTY;
-		if (bake_cells[i].level < p_subdiv) {
-			c = new_size;
-			new_size++;
-			demap.push_back(i);
-		}
-		remap.write[i] = c;
-	}
-
-	Vector<VoxelLightBakerOctree> octree;
-	octree.resize(new_size);
-
-	for (int i = 0; i < new_size; i++) {
-		octree.write[i].alpha = bake_cells[demap[i]].alpha;
-		for (int j = 0; j < 6; j++) {
-			for (int k = 0; k < 3; k++) {
-				float l = bake_light[demap[i]].accum[j][k]; //add anisotropic light
-				l += bake_cells[demap[i]].emission[k]; //add emission
-				octree.write[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree
-			}
-		}
-
-		for (int j = 0; j < 8; j++) {
-			uint32_t child = bake_cells[demap[i]].children[j];
-			octree.write[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child];
-		}
-	}
-
-	PoolVector<uint8_t> ret;
-	int ret_bytes = octree.size() * sizeof(VoxelLightBakerOctree);
-	ret.resize(ret_bytes);
-	{
-		PoolVector<uint8_t>::Write w = ret.write();
-		copymem(w.ptr(), octree.ptr(), ret_bytes);
-	}
-
-	return ret;
-}
-
-float VoxelLightBaker::get_cell_size() const {
-	return cell_size;
-}
-
-Transform VoxelLightBaker::get_to_cell_space_xform() const {
-	return to_cell_space;
-}
-VoxelLightBaker::VoxelLightBaker() {
-	color_scan_cell_width = 4;
-	bake_texture_size = 128;
-	propagation = 0.85;
-	energy = 1.0;
-}

+ 1108 - 0
scene/3d/voxelizer.cpp

@@ -0,0 +1,1108 @@
+/*************************************************************************/
+/*  voxelizer.cpp                                                        */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "voxelizer.h"
+#include "core/os/os.h"
+#include "core/os/threaded_array_processor.h"
+
+#include <stdlib.h>
+
+#define FINDMINMAX(x0, x1, x2, min, max) \
+	min = max = x0;                      \
+	if (x1 < min) min = x1;              \
+	if (x1 > max) max = x1;              \
+	if (x2 < min) min = x2;              \
+	if (x2 > max) max = x2;
+
+static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) {
+	int q;
+	Vector3 vmin, vmax;
+	for (q = 0; q <= 2; q++) {
+		if (normal[q] > 0.0f) {
+			vmin[q] = -maxbox[q];
+			vmax[q] = maxbox[q];
+		} else {
+			vmin[q] = maxbox[q];
+			vmax[q] = -maxbox[q];
+		}
+	}
+	if (normal.dot(vmin) + d > 0.0f) return false;
+	if (normal.dot(vmax) + d >= 0.0f) return true;
+
+	return false;
+}
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb)                 \
+	p0 = a * v0.y - b * v0.z;                      \
+	p2 = a * v2.y - b * v2.z;                      \
+	if (p0 < p2) {                                 \
+		min = p0;                                  \
+		max = p2;                                  \
+	} else {                                       \
+		min = p2;                                  \
+		max = p0;                                  \
+	}                                              \
+	rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+	if (min > rad || max < -rad) return false;
+
+#define AXISTEST_X2(a, b, fa, fb)                  \
+	p0 = a * v0.y - b * v0.z;                      \
+	p1 = a * v1.y - b * v1.z;                      \
+	if (p0 < p1) {                                 \
+		min = p0;                                  \
+		max = p1;                                  \
+	} else {                                       \
+		min = p1;                                  \
+		max = p0;                                  \
+	}                                              \
+	rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+	if (min > rad || max < -rad) return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb)                 \
+	p0 = -a * v0.x + b * v0.z;                     \
+	p2 = -a * v2.x + b * v2.z;                     \
+	if (p0 < p2) {                                 \
+		min = p0;                                  \
+		max = p2;                                  \
+	} else {                                       \
+		min = p2;                                  \
+		max = p0;                                  \
+	}                                              \
+	rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+	if (min > rad || max < -rad) return false;
+
+#define AXISTEST_Y1(a, b, fa, fb)                  \
+	p0 = -a * v0.x + b * v0.z;                     \
+	p1 = -a * v1.x + b * v1.z;                     \
+	if (p0 < p1) {                                 \
+		min = p0;                                  \
+		max = p1;                                  \
+	} else {                                       \
+		min = p1;                                  \
+		max = p0;                                  \
+	}                                              \
+	rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+	if (min > rad || max < -rad) return false;
+
+/*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb)                 \
+	p1 = a * v1.x - b * v1.y;                      \
+	p2 = a * v2.x - b * v2.y;                      \
+	if (p2 < p1) {                                 \
+		min = p2;                                  \
+		max = p1;                                  \
+	} else {                                       \
+		min = p1;                                  \
+		max = p2;                                  \
+	}                                              \
+	rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+	if (min > rad || max < -rad) return false;
+
+#define AXISTEST_Z0(a, b, fa, fb)                  \
+	p0 = a * v0.x - b * v0.y;                      \
+	p1 = a * v1.x - b * v1.y;                      \
+	if (p0 < p1) {                                 \
+		min = p0;                                  \
+		max = p1;                                  \
+	} else {                                       \
+		min = p1;                                  \
+		max = p0;                                  \
+	}                                              \
+	rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+	if (min > rad || max < -rad) return false;
+
+static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) {
+
+	/*    use separating axis theorem to test overlap between triangle and box */
+	/*    need to test for overlap in these directions: */
+	/*    1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+	/*       we do not even need to test these) */
+	/*    2) normal of the triangle */
+	/*    3) crossproduct(edge from tri, {x,y,z}-directin) */
+	/*       this gives 3x3=9 more tests */
+	Vector3 v0, v1, v2;
+	float min, max, d, p0, p1, p2, rad, fex, fey, fez;
+	Vector3 normal, e0, e1, e2;
+
+	/* This is the fastest branch on Sun */
+	/* move everything so that the boxcenter is in (0,0,0) */
+
+	v0 = triverts[0] - boxcenter;
+	v1 = triverts[1] - boxcenter;
+	v2 = triverts[2] - boxcenter;
+
+	/* compute triangle edges */
+	e0 = v1 - v0; /* tri edge 0 */
+	e1 = v2 - v1; /* tri edge 1 */
+	e2 = v0 - v2; /* tri edge 2 */
+
+	/* Bullet 3:  */
+	/*  test the 9 tests first (this was faster) */
+	fex = Math::abs(e0.x);
+	fey = Math::abs(e0.y);
+	fez = Math::abs(e0.z);
+	AXISTEST_X01(e0.z, e0.y, fez, fey);
+	AXISTEST_Y02(e0.z, e0.x, fez, fex);
+	AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+	fex = Math::abs(e1.x);
+	fey = Math::abs(e1.y);
+	fez = Math::abs(e1.z);
+	AXISTEST_X01(e1.z, e1.y, fez, fey);
+	AXISTEST_Y02(e1.z, e1.x, fez, fex);
+	AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+	fex = Math::abs(e2.x);
+	fey = Math::abs(e2.y);
+	fez = Math::abs(e2.z);
+	AXISTEST_X2(e2.z, e2.y, fez, fey);
+	AXISTEST_Y1(e2.z, e2.x, fez, fex);
+	AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+	/* Bullet 1: */
+	/*  first test overlap in the {x,y,z}-directions */
+	/*  find min, max of the triangle each direction, and test for overlap in */
+	/*  that direction -- this is equivalent to testing a minimal AABB around */
+	/*  the triangle against the AABB */
+
+	/* test in X-direction */
+	FINDMINMAX(v0.x, v1.x, v2.x, min, max);
+	if (min > boxhalfsize.x || max < -boxhalfsize.x) return false;
+
+	/* test in Y-direction */
+	FINDMINMAX(v0.y, v1.y, v2.y, min, max);
+	if (min > boxhalfsize.y || max < -boxhalfsize.y) return false;
+
+	/* test in Z-direction */
+	FINDMINMAX(v0.z, v1.z, v2.z, min, max);
+	if (min > boxhalfsize.z || max < -boxhalfsize.z) return false;
+
+	/* Bullet 2: */
+	/*  test if the box intersects the plane of the triangle */
+	/*  compute plane equation of triangle: normal*x+d=0 */
+	normal = e0.cross(e1);
+	d = -normal.dot(v0); /* plane eq: normal.x+d=0 */
+	return planeBoxOverlap(normal, d, boxhalfsize); /* if true, box and triangle overlaps */
+}
+
+static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) {
+
+	if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) {
+		r_uv = p_uv[0];
+		r_normal = p_normal[0];
+		return;
+	}
+	if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) {
+		r_uv = p_uv[1];
+		r_normal = p_normal[1];
+		return;
+	}
+	if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) {
+		r_uv = p_uv[2];
+		r_normal = p_normal[2];
+		return;
+	}
+
+	Vector3 v0 = p_vtx[1] - p_vtx[0];
+	Vector3 v1 = p_vtx[2] - p_vtx[0];
+	Vector3 v2 = p_pos - p_vtx[0];
+
+	float d00 = v0.dot(v0);
+	float d01 = v0.dot(v1);
+	float d11 = v1.dot(v1);
+	float d20 = v2.dot(v0);
+	float d21 = v2.dot(v1);
+	float denom = (d00 * d11 - d01 * d01);
+	if (denom == 0) {
+		r_uv = p_uv[0];
+		r_normal = p_normal[0];
+		return;
+	}
+	float v = (d11 * d20 - d01 * d21) / denom;
+	float w = (d00 * d21 - d01 * d20) / denom;
+	float u = 1.0f - v - w;
+
+	r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w;
+	r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized();
+}
+
+void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
+
+	if (p_level == cell_subdiv) {
+		//plot the face by guessing its albedo and emission value
+
+		//find best axis to map to, for scanning values
+		int closest_axis = 0;
+		float closest_dot = 0;
+
+		Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]);
+		Vector3 normal = plane.normal;
+
+		for (int i = 0; i < 3; i++) {
+
+			Vector3 axis;
+			axis[i] = 1.0;
+			float dot = ABS(normal.dot(axis));
+			if (i == 0 || dot > closest_dot) {
+				closest_axis = i;
+				closest_dot = dot;
+			}
+		}
+
+		Vector3 axis;
+		axis[closest_axis] = 1.0;
+		Vector3 t1;
+		t1[(closest_axis + 1) % 3] = 1.0;
+		Vector3 t2;
+		t2[(closest_axis + 2) % 3] = 1.0;
+
+		t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width);
+		t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width);
+
+		Color albedo_accum;
+		Color emission_accum;
+		Vector3 normal_accum;
+
+		float alpha = 0.0;
+
+		//map to a grid average in the best axis for this face
+		for (int i = 0; i < color_scan_cell_width; i++) {
+
+			Vector3 ofs_i = float(i) * t1;
+
+			for (int j = 0; j < color_scan_cell_width; j++) {
+
+				Vector3 ofs_j = float(j) * t2;
+
+				Vector3 from = p_aabb.position + ofs_i + ofs_j;
+				Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
+				Vector3 half = (to - from) * 0.5;
+
+				//is in this cell?
+				if (!fast_tri_box_overlap(from + half, half, p_vtx)) {
+					continue; //face does not span this cell
+				}
+
+				//go from -size to +size*2 to avoid skipping collisions
+				Vector3 ray_from = from + (t1 + t2) * 0.5 - axis * p_aabb.size[closest_axis];
+				Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis] * 2;
+
+				if (normal.dot(ray_from - ray_to) < 0) {
+					SWAP(ray_from, ray_to);
+				}
+
+				Vector3 intersection;
+
+				if (!plane.intersects_segment(ray_from, ray_to, &intersection)) {
+					if (ABS(plane.distance_to(ray_from)) < ABS(plane.distance_to(ray_to))) {
+						intersection = plane.project(ray_from);
+					} else {
+
+						intersection = plane.project(ray_to);
+					}
+				}
+
+				intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection);
+
+				Vector2 uv;
+				Vector3 lnormal;
+				get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal);
+				if (lnormal == Vector3()) //just in case normal as nor provided
+					lnormal = normal;
+
+				int uv_x = CLAMP(int(Math::fposmod(uv.x, 1.0f) * bake_texture_size), 0, bake_texture_size - 1);
+				int uv_y = CLAMP(int(Math::fposmod(uv.y, 1.0f) * bake_texture_size), 0, bake_texture_size - 1);
+
+				int ofs = uv_y * bake_texture_size + uv_x;
+				albedo_accum.r += p_material.albedo[ofs].r;
+				albedo_accum.g += p_material.albedo[ofs].g;
+				albedo_accum.b += p_material.albedo[ofs].b;
+				albedo_accum.a += p_material.albedo[ofs].a;
+
+				emission_accum.r += p_material.emission[ofs].r;
+				emission_accum.g += p_material.emission[ofs].g;
+				emission_accum.b += p_material.emission[ofs].b;
+
+				normal_accum += lnormal;
+
+				alpha += 1.0;
+			}
+		}
+
+		if (alpha == 0) {
+			//could not in any way get texture information.. so use closest point to center
+
+			Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]);
+			Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5);
+
+			Vector3 lnormal;
+			Vector2 uv;
+			get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal);
+			if (lnormal == Vector3()) //just in case normal as nor provided
+				lnormal = normal;
+
+			int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
+			int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
+
+			int ofs = uv_y * bake_texture_size + uv_x;
+
+			alpha = 1.0 / (color_scan_cell_width * color_scan_cell_width);
+
+			albedo_accum.r = p_material.albedo[ofs].r * alpha;
+			albedo_accum.g = p_material.albedo[ofs].g * alpha;
+			albedo_accum.b = p_material.albedo[ofs].b * alpha;
+			albedo_accum.a = p_material.albedo[ofs].a * alpha;
+
+			emission_accum.r = p_material.emission[ofs].r * alpha;
+			emission_accum.g = p_material.emission[ofs].g * alpha;
+			emission_accum.b = p_material.emission[ofs].b * alpha;
+
+			normal_accum = lnormal * alpha;
+
+		} else {
+
+			float accdiv = 1.0 / (color_scan_cell_width * color_scan_cell_width);
+			alpha *= accdiv;
+
+			albedo_accum.r *= accdiv;
+			albedo_accum.g *= accdiv;
+			albedo_accum.b *= accdiv;
+			albedo_accum.a *= accdiv;
+
+			emission_accum.r *= accdiv;
+			emission_accum.g *= accdiv;
+			emission_accum.b *= accdiv;
+
+			normal_accum *= accdiv;
+		}
+
+		//put this temporarily here, corrected in a later step
+		bake_cells.write[p_idx].albedo[0] += albedo_accum.r;
+		bake_cells.write[p_idx].albedo[1] += albedo_accum.g;
+		bake_cells.write[p_idx].albedo[2] += albedo_accum.b;
+		bake_cells.write[p_idx].emission[0] += emission_accum.r;
+		bake_cells.write[p_idx].emission[1] += emission_accum.g;
+		bake_cells.write[p_idx].emission[2] += emission_accum.b;
+		bake_cells.write[p_idx].normal[0] += normal_accum.x;
+		bake_cells.write[p_idx].normal[1] += normal_accum.y;
+		bake_cells.write[p_idx].normal[2] += normal_accum.z;
+		bake_cells.write[p_idx].alpha += alpha;
+
+	} else {
+		//go down
+
+		int half = (1 << cell_subdiv) >> (p_level + 1);
+		for (int i = 0; i < 8; i++) {
+
+			AABB aabb = p_aabb;
+			aabb.size *= 0.5;
+
+			int nx = p_x;
+			int ny = p_y;
+			int nz = p_z;
+
+			if (i & 1) {
+				aabb.position.x += aabb.size.x;
+				nx += half;
+			}
+			if (i & 2) {
+				aabb.position.y += aabb.size.y;
+				ny += half;
+			}
+			if (i & 4) {
+				aabb.position.z += aabb.size.z;
+				nz += half;
+			}
+			//make sure to not plot beyond limits
+			if (nx < 0 || nx >= axis_cell_size[0] || ny < 0 || ny >= axis_cell_size[1] || nz < 0 || nz >= axis_cell_size[2])
+				continue;
+
+			{
+				AABB test_aabb = aabb;
+				//test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
+				Vector3 qsize = test_aabb.size * 0.5; //quarter size, for fast aabb test
+
+				if (!fast_tri_box_overlap(test_aabb.position + qsize, qsize, p_vtx)) {
+					//if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
+					//does not fit in child, go on
+					continue;
+				}
+			}
+
+			if (bake_cells[p_idx].children[i] == CHILD_EMPTY) {
+				//sub cell must be created
+
+				uint32_t child_idx = bake_cells.size();
+				bake_cells.write[p_idx].children[i] = child_idx;
+				bake_cells.resize(bake_cells.size() + 1);
+				bake_cells.write[child_idx].level = p_level + 1;
+				bake_cells.write[child_idx].x = nx / half;
+				bake_cells.write[child_idx].y = ny / half;
+				bake_cells.write[child_idx].z = nz / half;
+			}
+
+			_plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb);
+		}
+	}
+}
+
+Vector<Color> Voxelizer::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) {
+
+	Vector<Color> ret;
+
+	if (p_image.is_null() || p_image->empty()) {
+
+		ret.resize(bake_texture_size * bake_texture_size);
+		for (int i = 0; i < bake_texture_size * bake_texture_size; i++) {
+			ret.write[i] = p_color_add;
+		}
+
+		return ret;
+	}
+	p_image = p_image->duplicate();
+
+	if (p_image->is_compressed()) {
+		p_image->decompress();
+	}
+	p_image->convert(Image::FORMAT_RGBA8);
+	p_image->resize(bake_texture_size, bake_texture_size, Image::INTERPOLATE_CUBIC);
+
+	PoolVector<uint8_t>::Read r = p_image->get_data().read();
+	ret.resize(bake_texture_size * bake_texture_size);
+
+	for (int i = 0; i < bake_texture_size * bake_texture_size; i++) {
+		Color c;
+		c.r = (r[i * 4 + 0] / 255.0) * p_color_mul.r + p_color_add.r;
+		c.g = (r[i * 4 + 1] / 255.0) * p_color_mul.g + p_color_add.g;
+		c.b = (r[i * 4 + 2] / 255.0) * p_color_mul.b + p_color_add.b;
+
+		c.a = r[i * 4 + 3] / 255.0;
+
+		ret.write[i] = c;
+	}
+
+	return ret;
+}
+
+Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material) {
+
+	//this way of obtaining materials is inaccurate and also does not support some compressed formats very well
+	Ref<StandardMaterial3D> mat = p_material;
+
+	Ref<Material> material = mat; //hack for now
+
+	if (material_cache.has(material)) {
+		return material_cache[material];
+	}
+
+	MaterialCache mc;
+
+	if (mat.is_valid()) {
+
+		Ref<Texture2D> albedo_tex = mat->get_texture(StandardMaterial3D::TEXTURE_ALBEDO);
+
+		Ref<Image> img_albedo;
+		if (albedo_tex.is_valid()) {
+
+			img_albedo = albedo_tex->get_data();
+			mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative
+		} else {
+			mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive
+		}
+
+		Ref<Texture2D> emission_tex = mat->get_texture(StandardMaterial3D::TEXTURE_EMISSION);
+
+		Color emission_col = mat->get_emission();
+		float emission_energy = mat->get_emission_energy();
+
+		Ref<Image> img_emission;
+
+		if (emission_tex.is_valid()) {
+
+			img_emission = emission_tex->get_data();
+		}
+
+		if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) {
+			mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy);
+		} else {
+			mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0));
+		}
+
+	} else {
+		Ref<Image> empty;
+
+		mc.albedo = _get_bake_texture(empty, Color(0, 0, 0), Color(1, 1, 1));
+		mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0));
+	}
+
+	material_cache[p_material] = mc;
+	return mc;
+}
+
+void Voxelizer::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) {
+
+	for (int i = 0; i < p_mesh->get_surface_count(); i++) {
+
+		if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
+			continue; //only triangles
+
+		Ref<Material> src_material;
+
+		if (p_override_material.is_valid()) {
+			src_material = p_override_material;
+		} else if (i < p_materials.size() && p_materials[i].is_valid()) {
+			src_material = p_materials[i];
+		} else {
+			src_material = p_mesh->surface_get_material(i);
+		}
+		MaterialCache material = _get_material_cache(src_material);
+
+		Array a = p_mesh->surface_get_arrays(i);
+
+		PoolVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+		PoolVector<Vector3>::Read vr = vertices.read();
+		PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
+		PoolVector<Vector2>::Read uvr;
+		PoolVector<Vector3> normals = a[Mesh::ARRAY_NORMAL];
+		PoolVector<Vector3>::Read nr;
+		PoolVector<int> index = a[Mesh::ARRAY_INDEX];
+
+		bool read_uv = false;
+		bool read_normals = false;
+
+		if (uv.size()) {
+
+			uvr = uv.read();
+			read_uv = true;
+		}
+
+		if (normals.size()) {
+			read_normals = true;
+			nr = normals.read();
+		}
+
+		if (index.size()) {
+
+			int facecount = index.size() / 3;
+			PoolVector<int>::Read ir = index.read();
+
+			for (int j = 0; j < facecount; j++) {
+
+				Vector3 vtxs[3];
+				Vector2 uvs[3];
+				Vector3 normal[3];
+
+				for (int k = 0; k < 3; k++) {
+					vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]);
+				}
+
+				if (read_uv) {
+					for (int k = 0; k < 3; k++) {
+						uvs[k] = uvr[ir[j * 3 + k]];
+					}
+				}
+
+				if (read_normals) {
+					for (int k = 0; k < 3; k++) {
+						normal[k] = nr[ir[j * 3 + k]];
+					}
+				}
+
+				//test against original bounds
+				if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
+					continue;
+				//plot
+				_plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
+			}
+
+		} else {
+
+			int facecount = vertices.size() / 3;
+
+			for (int j = 0; j < facecount; j++) {
+
+				Vector3 vtxs[3];
+				Vector2 uvs[3];
+				Vector3 normal[3];
+
+				for (int k = 0; k < 3; k++) {
+					vtxs[k] = p_xform.xform(vr[j * 3 + k]);
+				}
+
+				if (read_uv) {
+					for (int k = 0; k < 3; k++) {
+						uvs[k] = uvr[j * 3 + k];
+					}
+				}
+
+				if (read_normals) {
+					for (int k = 0; k < 3; k++) {
+						normal[k] = nr[j * 3 + k];
+					}
+				}
+
+				//test against original bounds
+				if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
+					continue;
+				//plot face
+				_plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
+			}
+		}
+	}
+
+	max_original_cells = bake_cells.size();
+}
+
+void Voxelizer::_sort() {
+
+	// cells need to be sorted by level and coordinates
+	// it is important that level has more priority (for compute), and that Z has the least,
+	// given it may aid older implementations plot using GPU
+
+	Vector<CellSort> sorted_cells;
+	uint32_t cell_count = bake_cells.size();
+	sorted_cells.resize(cell_count);
+	{
+
+		CellSort *sort_cellsp = sorted_cells.ptrw();
+		const Cell *bake_cellsp = bake_cells.ptr();
+
+		for (uint32_t i = 0; i < cell_count; i++) {
+			sort_cellsp[i].x = bake_cellsp[i].x;
+			sort_cellsp[i].y = bake_cellsp[i].y;
+			sort_cellsp[i].z = bake_cellsp[i].z;
+			sort_cellsp[i].level = bake_cellsp[i].level;
+			sort_cellsp[i].index = i;
+		}
+	}
+
+	sorted_cells.sort();
+
+	//verify just in case, index 0 must be level 0
+	ERR_FAIL_COND(sorted_cells[0].level != 0);
+
+	Vector<Cell> new_bake_cells;
+	new_bake_cells.resize(cell_count);
+	Vector<uint32_t> reverse_map;
+
+	{
+		reverse_map.resize(cell_count);
+		const CellSort *sort_cellsp = sorted_cells.ptr();
+		uint32_t *reverse_mapp = reverse_map.ptrw();
+
+		for (uint32_t i = 0; i < cell_count; i++) {
+			reverse_mapp[sort_cellsp[i].index] = i;
+		}
+	}
+
+	{
+
+		const CellSort *sort_cellsp = sorted_cells.ptr();
+		const Cell *bake_cellsp = bake_cells.ptr();
+		const uint32_t *reverse_mapp = reverse_map.ptr();
+		Cell *new_bake_cellsp = new_bake_cells.ptrw();
+
+		for (uint32_t i = 0; i < cell_count; i++) {
+			//copy to new cell
+			new_bake_cellsp[i] = bake_cellsp[sort_cellsp[i].index];
+			//remap children
+			for (uint32_t j = 0; j < 8; j++) {
+				if (new_bake_cellsp[i].children[j] != CHILD_EMPTY) {
+					new_bake_cellsp[i].children[j] = reverse_mapp[new_bake_cellsp[i].children[j]];
+				}
+			}
+		}
+	}
+
+	bake_cells = new_bake_cells;
+	sorted = true;
+}
+
+void Voxelizer::_fixup_plot(int p_idx, int p_level) {
+
+	if (p_level == cell_subdiv) {
+
+		leaf_voxel_count++;
+		float alpha = bake_cells[p_idx].alpha;
+
+		bake_cells.write[p_idx].albedo[0] /= alpha;
+		bake_cells.write[p_idx].albedo[1] /= alpha;
+		bake_cells.write[p_idx].albedo[2] /= alpha;
+
+		//transfer emission to light
+		bake_cells.write[p_idx].emission[0] /= alpha;
+		bake_cells.write[p_idx].emission[1] /= alpha;
+		bake_cells.write[p_idx].emission[2] /= alpha;
+
+		bake_cells.write[p_idx].normal[0] /= alpha;
+		bake_cells.write[p_idx].normal[1] /= alpha;
+		bake_cells.write[p_idx].normal[2] /= alpha;
+
+		Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]);
+		if (n.length() < 0.01) {
+			//too much fight over normal, zero it
+			bake_cells.write[p_idx].normal[0] = 0;
+			bake_cells.write[p_idx].normal[1] = 0;
+			bake_cells.write[p_idx].normal[2] = 0;
+		} else {
+			n.normalize();
+			bake_cells.write[p_idx].normal[0] = n.x;
+			bake_cells.write[p_idx].normal[1] = n.y;
+			bake_cells.write[p_idx].normal[2] = n.z;
+		}
+
+		bake_cells.write[p_idx].alpha = 1.0;
+
+		/*if (bake_light.size()) {
+			for(int i=0;i<6;i++) {
+
+			}
+		}*/
+
+	} else {
+
+		//go down
+
+		bake_cells.write[p_idx].emission[0] = 0;
+		bake_cells.write[p_idx].emission[1] = 0;
+		bake_cells.write[p_idx].emission[2] = 0;
+		bake_cells.write[p_idx].normal[0] = 0;
+		bake_cells.write[p_idx].normal[1] = 0;
+		bake_cells.write[p_idx].normal[2] = 0;
+		bake_cells.write[p_idx].albedo[0] = 0;
+		bake_cells.write[p_idx].albedo[1] = 0;
+		bake_cells.write[p_idx].albedo[2] = 0;
+
+		float alpha_average = 0;
+		int children_found = 0;
+
+		for (int i = 0; i < 8; i++) {
+
+			uint32_t child = bake_cells[p_idx].children[i];
+
+			if (child == CHILD_EMPTY)
+				continue;
+
+			_fixup_plot(child, p_level + 1);
+			alpha_average += bake_cells[child].alpha;
+
+			children_found++;
+		}
+
+		bake_cells.write[p_idx].alpha = alpha_average / 8.0;
+	}
+}
+
+void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) {
+
+	sorted = false;
+	original_bounds = p_bounds;
+	cell_subdiv = p_subdiv;
+	bake_cells.resize(1);
+	material_cache.clear();
+
+	print_line("subdiv: " + itos(p_subdiv));
+	//find out the actual real bounds, power of 2, which gets the highest subdivision
+	po2_bounds = p_bounds;
+	int longest_axis = po2_bounds.get_longest_axis_index();
+	axis_cell_size[longest_axis] = 1 << cell_subdiv;
+	leaf_voxel_count = 0;
+
+	for (int i = 0; i < 3; i++) {
+
+		if (i == longest_axis)
+			continue;
+
+		axis_cell_size[i] = axis_cell_size[longest_axis];
+		float axis_size = po2_bounds.size[longest_axis];
+
+		//shrink until fit subdiv
+		while (axis_size / 2.0 >= po2_bounds.size[i]) {
+			axis_size /= 2.0;
+			axis_cell_size[i] >>= 1;
+		}
+
+		po2_bounds.size[i] = po2_bounds.size[longest_axis];
+	}
+
+	Transform to_bounds;
+	to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis]));
+	to_bounds.origin = po2_bounds.position;
+
+	Transform to_grid;
+	to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis]));
+
+	to_cell_space = to_grid * to_bounds.affine_inverse();
+
+	cell_size = po2_bounds.size[longest_axis] / axis_cell_size[longest_axis];
+}
+
+void Voxelizer::end_bake() {
+	if (!sorted) {
+		_sort();
+	}
+	_fixup_plot(0, 0);
+}
+
+//create the data for visual server
+
+int Voxelizer::get_gi_probe_octree_depth() const {
+	return cell_subdiv;
+}
+Vector3i Voxelizer::get_giprobe_octree_size() const {
+	return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]);
+}
+int Voxelizer::get_giprobe_cell_count() const {
+	return bake_cells.size();
+}
+
+PoolVector<uint8_t> Voxelizer::get_giprobe_octree_cells() const {
+	PoolVector<uint8_t> data;
+	data.resize((8 * 4) * bake_cells.size()); //8 uint32t values
+	{
+		PoolVector<uint8_t>::Write w = data.write();
+		uint32_t *children_cells = (uint32_t *)w.ptr();
+		const Cell *cells = bake_cells.ptr();
+
+		uint32_t cell_count = bake_cells.size();
+
+		for (uint32_t i = 0; i < cell_count; i++) {
+
+			for (uint32_t j = 0; j < 8; j++) {
+				children_cells[i * 8 + j] = cells[i].children[j];
+			}
+		}
+	}
+
+	return data;
+}
+PoolVector<uint8_t> Voxelizer::get_giprobe_data_cells() const {
+	PoolVector<uint8_t> data;
+	data.resize((4 * 4) * bake_cells.size()); //8 uint32t values
+	{
+		PoolVector<uint8_t>::Write w = data.write();
+		uint32_t *dataptr = (uint32_t *)w.ptr();
+		const Cell *cells = bake_cells.ptr();
+
+		uint32_t cell_count = bake_cells.size();
+
+		for (uint32_t i = 0; i < cell_count; i++) {
+
+			{ //position
+
+				uint32_t x = cells[i].x;
+				uint32_t y = cells[i].y;
+				uint32_t z = cells[i].z;
+
+				uint32_t position = x;
+				position |= y << 11;
+				position |= z << 21;
+
+				dataptr[i * 4 + 0] = position;
+			}
+
+			{ //albedo + alpha
+				uint32_t rgba = uint32_t(CLAMP(cells[i].alpha * 255.0, 0, 255)) << 24; //a
+				rgba |= uint32_t(CLAMP(cells[i].albedo[2] * 255.0, 0, 255)) << 16; //b
+				rgba |= uint32_t(CLAMP(cells[i].albedo[1] * 255.0, 0, 255)) << 8; //g
+				rgba |= uint32_t(CLAMP(cells[i].albedo[0] * 255.0, 0, 255)); //r
+
+				dataptr[i * 4 + 1] = rgba;
+			}
+
+			{ //emission, as rgbe9995
+				Color emission = Color(cells[i].emission[0], cells[i].emission[1], cells[i].emission[2]);
+				dataptr[i * 4 + 2] = emission.to_rgbe9995();
+			}
+
+			{ //normal
+
+				Vector3 n(bake_cells[i].normal[0], bake_cells[i].normal[1], bake_cells[i].normal[2]);
+				n.normalize();
+
+				uint32_t normal = uint32_t(uint8_t(int8_t(CLAMP(n.x * 127.0, -128, 127))));
+				normal |= uint32_t(uint8_t(int8_t(CLAMP(n.y * 127.0, -128, 127)))) << 8;
+				normal |= uint32_t(uint8_t(int8_t(CLAMP(n.z * 127.0, -128, 127)))) << 16;
+
+				dataptr[i * 4 + 3] = normal;
+			}
+		}
+	}
+
+	return data;
+}
+
+PoolVector<int> Voxelizer::get_giprobe_level_cell_count() const {
+	uint32_t cell_count = bake_cells.size();
+	const Cell *cells = bake_cells.ptr();
+	PoolVector<int> level_count;
+	level_count.resize(cell_subdiv + 1); //remember, always x+1 levels for x subdivisions
+	{
+		PoolVector<int>::Write w = level_count.write();
+		for (int i = 0; i < cell_subdiv; i++) {
+			w[i] = 0;
+		}
+
+		for (uint32_t i = 0; i < cell_count; i++) {
+			w[cells[i].level]++;
+		}
+	}
+
+	return level_count;
+}
+
+void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) {
+
+	if (p_level == cell_subdiv - 1) {
+
+		Vector3 center = p_aabb.position + p_aabb.size * 0.5;
+		Transform xform;
+		xform.origin = center;
+		xform.basis.scale(p_aabb.size * 0.5);
+		p_multimesh->set_instance_transform(idx, xform);
+		Color col;
+		col = Color(bake_cells[p_idx].albedo[0], bake_cells[p_idx].albedo[1], bake_cells[p_idx].albedo[2]);
+		//Color col = Color(bake_cells[p_idx].emission[0], bake_cells[p_idx].emission[1], bake_cells[p_idx].emission[2]);
+		p_multimesh->set_instance_color(idx, col);
+
+		idx++;
+
+	} else {
+
+		for (int i = 0; i < 8; i++) {
+
+			uint32_t child = bake_cells[p_idx].children[i];
+
+			if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells)
+				continue;
+
+			AABB aabb = p_aabb;
+			aabb.size *= 0.5;
+
+			if (i & 1)
+				aabb.position.x += aabb.size.x;
+			if (i & 2)
+				aabb.position.y += aabb.size.y;
+			if (i & 4)
+				aabb.position.z += aabb.size.z;
+
+			_debug_mesh(bake_cells[p_idx].children[i], p_level + 1, aabb, p_multimesh, idx);
+		}
+	}
+}
+
+Ref<MultiMesh> Voxelizer::create_debug_multimesh() {
+
+	Ref<MultiMesh> mm;
+
+	mm.instance();
+
+	mm->set_transform_format(MultiMesh::TRANSFORM_3D);
+	mm->set_use_colors(true);
+	mm->set_instance_count(leaf_voxel_count);
+
+	Ref<ArrayMesh> mesh;
+	mesh.instance();
+
+	{
+		Array arr;
+		arr.resize(Mesh::ARRAY_MAX);
+
+		PoolVector<Vector3> vertices;
+		PoolVector<Color> colors;
+#define ADD_VTX(m_idx)                      \
+	vertices.push_back(face_points[m_idx]); \
+	colors.push_back(Color(1, 1, 1, 1));
+
+		for (int i = 0; i < 6; i++) {
+
+			Vector3 face_points[4];
+
+			for (int j = 0; j < 4; j++) {
+
+				float v[3];
+				v[0] = 1.0;
+				v[1] = 1 - 2 * ((j >> 1) & 1);
+				v[2] = v[1] * (1 - 2 * (j & 1));
+
+				for (int k = 0; k < 3; k++) {
+
+					if (i < 3)
+						face_points[j][(i + k) % 3] = v[k];
+					else
+						face_points[3 - j][(i + k) % 3] = -v[k];
+				}
+			}
+
+			//tri 1
+			ADD_VTX(0);
+			ADD_VTX(1);
+			ADD_VTX(2);
+			//tri 2
+			ADD_VTX(2);
+			ADD_VTX(3);
+			ADD_VTX(0);
+		}
+
+		arr[Mesh::ARRAY_VERTEX] = vertices;
+		arr[Mesh::ARRAY_COLOR] = colors;
+		mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr);
+	}
+
+	{
+		Ref<StandardMaterial3D> fsm;
+		fsm.instance();
+		fsm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+		fsm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+		fsm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+		fsm->set_albedo(Color(1, 1, 1, 1));
+
+		mesh->surface_set_material(0, fsm);
+	}
+
+	mm->set_mesh(mesh);
+
+	int idx = 0;
+	_debug_mesh(0, 0, po2_bounds, mm, idx);
+
+	return mm;
+}
+
+Transform Voxelizer::get_to_cell_space_xform() const {
+	return to_cell_space;
+}
+Voxelizer::Voxelizer() {
+	sorted = false;
+	color_scan_cell_width = 4;
+	bake_texture_size = 128;
+}

+ 35 - 81
scene/3d/voxel_light_baker.h → scene/3d/voxelizer.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  voxel_light_baker.h                                                  */
+/*  voxelizer.h                                                          */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -31,27 +31,11 @@
 #ifndef VOXEL_LIGHT_BAKER_H
 #define VOXEL_LIGHT_BAKER_H
 
+#include "core/math/vector3i.h"
 #include "scene/3d/mesh_instance.h"
 #include "scene/resources/multimesh.h"
 
-class VoxelLightBaker {
-public:
-	enum DebugMode {
-		DEBUG_ALBEDO,
-		DEBUG_LIGHT
-	};
-
-	enum BakeQuality {
-		BAKE_QUALITY_LOW,
-		BAKE_QUALITY_MEDIUM,
-		BAKE_QUALITY_HIGH
-	};
-
-	enum BakeMode {
-		BAKE_MODE_CONE_TRACE,
-		BAKE_MODE_RAY_TRACE,
-	};
-
+class Voxelizer {
 private:
 	enum {
 		CHILD_EMPTY = 0xFFFFFFFF
@@ -66,7 +50,10 @@ private:
 		float normal[3];
 		uint32_t used_sides;
 		float alpha; //used for upsampling
-		int level;
+		uint16_t x;
+		uint16_t y;
+		uint16_t z;
+		uint16_t level;
 
 		Cell() {
 			for (int i = 0; i < 8; i++) {
@@ -80,6 +67,7 @@ private:
 			}
 			alpha = 0;
 			used_sides = 0;
+			x = y = z = 0;
 			level = 0;
 		}
 	};
@@ -87,27 +75,24 @@ private:
 	Vector<Cell> bake_cells;
 	int cell_subdiv;
 
-	struct Light {
-		int x, y, z;
-		float accum[6][3]; //rgb anisotropic
-		float direct_accum[6][3]; //for direct bake
-		int next_leaf;
-		Light() {
-			x = y = z = 0;
-			for (int i = 0; i < 6; i++) {
-				for (int j = 0; j < 3; j++) {
-					accum[i][j] = 0;
-					direct_accum[i][j] = 0;
-				}
-			}
-			next_leaf = 0;
+	struct CellSort {
+		union {
+			struct {
+				uint64_t z : 16;
+				uint64_t y : 16;
+				uint64_t x : 16;
+				uint64_t level : 16;
+			};
+			uint64_t key;
+		};
+
+		int32_t index;
+
+		_FORCE_INLINE_ bool operator<(const CellSort &p_cell_sort) const {
+			return key < p_cell_sort.key;
 		}
 	};
 
-	int first_leaf;
-
-	Vector<Light> bake_light;
-
 	struct MaterialCache {
 		//128x128 textures
 		Vector<Color> albedo;
@@ -115,9 +100,6 @@ private:
 	};
 
 	Map<Ref<Material>, MaterialCache> material_cache;
-	int leaf_voxel_count;
-	bool direct_lights_baked;
-
 	AABB original_bounds;
 	AABB po2_bounds;
 	int axis_cell_size[3];
@@ -128,64 +110,36 @@ private:
 	int bake_texture_size;
 	float cell_size;
 	float propagation;
-	float energy;
-
-	BakeQuality bake_quality;
-	BakeMode bake_mode;
 
 	int max_original_cells;
-
-	void _init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent);
+	int leaf_voxel_count;
 
 	Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add);
 	MaterialCache _get_material_cache(Ref<Material> p_material);
 
 	void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb);
 	void _fixup_plot(int p_idx, int p_level);
-	void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode);
-	void _check_init_light();
-
-	uint32_t _find_cell_at_pos(const Cell *cells, int x, int y, int z);
+	void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx);
 
-	struct LightMap {
-		Vector3 light;
-		Vector3 pos;
-		Vector3 normal;
-	};
-
-	void _plot_triangle(Vector2 *vertices, Vector3 *positions, Vector3 *normals, LightMap *pixels, int width, int height);
-
-	_FORCE_INLINE_ void _sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha);
-	_FORCE_INLINE_ Vector3 _voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture);
-	_FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
-	_FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
-
-	void _lightmap_bake_point(uint32_t p_x, LightMap *p_line);
+	bool sorted;
+	void _sort();
 
 public:
 	void begin_bake(int p_subdiv, const AABB &p_bounds);
 	void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material);
-	void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, BakeMode p_bake_mode = BAKE_MODE_CONE_TRACE, float p_propagation = 0.85, float p_energy = 1);
-	void plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct);
-	void plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct);
-	void plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct);
 	void end_bake();
 
-	struct LightMapData {
-		int width;
-		int height;
-		PoolVector<float> light;
-	};
-
-	Error make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, float default_texels_per_unit, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float) = NULL, void *p_bake_time_ud = NULL);
+	int get_gi_probe_octree_depth() const;
+	Vector3i get_giprobe_octree_size() const;
+	int get_giprobe_cell_count() const;
+	PoolVector<uint8_t> get_giprobe_octree_cells() const;
+	PoolVector<uint8_t> get_giprobe_data_cells() const;
+	PoolVector<int> get_giprobe_level_cell_count() const;
 
-	PoolVector<int> create_gi_probe_data();
-	Ref<MultiMesh> create_debug_multimesh(DebugMode p_mode = DEBUG_ALBEDO);
-	PoolVector<uint8_t> create_capture_octree(int p_subdiv);
+	Ref<MultiMesh> create_debug_multimesh();
 
-	float get_cell_size() const;
 	Transform get_to_cell_space_xform() const;
-	VoxelLightBaker();
+	Voxelizer();
 };
 
 #endif // VOXEL_LIGHT_BAKER_H

+ 6 - 0
scene/main/viewport.h

@@ -129,8 +129,14 @@ public:
 	enum DebugDraw {
 		DEBUG_DRAW_DISABLED,
 		DEBUG_DRAW_UNSHADED,
+		DEBUG_DRAW_LIGHTING,
 		DEBUG_DRAW_OVERDRAW,
 		DEBUG_DRAW_WIREFRAME,
+		DEBUG_DRAW_GI_PROBE_ALBEDO,
+		DEBUG_DRAW_GI_PROBE_LIGHTING,
+		DEBUG_DRAW_SHADOW_ATLAS,
+		DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
+
 	};
 
 	enum ClearMode {

+ 2 - 2
scene/register_scene_types.cpp

@@ -419,8 +419,8 @@ void register_scene_types() {
 	ClassDB::register_class<ReflectionProbe>();
 	ClassDB::register_class<GIProbe>();
 	ClassDB::register_class<GIProbeData>();
-	ClassDB::register_class<BakedLightmap>();
-	ClassDB::register_class<BakedLightmapData>();
+	//ClassDB::register_class<BakedLightmap>();
+	//ClassDB::register_class<BakedLightmapData>();
 	ClassDB::register_class<Particles>();
 	ClassDB::register_class<CPUParticles>();
 	ClassDB::register_class<Position3D>();

+ 22 - 3
scene/resources/mesh.cpp

@@ -904,6 +904,8 @@ Array ArrayMesh::_get_surfaces() const {
 
 		ret.push_back(data);
 	}
+	print_line("Saving surfaces: " + itos(ret.size()));
+
 	return ret;
 }
 
@@ -983,7 +985,15 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
 		if (d.has("2d")) {
 			_2d = d["2d"];
 		}
-
+		/*
+		print_line("format: " + itos(surface.format));
+		print_line("aabb: " + surface.aabb);
+		print_line("array size: " + itos(surface.vertex_data.size()));
+		print_line("vertex count: " + itos(surface.vertex_count));
+		print_line("index size: " + itos(surface.index_data.size()));
+		print_line("index count: " + itos(surface.index_count));
+		print_line("primitive: " + itos(surface.primitive));
+*/
 		surface_data.push_back(surface);
 		surface_materials.push_back(material);
 		surface_names.push_back(name);
@@ -999,6 +1009,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
 	} else {
 		// if mesh does not exist (first time this is loaded, most likely),
 		// we can create it with a single call, which is a lot more efficient and thread friendly
+		print_line("create mesh from surfaces: " + itos(surface_data.size()));
 		mesh = VS::get_singleton()->mesh_create_from_surfaces(surface_data);
 		VS::get_singleton()->mesh_set_blend_shape_mode(mesh, (VS::BlendShapeMode)blend_shape_mode);
 	}
@@ -1144,6 +1155,14 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &
 	Error err = VS::get_singleton()->mesh_create_surface_data_from_arrays(&surface, (VisualServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_lods, p_flags);
 	ERR_FAIL_COND(err != OK);
 
+	/*	print_line("format: " + itos(surface.format));
+	print_line("aabb: " + surface.aabb);
+	print_line("array size: " + itos(surface.vertex_data.size()));
+	print_line("vertex count: " + itos(surface.vertex_count));
+	print_line("index size: " + itos(surface.index_data.size()));
+	print_line("index count: " + itos(surface.index_count));
+	print_line("primitive: " + itos(surface.primitive));
+*/
 	add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shapes, surface.bone_aabbs, surface.lods);
 }
 
@@ -1570,8 +1589,8 @@ void ArrayMesh::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("_set_surfaces", "surfaces"), &ArrayMesh::_set_surfaces);
 	ClassDB::bind_method(D_METHOD("_get_surfaces"), &ArrayMesh::_get_surfaces);
 
-	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative", PROPERTY_USAGE_NOEDITOR), "set_blend_shape_mode", "get_blend_shape_mode");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_surfaces", "_get_surfaces");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
 
 	BIND_CONSTANT(NO_INDEX_ARRAY);

+ 1 - 1
scene/resources/resource_format_text.cpp

@@ -1281,7 +1281,7 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
 	ria->res_path = ria->local_path;
 	//ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
 	String r = ria->recognize(f);
-	return r;
+	return ClassDB::get_compatibility_remapped_class(r);
 }
 
 void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {

+ 28 - 37
servers/visual/rasterizer.h

@@ -230,12 +230,13 @@ public:
 	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
 	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
 
-	virtual RID gi_probe_instance_create() = 0;
-	virtual void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) = 0;
+	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 void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) = 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 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_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_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 set_scene_pass(uint64_t p_pass) = 0;
@@ -481,51 +482,41 @@ public:
 
 	virtual RID gi_probe_create() = 0;
 
-	virtual void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds) = 0;
-	virtual AABB gi_probe_get_bounds(RID p_probe) const = 0;
-
-	virtual void gi_probe_set_cell_size(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_cell_size(RID p_probe) const = 0;
+	virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) = 0;
 
-	virtual void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform) = 0;
-	virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const = 0;
+	virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
+	virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
+	virtual PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
+	virtual PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
+	virtual PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
+	virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data) = 0;
-	virtual PoolVector<int> gi_probe_get_dynamic_data(RID p_probe) const = 0;
+	virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
+	virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_dynamic_range(RID p_probe, int p_range) = 0;
-	virtual int gi_probe_get_dynamic_range(RID p_probe) const = 0;
+	virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
+	virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_energy(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_energy(RID p_probe) const = 0;
+	virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
+	virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_bias(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_bias(RID p_probe) const = 0;
+	virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
+	virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_normal_bias(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_normal_bias(RID p_probe) const = 0;
+	virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
+	virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_propagation(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_propagation(RID p_probe) const = 0;
+	virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
+	virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_interior(RID p_probe, bool p_enable) = 0;
-	virtual bool gi_probe_is_interior(RID p_probe) const = 0;
+	virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
+	virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_compress(RID p_probe, bool p_enable) = 0;
-	virtual bool gi_probe_is_compressed(RID p_probe) const = 0;
+	virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
+	virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
 
 	virtual uint32_t gi_probe_get_version(RID p_probe) = 0;
 
-	enum GIProbeCompression {
-		GI_PROBE_UNCOMPRESSED,
-		GI_PROBE_S3TC,
-		GI_PROBE_ETC2
-	};
-
-	virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const = 0;
-	virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) = 0;
-	virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) = 0;
-
 	/* LIGHTMAP CAPTURE */
 
 	struct LightmapCaptureOctree {

+ 2 - 2
servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp

@@ -1331,7 +1331,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
 
 	RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
 
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
 
 	if (p_screen_uniform_set.is_valid()) {
 		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_screen_uniform_set, 3);
@@ -1637,7 +1637,7 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, const Transform2D &p_lig
 
 		Vector<Color> cc;
 		cc.push_back(Color(p_far, p_far, p_far, 1.0));
-		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, cc, Rect2i((cl->shadow.size / 4) * i, 0, (cl->shadow.size / 4), 1));
+		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, Rect2i((cl->shadow.size / 4) * i, 0, (cl->shadow.size / 4), 1));
 
 		CameraMatrix projection;
 		{

+ 8 - 8
servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp

@@ -46,7 +46,7 @@ void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_frame
 		blur.push_constant.flags |= BLUR_FLAG_FLIP_Y;
 	}
 
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, Vector<Color>(), p_rect);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
 	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -67,7 +67,7 @@ void RasterizerEffectsRD::region_copy(RID p_source_rd_texture, RID p_dest_frameb
 		blur.push_constant.section[3] = p_region.size.height;
 	}
 
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
 	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -93,7 +93,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuff
 	blur.push_constant.pixel_size[1] = p_pixel_size.y;
 
 	//HORIZONTAL
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half)));
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
 	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -105,7 +105,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuff
 	RD::get_singleton()->draw_list_end();
 
 	//VERTICAL
-	draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+	draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0);
 	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -127,7 +127,7 @@ void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_sour
 	roughness.push_constant.use_direct_write = p_roughness == 0.0;
 
 	//RUN
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
 
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
@@ -171,7 +171,7 @@ void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_frameb
 	blur.push_constant.pixel_size[0] = p_pixel_size.x;
 	blur.push_constant.pixel_size[1] = p_pixel_size.y;
 
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_MIPMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
 	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -188,7 +188,7 @@ void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest
 	push_constant.z_near = p_z_near;
 	push_constant.z_flip = p_dp_flip;
 
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, Vector<Color>(), p_rect);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy.pipelines[COPY_MODE_CUBE_TO_DP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
 	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -222,7 +222,7 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer,
 
 	tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
 
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH);
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
 	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0);
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1);

Datei-Diff unterdrückt, da er zu groß ist
+ 274 - 491
servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp


+ 28 - 3
servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h

@@ -188,6 +188,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 		//for rendering, may be MSAAd
 		RID color;
 		RID depth;
+		RID depth_fb;
 		RID color_fb;
 		RID color_only_fb;
 		int width, height;
@@ -204,7 +205,9 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 
 	RID shadow_sampler;
 	RID render_base_uniform_set;
-	void _setup_render_base_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas);
+	RID render_pass_uniform_set;
+	void _update_render_base_uniform_set();
+	void _setup_render_pass_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas);
 
 	/* Scene State UBO */
 
@@ -247,6 +250,20 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 		float shadow_matrices[4][16];
 	};
 
+	struct GIProbeData {
+		float xform[16];
+		float bounds[3];
+		float dynamic_range;
+
+		float bias;
+		float normal_bias;
+		uint32_t blend_ambient;
+		uint32_t texture_slot;
+
+		float anisotropy_strength;
+		uint32_t pad[3];
+	};
+
 	enum {
 		INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
 		INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
@@ -315,6 +332,11 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 		RID reflection_buffer;
 		uint32_t max_reflection_probes_per_instance;
 
+		GIProbeData *gi_probes;
+		uint32_t max_gi_probes;
+		RID gi_probe_buffer;
+		uint32_t max_gi_probe_probes_per_instance;
+
 		LightData *lights;
 		uint32_t max_lights;
 		RID light_buffer;
@@ -498,6 +520,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 	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_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 _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);
@@ -508,13 +531,15 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 
 	void _draw_sky(RD::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, float p_alpha);
 
+	VS::ViewportDebugDraw debug_draw = VS::VIEWPORT_DEBUG_DRAW_DISABLED;
+
 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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+	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);
 
 public:
 	virtual void set_time(double p_time);
-	virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {}
+	virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw);
 
 	virtual bool free(RID p_rid);
 

+ 556 - 7
servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -619,6 +619,10 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R
 				atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
 			}
 		}
+
+		Vector<RID> fb;
+		fb.push_back(atlas->depth_buffer);
+		atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
 	}
 
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
@@ -700,6 +704,16 @@ RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance,
 	return atlas->reflections[rpi->atlas_index].fbs[p_index];
 }
 
+RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
+	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+	ERR_FAIL_COND_V(!rpi, RID());
+	ERR_FAIL_INDEX_V(p_index, 6, RID());
+
+	ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+	ERR_FAIL_COND_V(!atlas, RID());
+	return atlas->depth_fb;
+}
+
 ///////////////////////////////////////////////////////////
 
 RID RasterizerSceneRD::shadow_atlas_create() {
@@ -1192,6 +1206,454 @@ RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p
 
 	return &shadow_maps[p_size];
 }
+/////////////////////////////////
+
+RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) {
+	//find a free slot
+	int index = -1;
+	for (int i = 0; i < gi_probe_slots.size(); i++) {
+		if (gi_probe_slots[i] == RID()) {
+			index = i;
+			break;
+		}
+	}
+
+	ERR_FAIL_COND_V(index == -1, RID());
+
+	GIProbeInstance gi_probe;
+	gi_probe.slot = index;
+	gi_probe.probe = p_base;
+	RID rid = gi_probe_instance_owner.make_rid(gi_probe);
+	gi_probe_slots.write[index] = rid;
+
+	return rid;
+}
+
+void RasterizerSceneRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
+
+	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->transform = p_xform;
+}
+
+bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const {
+	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gi_probe, false);
+
+	//return true;
+	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) {
+
+	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe);
+
+	// (RE)CREATE IF NEEDED
+
+	if (gi_probe->last_probe_data_version != data_version) {
+		//need to re-create everything
+		if (gi_probe->texture.is_valid()) {
+			RD::get_singleton()->free(gi_probe->texture);
+			if (gi_probe_use_anisotropy) {
+				RD::get_singleton()->free(gi_probe->anisotropy[0]);
+				RD::get_singleton()->free(gi_probe->anisotropy[1]);
+			}
+			RD::get_singleton()->free(gi_probe->write_buffer);
+			gi_probe->mipmaps.clear();
+		}
+
+		Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
+
+		if (octree_size != Vector3i()) {
+			//can create a 3D texture
+			PoolVector<int> levels = storage->gi_probe_get_level_counts(gi_probe->probe);
+
+			for (int i = 0; i < levels.size(); i++) {
+				print_line("level " + itos(i) + ": " + itos(levels[i]));
+			}
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+			tf.width = octree_size.x;
+			tf.height = octree_size.y;
+			tf.depth = octree_size.z;
+			tf.type = RD::TEXTURE_TYPE_3D;
+			tf.mipmaps = levels.size();
+
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+
+			gi_probe->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+			RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+
+			if (gi_probe_use_anisotropy) {
+				tf.format = RD::DATA_FORMAT_R5G6B5_UNORM_PACK16;
+				tf.shareable_formats.push_back(RD::DATA_FORMAT_R5G6B5_UNORM_PACK16);
+				tf.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
+
+				gi_probe->anisotropy[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+				gi_probe->anisotropy[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+				RD::get_singleton()->texture_clear(gi_probe->anisotropy[0], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+				RD::get_singleton()->texture_clear(gi_probe->anisotropy[1], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+			}
+
+			{
+				int total_elements = 0;
+				for (int i = 0; i < levels.size(); i++) {
+					total_elements += levels[i];
+				}
+
+				if (gi_probe_use_anisotropy) {
+					total_elements *= 6;
+				}
+
+				gi_probe->write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16);
+			}
+
+			for (int i = 0; i < levels.size(); i++) {
+				GIProbeInstance::Mipmap mipmap;
+				mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), gi_probe->texture, 0, i, RD::TEXTURE_SLICE_3D);
+				if (gi_probe_use_anisotropy) {
+					RD::TextureView tv;
+					tv.format_override = RD::DATA_FORMAT_R16_UINT;
+					mipmap.anisotropy[0] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[0], 0, i, RD::TEXTURE_SLICE_3D);
+					mipmap.anisotropy[1] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[1], 0, i, RD::TEXTURE_SLICE_3D);
+				}
+
+				mipmap.level = levels.size() - i - 1;
+				mipmap.cell_offset = 0;
+				for (uint32_t j = 0; j < mipmap.level; j++) {
+					mipmap.cell_offset += levels[j];
+				}
+				mipmap.cell_count = levels[mipmap.level];
+
+				Vector<RD::Uniform> uniforms;
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+					u.binding = 1;
+					u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe));
+					uniforms.push_back(u);
+				}
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+					u.binding = 2;
+					u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
+					uniforms.push_back(u);
+				}
+
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+					u.binding = 4;
+					u.ids.push_back(gi_probe->write_buffer);
+					uniforms.push_back(u);
+				}
+				{
+					Vector<RD::Uniform> copy_uniforms = uniforms;
+					if (i == 0) {
+						{
+							RD::Uniform u;
+							u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+							u.binding = 3;
+							u.ids.push_back(gi_probe_lights_uniform);
+							copy_uniforms.push_back(u);
+						}
+
+						mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
+
+						copy_uniforms = uniforms; //restore
+
+						{
+							RD::Uniform u;
+							u.type = RD::UNIFORM_TYPE_TEXTURE;
+							u.binding = 5;
+							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) {
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_TEXTURE;
+								u.binding = 7;
+								u.ids.push_back(gi_probe->anisotropy[0]);
+								copy_uniforms.push_back(u);
+							}
+							{
+								RD::Uniform u;
+								u.type = RD::UNIFORM_TYPE_TEXTURE;
+								u.binding = 8;
+								u.ids.push_back(gi_probe->anisotropy[1]);
+								copy_uniforms.push_back(u);
+							}
+						}
+
+						mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
+					} else {
+						mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
+					}
+				}
+
+				{
+					RD::Uniform u;
+					u.type = RD::UNIFORM_TYPE_IMAGE;
+					u.binding = 5;
+					u.ids.push_back(mipmap.texture);
+					uniforms.push_back(u);
+				}
+
+				if (gi_probe_use_anisotropy) {
+					{
+						RD::Uniform u;
+						u.type = RD::UNIFORM_TYPE_IMAGE;
+						u.binding = 6;
+						u.ids.push_back(mipmap.anisotropy[0]);
+						uniforms.push_back(u);
+					}
+					{
+						RD::Uniform u;
+						u.type = RD::UNIFORM_TYPE_IMAGE;
+						u.binding = 7;
+						u.ids.push_back(mipmap.anisotropy[1]);
+						uniforms.push_back(u);
+					}
+				}
+
+				mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
+
+				gi_probe->mipmaps.push_back(mipmap);
+			}
+		}
+
+		gi_probe->last_probe_data_version = data_version;
+	}
+
+	// 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
+
+		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.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.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);
+
+			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();
+
+			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;
+
+		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 (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;
+
+				RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+
+				RD::get_singleton()->compute_list_dispatch(compute_list, (gi_probe->mipmaps[i].cell_count - 1) / 64 + 1, 1, 1);
+			}
+
+			RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+
+			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;
+
+				RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+
+				RD::get_singleton()->compute_list_dispatch(compute_list, (gi_probe->mipmaps[i].cell_count - 1) / 64 + 1, 1, 1);
+			}
+		}
+
+		RD::get_singleton()->compute_list_end();
+	}
+
+	gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe);
+	print_line("update GI");
+}
+
+void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, float p_alpha) {
+	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	if (gi_probe->mipmaps.size() == 0) {
+		return;
+	}
+
+	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;
+
+	GIProbeDebugPushConstant push_constant;
+	push_constant.alpha = p_alpha;
+	push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
+	push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset;
+	push_constant.level = level;
+
+	int cell_count = gi_probe->mipmaps[level].cell_count;
+
+	for (int i = 0; i < 4; i++) {
+		for (int j = 0; j < 4; j++) {
+
+			push_constant.projection[i * 4 + j] = transform.matrix[i][j];
+		}
+	}
+
+	if (giprobe_debug_uniform_set.is_valid()) {
+		RD::get_singleton()->free(giprobe_debug_uniform_set);
+	}
+	Vector<RD::Uniform> uniforms;
+	{
+		RD::Uniform u;
+		u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+		u.binding = 1;
+		u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
+		uniforms.push_back(u);
+	}
+	{
+		RD::Uniform u;
+		u.type = RD::UNIFORM_TYPE_TEXTURE;
+		u.binding = 2;
+		u.ids.push_back(gi_probe->texture);
+		uniforms.push_back(u);
+	}
+	{
+		RD::Uniform u;
+		u.type = RD::UNIFORM_TYPE_SAMPLER;
+		u.binding = 3;
+		u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+		uniforms.push_back(u);
+	}
+
+	if (gi_probe_use_anisotropy) {
+		{
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			u.binding = 4;
+			u.ids.push_back(gi_probe->anisotropy[0]);
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			u.binding = 5;
+			u.ids.push_back(gi_probe->anisotropy[1]);
+			uniforms.push_back(u);
+		}
+	}
+
+	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_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_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);
+}
+
+const Vector<RID> &RasterizerSceneRD::gi_probe_get_slots() const {
+
+	return gi_probe_slots;
+}
+
+bool RasterizerSceneRD::gi_probe_slots_are_dirty() const {
+	return gi_probe_slots_dirty;
+}
+
+void RasterizerSceneRD::gi_probe_slots_make_not_dirty() {
+	gi_probe_slots_dirty = false;
+}
+
+bool RasterizerSceneRD::gi_probe_is_high_quality() const {
+	return gi_probe_use_6_cones;
+}
 
 ////////////////////////////////
 RID RasterizerSceneRD::render_buffers_create() {
@@ -1218,12 +1680,12 @@ bool RasterizerSceneRD::is_using_radiance_cubemap_array() const {
 	return sky_use_cubemap_array;
 }
 
-void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
 
 	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
 	ERR_FAIL_COND(!rb && p_render_buffers.is_valid());
 
-	_render_scene(rb ? rb->data : (RenderBufferData *)NULL, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
+	_render_scene(rb ? rb->data : (RenderBufferData *)NULL, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
 }
 
 void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
@@ -1418,6 +1880,20 @@ bool RasterizerSceneRD::free(RID p_rid) {
 		//ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
 		reflection_probe_release_atlas_index(p_rid);
 		reflection_probe_instance_owner.free(p_rid);
+	} else if (gi_probe_instance_owner.owns(p_rid)) {
+		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid);
+		if (gi_probe->texture.is_valid()) {
+			RD::get_singleton()->free(gi_probe->texture);
+			RD::get_singleton()->free(gi_probe->write_buffer);
+		}
+		if (gi_probe->anisotropy[0].is_valid()) {
+			RD::get_singleton()->free(gi_probe->anisotropy[0]);
+			RD::get_singleton()->free(gi_probe->anisotropy[1]);
+		}
+
+		gi_probe_slots.write[gi_probe->slot] = RID();
+
+		gi_probe_instance_owner.free(p_rid);
 	} else if (sky_owner.owns(p_rid)) {
 		_update_dirty_skys();
 		Sky *sky = sky_owner.getornull(p_rid);
@@ -1470,13 +1946,83 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
 	sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections");
 	//	sky_use_cubemap_array = false;
 
+	uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
+
 	{
-		String defines = "";
+
+		//kinda complicated to compute the amount of slots, we try to use as many as we can
+
+		gi_probe_max_lights = 32;
+
+		gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
+		gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
+
+		gi_probe_use_anisotropy = GLOBAL_GET("rendering/quality/gi_probes/anisotropic");
+		gi_probe_use_6_cones = GLOBAL_GET("rendering/quality/gi_probes/high_quality");
+
+		if (textures_per_stage <= 16) {
+			gi_probe_slots.resize(2); //thats all you can get
+			gi_probe_use_anisotropy = false;
+		} else if (textures_per_stage <= 31) {
+			gi_probe_slots.resize(4); //thats all you can get, iOS
+			gi_probe_use_anisotropy = false;
+		} else if (textures_per_stage <= 128) {
+			gi_probe_slots.resize(32); //old intel
+			gi_probe_use_anisotropy = false;
+		} else if (textures_per_stage <= 256) {
+			gi_probe_slots.resize(64); //old intel too
+			gi_probe_use_anisotropy = false;
+		} else {
+			if (gi_probe_use_anisotropy) {
+				gi_probe_slots.resize(1024 / 3); //needs 3 textures
+			} else {
+				gi_probe_slots.resize(1024); //modern intel, nvidia, 8192 or greater
+			}
+		}
+
+		String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
+		if (gi_probe_use_anisotropy) {
+			defines += "\n#define MODE_ANISOTROPIC\n";
+		}
+
+		Vector<String> versions;
+		versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
+		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");
+
+		giprobe_shader.initialize(versions, defines);
+		giprobe_lighting_shader_version = giprobe_shader.version_create();
+		for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) {
+			giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i);
+			giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]);
+		}
+	}
+
+	{
+
+		String defines;
+		if (gi_probe_use_anisotropy) {
+			defines += "\n#define USE_ANISOTROPY\n";
+		}
 		Vector<String> versions;
-		versions.push_back("");
-		giprobe_lighting_shader.initialize(versions, defines);
-		giprobe_lighting_shader_version = giprobe_lighting_shader.version_create();
-		giprobe_lighting_shader_version_shader = giprobe_lighting_shader.version_get_shader(giprobe_lighting_shader_version, 0);
+		versions.push_back("\n#define MODE_DEBUG_COLOR\n");
+		versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
+
+		giprobe_debug_shader.initialize(versions, defines);
+		giprobe_debug_shader_version = giprobe_debug_shader.version_create();
+		for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) {
+			giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i);
+
+			RD::PipelineRasterizationState rs;
+			rs.cull_mode = RD::POLYGON_CULL_FRONT;
+			RD::PipelineDepthStencilState ds;
+			ds.enable_depth_test = true;
+			ds.enable_depth_write = true;
+			ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+
+			giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+		}
 	}
 }
 
@@ -1489,4 +2035,7 @@ RasterizerSceneRD::~RasterizerSceneRD() {
 	for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) {
 		RD::get_singleton()->free(E->get().cubemap);
 	}
+
+	RD::get_singleton()->free(gi_probe_lights_uniform);
+	memdelete_arr(gi_probe_lights);
 }

+ 170 - 9
servers/visual/rasterizer_rd/rasterizer_scene_rd.h

@@ -4,7 +4,8 @@
 #include "core/rid_owner.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
-#include "servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl.gen.h"
+#include "servers/visual/rasterizer_rd/shaders/giprobe.glsl.gen.h"
+#include "servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl.gen.h"
 #include "servers/visual/rendering_device.h"
 
 class RasterizerSceneRD : public RasterizerScene {
@@ -16,9 +17,11 @@ protected:
 	};
 	virtual RenderBufferData *_create_render_buffer_data() = 0;
 
-	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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
+	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 _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, float p_alpha);
+
 private:
 	int roughness_layers;
 
@@ -76,6 +79,7 @@ private:
 
 		RID reflection;
 		RID depth_buffer;
+		RID depth_fb;
 
 		struct Reflection {
 			RID owner;
@@ -111,9 +115,110 @@ private:
 
 	/* GIPROBE INSTANCE */
 
-	GiprobeLightingShaderRD giprobe_lighting_shader;
+	struct GIProbeLight {
+
+		uint32_t type;
+		float energy;
+		float radius;
+		float attenuation;
+
+		float color[3];
+		float spot_angle_radians;
+
+		float position[3];
+		float spot_attenuation;
+
+		float direction[3];
+		uint32_t has_shadow;
+	};
+
+	struct GIProbePushConstant {
+
+		int32_t limits[3];
+		uint32_t stack_size;
+
+		float emission_scale;
+		float propagation;
+		float dynamic_range;
+		uint32_t light_count;
+
+		uint32_t cell_offset;
+		uint32_t cell_count;
+		float aniso_strength;
+		uint32_t pad;
+	};
+
+	struct GIProbeInstance {
+
+		RID probe;
+		RID texture;
+		RID anisotropy[2]; //only if anisotropy is used
+		RID write_buffer;
+
+		struct Mipmap {
+			RID texture;
+			RID anisotropy[2]; //only if anisotropy is used
+			RID uniform_set;
+			RID second_bounce_uniform_set;
+			RID write_uniform_set;
+			uint32_t level;
+			uint32_t cell_offset;
+			uint32_t cell_count;
+		};
+		Vector<Mipmap> mipmaps;
+
+		int slot = -1;
+		uint32_t last_probe_version = 0;
+		uint32_t last_probe_data_version = 0;
+
+		uint64_t last_pass = 0;
+		uint32_t render_index = 0;
+
+		Transform transform;
+	};
+
+	GIProbeLight *gi_probe_lights;
+	uint32_t gi_probe_max_lights;
+	RID gi_probe_lights_uniform;
+
+	bool gi_probe_use_anisotropy = false;
+	bool gi_probe_use_6_cones = false;
+	bool gi_probe_slots_dirty = true;
+	Vector<RID> gi_probe_slots;
+
+	enum {
+		GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
+		GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
+		GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
+		GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
+		GI_PROBE_SHADER_VERSION_MAX
+	};
+	GiprobeShaderRD giprobe_shader;
 	RID giprobe_lighting_shader_version;
-	RID giprobe_lighting_shader_version_shader;
+	RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX];
+	RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX];
+
+	mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+
+	enum {
+		GI_PROBE_DEBUG_COLOR,
+		GI_PROBE_DEBUG_LIGHT,
+		GI_PROBE_DEBUG_MAX
+	};
+
+	struct GIProbeDebugPushConstant {
+		float projection[16];
+		uint32_t cell_offset;
+		float dynamic_range;
+		float alpha;
+		uint32_t level;
+	};
+
+	GiprobeDebugShaderRD giprobe_debug_shader;
+	RID giprobe_debug_shader_version;
+	RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
+	RenderPipelineVertexFormatCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
+	RID giprobe_debug_uniform_set;
 
 	/* SHADOW ATLAS */
 
@@ -497,6 +602,7 @@ public:
 
 	uint32_t reflection_probe_instance_get_resolution(RID p_instance);
 	RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
+	RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
 
 	_FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
 		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
@@ -545,15 +651,70 @@ public:
 		return rpi->atlas_index;
 	}
 
-	RID gi_probe_instance_create() { return RID(); }
-	void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) {}
-	void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {}
-	void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) {}
+	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);
+	_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;
+	}
+	_FORCE_INLINE_ RID gi_probe_instance_get_base_probe(RID p_probe) {
+		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+		return gi_probe->probe;
+	}
+	_FORCE_INLINE_ Transform gi_probe_instance_get_transform_to_cell(RID p_probe) {
+		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+		return storage->gi_probe_get_to_cell_xform(gi_probe->probe) * gi_probe->transform.affine_inverse();
+	}
+
+	_FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
+		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+		return gi_probe->texture;
+	}
+	_FORCE_INLINE_ RID gi_probe_instance_get_aniso_texture(RID p_probe, int p_index) {
+		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+		return gi_probe->anisotropy[p_index];
+	}
+
+	_FORCE_INLINE_ void gi_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
+		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
+		ERR_FAIL_COND(!gi_probe);
+		gi_probe->render_index = p_render_index;
+	}
+
+	_FORCE_INLINE_ uint32_t gi_probe_instance_get_render_index(RID p_instance) {
+		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
+		ERR_FAIL_COND_V(!gi_probe, 0);
+
+		return gi_probe->render_index;
+	}
+
+	_FORCE_INLINE_ void gi_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
+		GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
+		ERR_FAIL_COND(!g_probe);
+		g_probe->last_pass = p_render_pass;
+	}
+
+	_FORCE_INLINE_ uint32_t gi_probe_instance_get_render_pass(RID p_instance) {
+		GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
+		ERR_FAIL_COND_V(!g_probe, 0);
+
+		return g_probe->last_pass;
+	}
+
+	const Vector<RID> &gi_probe_get_slots() const;
+	bool gi_probe_slots_are_dirty() const;
+	void gi_probe_slots_make_not_dirty();
+	_FORCE_INLINE_ bool gi_probe_is_anisotropic() const {
+		return gi_probe_use_anisotropy;
+	}
+	bool gi_probe_is_high_quality() const;
 
 	RID render_buffers_create();
 	void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa);
 
-	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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+	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);
 
 	void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
 

+ 263 - 2
servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp

@@ -987,6 +987,7 @@ void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_t
 /* COMMON MATERIAL API */
 
 RID RasterizerStorageRD::material_create() {
+
 	Material material;
 	material.data = NULL;
 	material.shader = NULL;
@@ -1924,7 +1925,7 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_
 		mesh->aabb.merge_with(p_surface.aabb);
 	}
 
-	s->material = p_mesh;
+	s->material = p_surface.material;
 
 	mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
 	mesh->surfaces[mesh->surface_count] = s;
@@ -1995,6 +1996,8 @@ VS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface)
 	sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
 	sd.vertex_count = s.vertex_count;
 	sd.index_count = s.index_count;
+	sd.primitive = s.primitive;
+
 	if (sd.index_count) {
 		sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
 	}
@@ -3544,6 +3547,253 @@ float RasterizerStorageRD::reflection_probe_get_interior_ambient_probe_contribut
 	return reflection_probe->interior_ambient_probe_contrib;
 }
 
+RID RasterizerStorageRD::gi_probe_create() {
+
+	return gi_probe_owner.make_rid(GIProbe());
+}
+
+void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	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;
+		}
+
+		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->to_cell_xform = p_to_cell_xform;
+	gi_probe->bounds = p_aabb;
+	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()) {
+		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;
+
+		ERR_FAIL_COND(p_data_cells.size() != cell_count * 16); //see that data size matches
+
+		gi_probe->cell_count = cell_count;
+		gi_probe->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells);
+		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;
+	}
+
+	gi_probe->version++;
+	if (data_version_changed) {
+		gi_probe->data_version++;
+	}
+	gi_probe->instance_dependency.instance_notify_changed(true, false);
+}
+
+AABB RasterizerStorageRD::gi_probe_get_bounds(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, AABB());
+
+	return gi_probe->bounds;
+}
+
+Vector3i RasterizerStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, Vector3i());
+	return gi_probe->octree_size;
+}
+PoolVector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, PoolVector<uint8_t>());
+
+	if (gi_probe->octree_buffer.is_valid()) {
+		return RD::get_singleton()->buffer_get_data(gi_probe->octree_buffer);
+	}
+	return PoolVector<uint8_t>();
+}
+PoolVector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, PoolVector<uint8_t>());
+
+	if (gi_probe->data_buffer.is_valid()) {
+		return RD::get_singleton()->buffer_get_data(gi_probe->data_buffer);
+	}
+	return PoolVector<uint8_t>();
+}
+PoolVector<int> RasterizerStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, PoolVector<int>());
+
+	return gi_probe->level_counts;
+}
+Transform RasterizerStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, Transform());
+
+	return gi_probe->to_cell_xform;
+}
+
+void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->dynamic_range = p_range;
+	gi_probe->version++;
+}
+float RasterizerStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+
+	return gi_probe->dynamic_range;
+}
+
+void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->propagation = p_range;
+	gi_probe->version++;
+}
+float RasterizerStorageRD::gi_probe_get_propagation(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->propagation;
+}
+
+void RasterizerStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->energy = p_energy;
+}
+float RasterizerStorageRD::gi_probe_get_energy(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->energy;
+}
+
+void RasterizerStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->bias = p_bias;
+}
+float RasterizerStorageRD::gi_probe_get_bias(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->bias;
+}
+
+void RasterizerStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->normal_bias = p_normal_bias;
+}
+float RasterizerStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->normal_bias;
+}
+
+void RasterizerStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) {
+
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->anisotropy_strength = p_strength;
+}
+
+float RasterizerStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->anisotropy_strength;
+}
+
+void RasterizerStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->interior = p_enable;
+}
+
+void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gi_probe);
+
+	gi_probe->use_two_bounces = p_enable;
+	gi_probe->version++;
+}
+
+bool RasterizerStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, false);
+	return gi_probe->use_two_bounces;
+}
+
+bool RasterizerStorageRD::gi_probe_is_interior(RID p_gi_probe) const {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->interior;
+}
+
+uint32_t RasterizerStorageRD::gi_probe_get_version(RID p_gi_probe) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->version;
+}
+
+uint32_t RasterizerStorageRD::gi_probe_get_data_version(RID p_gi_probe) {
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, 0);
+	return gi_probe->data_version;
+}
+
+RID RasterizerStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const {
+
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, RID());
+	return gi_probe->octree_buffer;
+}
+RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
+
+	GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gi_probe, RID());
+	return gi_probe->data_buffer;
+}
+
 /* RENDER TARGET API */
 
 void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
@@ -3821,7 +4071,7 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {
 	}
 	Vector<Color> clear_colors;
 	clear_colors.push_back(rt->clear_color);
-	RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors);
+	RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
 	RD::get_singleton()->draw_list_end();
 	rt->clear_requested = false;
 }
@@ -3899,6 +4149,9 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In
 	} else if (reflection_probe_owner.owns(p_base)) {
 		ReflectionProbe *rp = reflection_probe_owner.getornull(p_base);
 		p_instance->update_dependency(&rp->instance_dependency);
+	} else if (gi_probe_owner.owns(p_base)) {
+		GIProbe *gip = gi_probe_owner.getornull(p_base);
+		p_instance->update_dependency(&gip->instance_dependency);
 	} else if (light_owner.owns(p_base)) {
 		Light *l = light_owner.getornull(p_base);
 		p_instance->update_dependency(&l->instance_dependency);
@@ -3924,6 +4177,9 @@ VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
 	if (reflection_probe_owner.owns(p_rid)) {
 		return VS::INSTANCE_REFLECTION_PROBE;
 	}
+	if (gi_probe_owner.owns(p_rid)) {
+		return VS::INSTANCE_GI_PROBE;
+	}
 	if (light_owner.owns(p_rid)) {
 		return VS::INSTANCE_LIGHT;
 	}
@@ -4032,6 +4288,11 @@ bool RasterizerStorageRD::free(RID p_rid) {
 		ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid);
 		reflection_probe->instance_dependency.instance_notify_deleted(p_rid);
 		reflection_probe_owner.free(p_rid);
+	} else if (gi_probe_owner.owns(p_rid)) {
+		gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), PoolVector<uint8_t>(), PoolVector<uint8_t>(), PoolVector<int>()); //deallocate
+		GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
+		gi_probe->instance_dependency.instance_notify_deleted(p_rid);
+		gi_probe_owner.free(p_rid);
 
 	} else if (light_owner.owns(p_rid)) {
 

+ 64 - 31
servers/visual/rasterizer_rd/rasterizer_storage_rd.h

@@ -401,6 +401,42 @@ private:
 
 	mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
 
+	/* GI PROBE */
+
+	struct GIProbe {
+
+		RID octree_buffer;
+		RID data_buffer;
+
+		uint32_t octree_buffer_size = 0;
+		uint32_t data_buffer_size = 0;
+
+		PoolVector<int> level_counts;
+
+		int cell_count = 0;
+
+		Transform to_cell_xform;
+		AABB bounds;
+		Vector3i octree_size;
+
+		float dynamic_range = 4.0;
+		float energy = 1.0;
+		float bias = 1.4;
+		float normal_bias = 0.0;
+		float propagation = 0.7;
+		bool interior = false;
+		bool use_two_bounces = false;
+
+		float anisotropy_strength = 0.5;
+
+		uint32_t version = 1;
+		uint32_t data_version = 1;
+
+		RasterizerScene::InstanceDependency instance_dependency;
+	};
+
+	mutable RID_Owner<GIProbe> gi_probe_owner;
+
 	/* RENDER TARGET */
 
 	struct RenderTarget {
@@ -922,49 +958,46 @@ public:
 
 	/* GI PROBE API */
 
-	RID gi_probe_create() { return RID(); }
+	RID gi_probe_create();
 
-	void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds) {}
-	AABB gi_probe_get_bounds(RID p_probe) const { return AABB(); }
+	void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts);
 
-	void gi_probe_set_cell_size(RID p_probe, float p_range) {}
-	float gi_probe_get_cell_size(RID p_probe) const { return 0.0; }
+	AABB gi_probe_get_bounds(RID p_gi_probe) const;
+	Vector3i gi_probe_get_octree_size(RID p_gi_probe) const;
+	PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const;
+	PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const;
+	PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const;
+	Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const;
 
-	void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform) {}
-	Transform gi_probe_get_to_cell_xform(RID p_probe) const { return Transform(); }
-
-	void gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data) {}
-	PoolVector<int> gi_probe_get_dynamic_data(RID p_probe) const {
-		PoolVector<int> p;
-		return p;
-	}
+	void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range);
+	float gi_probe_get_dynamic_range(RID p_gi_probe) const;
 
-	void gi_probe_set_dynamic_range(RID p_probe, int p_range) {}
-	int gi_probe_get_dynamic_range(RID p_probe) const { return 0; }
+	void gi_probe_set_propagation(RID p_gi_probe, float p_range);
+	float gi_probe_get_propagation(RID p_gi_probe) const;
 
-	void gi_probe_set_energy(RID p_probe, float p_range) {}
-	float gi_probe_get_energy(RID p_probe) const { return 0.0; }
+	void gi_probe_set_energy(RID p_gi_probe, float p_energy);
+	float gi_probe_get_energy(RID p_gi_probe) const;
 
-	void gi_probe_set_bias(RID p_probe, float p_range) {}
-	float gi_probe_get_bias(RID p_probe) const { return 0.0; }
+	void gi_probe_set_bias(RID p_gi_probe, float p_bias);
+	float gi_probe_get_bias(RID p_gi_probe) const;
 
-	void gi_probe_set_normal_bias(RID p_probe, float p_range) {}
-	float gi_probe_get_normal_bias(RID p_probe) const { return 0.0; }
+	void gi_probe_set_normal_bias(RID p_gi_probe, float p_range);
+	float gi_probe_get_normal_bias(RID p_gi_probe) const;
 
-	void gi_probe_set_propagation(RID p_probe, float p_range) {}
-	float gi_probe_get_propagation(RID p_probe) const { return 0.0; }
+	void gi_probe_set_interior(RID p_gi_probe, bool p_enable);
+	bool gi_probe_is_interior(RID p_gi_probe) const;
 
-	void gi_probe_set_interior(RID p_probe, bool p_enable) {}
-	bool gi_probe_is_interior(RID p_probe) const { return false; }
+	void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable);
+	bool gi_probe_is_using_two_bounces(RID p_gi_probe) const;
 
-	void gi_probe_set_compress(RID p_probe, bool p_enable) {}
-	bool gi_probe_is_compressed(RID p_probe) const { return false; }
+	void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength);
+	float gi_probe_get_anisotropy_strength(RID p_gi_probe) const;
 
-	uint32_t gi_probe_get_version(RID p_probe) { return 0; }
+	uint32_t gi_probe_get_version(RID p_probe);
+	uint32_t gi_probe_get_data_version(RID p_probe);
 
-	GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const { return GI_PROBE_UNCOMPRESSED; }
-	RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) { return RID(); }
-	void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {}
+	RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
+	RID gi_probe_get_data_buffer(RID p_gi_probe) const;
 
 	/* LIGHTMAP CAPTURE */
 

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

@@ -11,5 +11,6 @@ if 'RD_GLSL' in env['BUILDERS']:
     env.RD_GLSL('sky.glsl');
     env.RD_GLSL('tonemap.glsl');
     env.RD_GLSL('copy.glsl');
-    env.RD_GLSL('giprobe_lighting.glsl');
+    env.RD_GLSL('giprobe.glsl');
+    env.RD_GLSL('giprobe_debug.glsl');
 

+ 543 - 0
servers/visual/rasterizer_rd/shaders/giprobe.glsl

@@ -0,0 +1,543 @@
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+#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;
+
+#define LIGHT_TYPE_DIRECTIONAL 0
+#define LIGHT_TYPE_OMNI 1
+#define LIGHT_TYPE_SPOT 2
+
+#ifdef MODE_COMPUTE_LIGHT
+
+struct Light {
+
+	uint type;
+	float energy;
+	float radius;
+	float attenuation;
+
+	vec3 color;
+	float spot_angle_radians;
+
+	vec3 position;
+	float spot_attenuation;
+
+	vec3 direction;
+	bool has_shadow;
+};
+
+
+layout(set=0,binding=3,std140) uniform Lights {
+    Light data[MAX_LIGHTS];
+} lights;
+
+
+
+#endif // MODE COMPUTE LIGHT
+
+
+#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;
+layout (set=0,binding=8) uniform texture3D aniso_neg_texture;
+#endif // MODE ANISOTROPIC
+
+#endif // MODE_SECOND_BOUNCE
+
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+	ivec3 limits;
+	uint stack_size;
+
+	float emission_scale;
+	float propagation;
+	float dynamic_range;
+
+	uint light_count;
+	uint cell_offset;
+	uint cell_count;
+	float aniso_strength;
+	uint pad;
+
+} params;
+
+
+layout(set=0,binding=4,std430) buffer Outputs {
+    vec4 data[];
+} outputs;
+
+#ifdef MODE_WRITE_TEXTURE
+
+layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
+
+#ifdef MODE_ANISOTROPIC
+
+layout (r16ui,set=0,binding=6) uniform restrict writeonly uimage3D aniso_pos_tex;
+layout (r16ui,set=0,binding=7) uniform restrict writeonly uimage3D aniso_neg_tex;
+
+#endif
+
+
+#endif
+
+
+#ifdef MODE_COMPUTE_LIGHT
+
+uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
+
+	uint result = NO_CHILDREN;
+
+	ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z));
+
+	while (distance > -distance_adv) { //use this to avoid precision errors
+
+		uint cell = 0;
+
+		ivec3 pos = ivec3(from);
+
+		if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) {
+
+			ivec3 ofs = ivec3(0);
+			ivec3 half_size = size / 2;
+
+			for (int i = 0; i < params.stack_size - 1; i++) {
+
+				bvec3 greater = greaterThanEqual(pos,ofs+half_size);
+
+				ofs += mix(ivec3(0),half_size,greater);
+
+				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;
+				}
+
+				cell = cell_children.data[cell].children[child];
+				if (cell == NO_CHILDREN)
+					break;
+
+				half_size >>= ivec3(1);
+			}
+
+			if ( cell != NO_CHILDREN) {
+				return cell; //found cell!
+			}
+
+		}
+
+		from += direction * distance_adv;
+		distance -= distance_adv;
+	}
+
+	return NO_CHILDREN;
+}
+
+bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
+
+
+	if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
+
+		light_pos = pos - lights.data[light].direction * length(vec3(params.limits));
+		attenuation = 1.0;
+
+	} else {
+
+		light_pos = lights.data[light].position;
+		float distance = length(pos - light_pos);
+		if (distance >= lights.data[light].radius) {
+			return false;
+		}
+
+
+		attenuation = pow( clamp( 1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation );
+
+
+		if (lights.data[light].type==LIGHT_TYPE_SPOT) {
+
+			vec3 rel = normalize(pos - light_pos);
+			float angle = acos(dot(rel,lights.data[light].direction));
+			if (angle > lights.data[light].spot_angle_radians) {
+				return false;
+			}
+
+			float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
+			attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
+		}
+	}
+
+	return true;
+}
+
+float get_normal_advance(vec3 p_normal) {
+
+	vec3 normal = p_normal;
+	vec3 unorm = abs(normal);
+
+	if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
+		// x code
+		unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
+	} else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
+		// y code
+		unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
+	} else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
+		// z code
+		unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
+	} else {
+		// oh-no we messed up code
+		// has to be
+		unorm = vec3(1.0, 0.0, 0.0);
+	}
+
+	return 1.0 / dot(normal,unorm);
+}
+
+#endif
+
+
+
+
+void main() {
+
+	uint cell_index = gl_GlobalInvocationID.x;;
+	if (cell_index >= params.cell_count) {
+		return;
+	}
+	cell_index += 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);
+	vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo);
+
+/////////////////COMPUTE LIGHT///////////////////////////////
+
+#ifdef MODE_COMPUTE_LIGHT
+
+	vec3 pos = vec3(posu) + vec3(0.5);
+
+	vec3 emission = vec3(ivec3(cell_data.data[cell_index].emission&0x3FF,(cell_data.data[cell_index].emission>>10)&0x7FF,cell_data.data[cell_index].emission>>21)) * params.emission_scale;
+	vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+
+#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));
+	const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
+#else
+	vec3 accum = vec3(0.0);
+#endif
+
+	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)) {
+			continue;
+		}
+
+		vec3 light_dir = pos - light_pos;
+		float distance = length(light_dir);
+		light_dir=normalize(light_dir);
+
+		if (length(normal.xyz) > 0.2 && dot(normal.xyz,light_dir)>=0) {
+			continue; //not facing the light
+		}
+
+		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;
+
+#ifdef MODE_ANISOTROPIC
+		for(uint j=0;j<6;j++) {
+
+			accum[j]+=max(0.0,dot(accum_dirs[j],-light_dir))*light+emission;
+		}
+#else
+		if (length(normal.xyz) > 0.2) {
+			accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission;
+		} else {
+			//all directions
+			accum+=light+emission;
+		}
+#endif
+	}
+
+
+#ifdef MODE_ANISOTROPIC
+
+	outputs.data[cell_index*6+0]=vec4(accum[0],0.0);
+	outputs.data[cell_index*6+1]=vec4(accum[1],0.0);
+	outputs.data[cell_index*6+2]=vec4(accum[2],0.0);
+	outputs.data[cell_index*6+3]=vec4(accum[3],0.0);
+	outputs.data[cell_index*6+4]=vec4(accum[4],0.0);
+	outputs.data[cell_index*6+5]=vec4(accum[5],0.0);
+#else
+	outputs.data[cell_index]=vec4(accum,0.0);
+
+#endif
+
+
+
+#endif //MODE_COMPUTE_LIGHT
+
+/////////////////SECOND BOUNCE///////////////////////////////
+#ifdef MODE_SECOND_BOUNCE
+	vec3 pos = vec3(posu) + vec3(0.5);
+	ivec3 ipos = ivec3(posu);
+	vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+
+
+#ifdef MODE_ANISOTROPIC
+	vec3 accum[6];
+	const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
+
+	/*vec3 src_color = texelFetch(sampler3D(color_texture,texture_sampler),ipos,0).rgb * params.dynamic_range;
+	vec3 src_aniso_pos = texelFetch(sampler3D(aniso_pos_texture,texture_sampler),ipos,0).rgb;
+	vec3 src_anisp_neg = texelFetch(sampler3D(anisp_neg_texture,texture_sampler),ipos,0).rgb;
+	accum[0]=src_col * src_aniso_pos.x;
+	accum[1]=src_col * src_aniso_neg.x;
+	accum[2]=src_col * src_aniso_pos.y;
+	accum[3]=src_col * src_aniso_neg.y;
+	accum[4]=src_col * src_aniso_pos.z;
+	accum[5]=src_col * src_aniso_neg.z;*/
+
+	accum[0] = outputs.data[cell_index*6+0].rgb;
+	accum[1] = outputs.data[cell_index*6+1].rgb;
+	accum[2] = outputs.data[cell_index*6+2].rgb;
+	accum[3] = outputs.data[cell_index*6+3].rgb;
+	accum[4] = outputs.data[cell_index*6+4].rgb;
+	accum[5] = outputs.data[cell_index*6+5].rgb;
+
+#else
+	vec3 accum = outputs.data[cell_index].rgb;
+
+#endif
+
+	if (length(normal.xyz) > 0.2) {
+
+		vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+		vec3 tangent = normalize(cross(v0, normal.xyz));
+		vec3 bitangent = normalize(cross(tangent, normal.xyz));
+		mat3 normal_mat = mat3(tangent, bitangent, normal.xyz);
+
+#define MAX_CONE_DIRS 6
+
+		vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+					vec3(0.0, 0.0, 1.0),
+					vec3(0.866025, 0.0, 0.5),
+					vec3(0.267617, 0.823639, 0.5),
+					vec3(-0.700629, 0.509037, 0.5),
+					vec3(-0.700629, -0.509037, 0.5),
+					vec3(0.267617, -0.823639, 0.5));
+
+		float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+		float tan_half_angle = 0.577;
+
+		for (int i = 0; i < MAX_CONE_DIRS; i++) {
+
+			vec3 direction = normal_mat * cone_dirs[i];
+			vec4 color = vec4(0.0);
+			{
+
+				float dist = 1.5;
+				float max_distance = length(vec3(params.limits));
+				vec3 cell_size = 1.0 / vec3(params.limits);
+
+#ifdef MODE_ANISOTROPIC
+				vec3 aniso_normal = mix(direction,normal.xyz,params.aniso_strength);
+#endif
+				while (dist < max_distance && color.a < 0.95) {
+					float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+					vec3 uvw_pos = (pos + dist * direction) * cell_size;
+					float half_diameter = diameter * 0.5;
+					//check if outside, then break
+					//if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+					//	break;
+					//}
+
+					float log2_diameter = log2(diameter);
+					vec4 scolor = textureLod(sampler3D(color_texture,texture_sampler), uvw_pos, log2_diameter);
+#ifdef MODE_ANISOTROPIC
+
+					vec3 aniso_neg = textureLod(sampler3D(aniso_neg_texture,texture_sampler), uvw_pos, log2_diameter).rgb;
+					vec3 aniso_pos = textureLod(sampler3D(aniso_pos_texture,texture_sampler), uvw_pos, log2_diameter).rgb;
+
+					scolor.rgb*=dot(max(vec3(0.0),(aniso_normal * aniso_pos)),vec3(1.0)) + dot(max(vec3(0.0),(-aniso_normal * aniso_neg)),vec3(1.0));
+#endif
+					float a = (1.0 - color.a);
+					color += a * scolor;
+					dist += half_diameter;
+
+				}
+
+			}
+			color *= cone_weights[i] * params.dynamic_range; //restore range
+#ifdef MODE_ANISOTROPIC
+			for(uint j=0;j<6;j++) {
+
+				accum[j]+=max(0.0,dot(accum_dirs[j],direction))*color.rgb;
+			}
+#else
+			accum+=color.rgb;
+#endif
+		}
+	}
+
+#ifdef MODE_ANISOTROPIC
+
+	outputs.data[cell_index*6+0]=vec4(accum[0],0.0);
+	outputs.data[cell_index*6+1]=vec4(accum[1],0.0);
+	outputs.data[cell_index*6+2]=vec4(accum[2],0.0);
+	outputs.data[cell_index*6+3]=vec4(accum[3],0.0);
+	outputs.data[cell_index*6+4]=vec4(accum[4],0.0);
+	outputs.data[cell_index*6+5]=vec4(accum[5],0.0);
+#else
+	outputs.data[cell_index]=vec4(accum,0.0);
+
+#endif
+
+#endif // MODE_SECOND_BOUNCE
+/////////////////UPDATE MIPMAPS///////////////////////////////
+
+#ifdef MODE_UPDATE_MIPMAPS
+
+	{
+#ifdef MODE_ANISOTROPIC
+		vec3 light_accum[6] = vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
+#else
+		vec3 light_accum = vec3(0.0);
+#endif
+		float count = 0.0;
+		for(uint i=0;i<8;i++) {
+			uint child_index = cell_children.data[cell_index].children[i];
+			if (child_index==NO_CHILDREN) {
+				continue;
+			}
+#ifdef MODE_ANISOTROPIC
+			light_accum[0] += outputs.data[child_index*6+0].rgb;
+			light_accum[1] += outputs.data[child_index*6+1].rgb;
+			light_accum[2] += outputs.data[child_index*6+2].rgb;
+			light_accum[3] += outputs.data[child_index*6+3].rgb;
+			light_accum[4] += outputs.data[child_index*6+4].rgb;
+			light_accum[5] += outputs.data[child_index*6+5].rgb;
+
+#else
+			light_accum += outputs.data[child_index].rgb;
+
+#endif
+
+			count+=1.0;
+		}
+
+		float divisor = mix(8.0,count,params.propagation);
+#ifdef MODE_ANISOTROPIC
+		outputs.data[cell_index*6+0]=vec4(light_accum[0] / divisor,0.0);
+		outputs.data[cell_index*6+1]=vec4(light_accum[1] / divisor,0.0);
+		outputs.data[cell_index*6+2]=vec4(light_accum[2] / divisor,0.0);
+		outputs.data[cell_index*6+3]=vec4(light_accum[3] / divisor,0.0);
+		outputs.data[cell_index*6+4]=vec4(light_accum[4] / divisor,0.0);
+		outputs.data[cell_index*6+5]=vec4(light_accum[5] / divisor,0.0);
+
+#else
+		outputs.data[cell_index]=vec4(light_accum / divisor,0.0);
+#endif
+
+
+
+	}
+#endif
+
+///////////////////WRITE TEXTURE/////////////////////////////
+
+#ifdef MODE_WRITE_TEXTURE
+	{
+
+#ifdef MODE_ANISOTROPIC
+		vec3 accum_total = vec3(0.0);
+		accum_total += outputs.data[cell_index*6+0].rgb;
+		accum_total += outputs.data[cell_index*6+1].rgb;
+		accum_total += outputs.data[cell_index*6+2].rgb;
+		accum_total += outputs.data[cell_index*6+3].rgb;
+		accum_total += outputs.data[cell_index*6+4].rgb;
+		accum_total += outputs.data[cell_index*6+5].rgb;
+
+		float accum_total_energy = max(dot(accum_total,GREY_VEC),0.00001);
+		vec3 iso_positive = vec3(dot(outputs.data[cell_index*6+0].rgb,GREY_VEC),dot(outputs.data[cell_index*6+2].rgb,GREY_VEC),dot(outputs.data[cell_index*6+4].rgb,GREY_VEC))/vec3(accum_total_energy);
+		vec3 iso_negative = vec3(dot(outputs.data[cell_index*6+1].rgb,GREY_VEC),dot(outputs.data[cell_index*6+3].rgb,GREY_VEC),dot(outputs.data[cell_index*6+5].rgb,GREY_VEC))/vec3(accum_total_energy);
+
+
+		{
+			uint aniso_pos = uint(clamp(iso_positive.b * 31.0,0.0,31.0));
+			aniso_pos |= uint(clamp(iso_positive.g * 63.0,0.0,63.0))<<5;
+			aniso_pos |= uint(clamp(iso_positive.r * 31.0,0.0,31.0))<<11;
+			imageStore(aniso_pos_tex,ivec3(posu),uvec4(aniso_pos));
+		}
+
+		{
+			uint aniso_neg = uint(clamp(iso_negative.b * 31.0,0.0,31.0));
+			aniso_neg |= uint(clamp(iso_negative.g * 63.0,0.0,63.0))<<5;
+			aniso_neg |= uint(clamp(iso_negative.r * 31.0,0.0,31.0))<<11;
+			imageStore(aniso_neg_tex,ivec3(posu),uvec4(aniso_neg));
+		}
+
+		imageStore(color_tex,ivec3(posu),vec4(accum_total / params.dynamic_range ,albedo.a));
+
+#else
+
+		imageStore(color_tex,ivec3(posu),vec4(outputs.data[cell_index].rgb / params.dynamic_range,albedo.a));
+
+#endif
+
+
+	}
+#endif
+}

+ 160 - 0
servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl

@@ -0,0 +1,160 @@
+[vertex]
+
+#version 450
+
+VERSION_DEFINES
+
+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=1,std140) buffer CellDataBuffer {
+    CellData data[];
+} cell_data;
+
+layout (set=0,binding=2) uniform texture3D color_tex;
+
+layout (set=0,binding=3) uniform sampler tex_sampler;
+
+#ifdef USE_ANISOTROPY
+layout (set=0,binding=4) uniform texture3D aniso_pos_tex;
+layout (set=0,binding=5) uniform texture3D aniso_neg_tex;
+#endif
+
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+	mat4 projection;
+	uint cell_offset;
+	float dynamic_range;
+	float alpha;
+	uint level;
+
+} params;
+
+layout(location=0) out vec4 color_interp;
+
+void main() {
+
+	const vec3 cube_triangles[36] = vec3[](
+	    vec3(-1.0f,-1.0f,-1.0f),
+	    vec3(-1.0f,-1.0f, 1.0f),
+	    vec3(-1.0f, 1.0f, 1.0f),
+	    vec3(1.0f, 1.0f,-1.0f),
+	    vec3(-1.0f,-1.0f,-1.0f),
+	    vec3(-1.0f, 1.0f,-1.0f),
+	    vec3(1.0f,-1.0f, 1.0f),
+	    vec3(-1.0f,-1.0f,-1.0f),
+	    vec3(1.0f,-1.0f,-1.0f),
+	    vec3(1.0f, 1.0f,-1.0f),
+	    vec3(1.0f,-1.0f,-1.0f),
+	    vec3(-1.0f,-1.0f,-1.0f),
+	    vec3(-1.0f,-1.0f,-1.0f),
+	    vec3(-1.0f, 1.0f, 1.0f),
+	    vec3(-1.0f, 1.0f,-1.0f),
+	    vec3(1.0f,-1.0f, 1.0f),
+	    vec3(-1.0f,-1.0f, 1.0f),
+	    vec3(-1.0f,-1.0f,-1.0f),
+	    vec3(-1.0f, 1.0f, 1.0f),
+	    vec3(-1.0f,-1.0f, 1.0f),
+	    vec3(1.0f,-1.0f, 1.0f),
+	    vec3(1.0f, 1.0f, 1.0f),
+	    vec3(1.0f,-1.0f,-1.0f),
+	    vec3(1.0f, 1.0f,-1.0f),
+	    vec3(1.0f,-1.0f,-1.0f),
+	    vec3(1.0f, 1.0f, 1.0f),
+	    vec3(1.0f,-1.0f, 1.0f),
+	    vec3(1.0f, 1.0f, 1.0f),
+	    vec3(1.0f, 1.0f,-1.0f),
+	    vec3(-1.0f, 1.0f,-1.0f),
+	    vec3(1.0f, 1.0f, 1.0f),
+	    vec3(-1.0f, 1.0f,-1.0f),
+	    vec3(-1.0f, 1.0f, 1.0f),
+	    vec3(1.0f, 1.0f, 1.0f),
+	    vec3(-1.0f, 1.0f, 1.0f),
+	    vec3(1.0f,-1.0f, 1.0f)
+	);
+
+
+	vec3 vertex = cube_triangles[gl_VertexIndex] * 0.5 + 0.5;
+
+	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);
+
+#ifdef MODE_DEBUG_COLOR
+	color_interp.xyz = unpackUnorm4x8(cell_data.data[cell_index].albedo).xyz;
+#endif
+#ifdef MODE_DEBUG_LIGHT
+
+#ifdef USE_ANISOTROPY
+
+#define POS_X 0
+#define POS_Y 1
+#define POS_Z 2
+#define NEG_X 3
+#define NEG_Y 4
+#define NEG_Z 5
+
+	const uint triangle_aniso[12] = uint[](
+			NEG_X,
+			NEG_Z,
+			NEG_Y,
+			NEG_Z,
+			NEG_X,
+			NEG_Y,
+			POS_Z,
+			POS_X,
+			POS_X,
+			POS_Y,
+			POS_Y,
+			POS_Z
+	);
+
+	color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).xyz * params.dynamic_range;
+	vec3 aniso_pos =  texelFetch(sampler3D(aniso_pos_tex,tex_sampler),ivec3(posu),int(params.level)).xyz;
+	vec3 aniso_neg =  texelFetch(sampler3D(aniso_neg_tex,tex_sampler),ivec3(posu),int(params.level)).xyz;
+	uint side = triangle_aniso[gl_VertexIndex/3];
+
+	float strength = 0.0;
+	switch(side) {
+	case POS_X: strength = aniso_pos.x; break;
+	case POS_Y: strength = aniso_pos.y; break;
+	case POS_Z: strength = aniso_pos.z; break;
+	case NEG_X: strength = aniso_neg.x; break;
+	case NEG_Y: strength = aniso_neg.y; break;
+	case NEG_Z: strength = aniso_neg.z; break;
+
+	}
+
+	color_interp.xyz *= strength;
+
+#else
+	color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).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);
+
+}
+
+[fragment]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location=0) in vec4 color_interp;
+layout(location=0) out vec4 frag_color;
+
+void main() {
+
+	frag_color = color_interp;
+}

+ 0 - 241
servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl

@@ -1,241 +0,0 @@
-[compute]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
-
-#define NO_CHILDREN 0xFFFFFFFF
-#define GREY_VEC vec3(0.33333,0.33333,0.33333)
-
-struct CellPosition {
-	uint children[8];
-};
-
-
-layout(set=0,binding=1,std140) buffer CellPositions {
-    CellPosition data[];
-} cell_positions;
-
-struct CellMaterial {
-	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,std140) buffer CellMaterials {
-    CellMaterial data[];
-} cell_materials;
-
-#define LIGHT_TYPE_DIRECTIONAL 0
-#define LIGHT_TYPE_OMNI 1
-#define LIGHT_TYPE_SPOT 2
-
-struct Light {
-
-	uint type;
-	float energy;
-	float radius;
-	float attenuation;
-
-	vec3 color;
-	float spot_angle_radians;
-
-	float advance;
-	float max_length;
-	uint pad0;
-	uint pad2;
-
-	vec3 position;
-	float spot_attenuation;
-
-
-	vec3 direction;
-	bool visible;
-
-	vec4 clip_planes[3];
-};
-
-layout(set=0,binding=3,std140) buffer Lights {
-    Light data[];
-} lights;
-
-
-layout(set=0,binding=4,std140) uniform Params {
-	vec3 limits;
-	float max_length;
-	uint size;
-	uint stack_size;
-	uint light_count;
-	float emission_scale;
-} params;
-
-
-layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex;
-
-
-uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
-
-	uint result = NO_CHILDREN;
-
-	while (distance > -distance_adv) { //use this to avoid precision errors
-
-		uint cell = 0;
-
-		ivec3 pos = ivec3(from);
-		ivec3 ofs = ivec3(0);
-		ivec3 half_size = ivec3(params.size) / 2;
-		if (any(lessThan(pos,ivec3(0))) || any(greaterThanEqual(pos,ivec3(params.size)))) {
-			return NO_CHILDREN; //outside range
-		}
-
-		for (int i = 0; i < params.stack_size - 1; i++) {
-
-			bvec3 greater = greaterThanEqual(pos,ofs+half_size);
-
-			ofs += mix(ivec3(0),half_size,greater);
-
-			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;
-			}
-
-			cell = cell_positions.data[cell].children[child];
-			if (cell == NO_CHILDREN)
-				break;
-
-			half_size >>= ivec3(1);
-		}
-
-		if ( cell != NO_CHILDREN) {
-			return cell; //found cell!
-		}
-
-		from += direction * distance_adv;
-		distance -= distance_adv;
-	}
-
-	return NO_CHILDREN;
-}
-
-bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
-
-	if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
-
-		light_pos = pos - lights.data[light].direction * params.max_length;
-		attenuation = 1.0;
-
-	} else {
-
-		light_pos = lights.data[light].position;
-		float distance = length(pos - light_pos);
-		if (distance >= lights.data[light].radius) {
-			return false;
-		}
-
-		attenuation = pow( distance / lights.data[light].radius + 0.0001, lights.data[light].attenuation );
-
-
-		if (lights.data[light].type==LIGHT_TYPE_SPOT) {
-
-			vec3 rel = normalize(pos - light_pos);
-			float angle = acos(dot(rel,lights.data[light].direction));
-			if (angle > lights.data[light].spot_angle_radians) {
-				return false;
-			}
-
-			float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
-			attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
-		}
-	}
-
-	return true;
-}
-
-void main() {
-
-	uint cell_index = gl_GlobalInvocationID.x;
-
-	uvec3 posu = uvec3(cell_materials.data[cell_index].position&0x3FF,(cell_materials.data[cell_index].position>>10)&0x3FF,cell_materials.data[cell_index].position>>20);
-	vec3 pos = vec3(posu);
-
-	vec3 emission = vec3(ivec3(cell_materials.data[cell_index].emission&0x3FF,(cell_materials.data[cell_index].emission>>10)&0x7FF,cell_materials.data[cell_index].emission>>21)) * params.emission_scale;
-	vec4 albedo = unpackUnorm4x8(cell_materials.data[cell_index].albedo);
-	vec4 normal = unpackSnorm4x8(cell_materials.data[cell_index].normal); //w >0.5 means, all directions
-
-#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));
-	const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
-#else
-	vec3 accum = vec3(0);
-#endif
-
-	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)) {
-			continue;
-		}
-
-		float distance_adv = lights.data[i].advance;
-
-		vec3 light_dir = pos - light_pos;
-		float distance = length(light_dir);
-
-		light_dir=normalize(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
-
-		if (normal.w < 0.5 && dot(normal.xyz,light_dir)>=0) {
-			continue; //not facing the light
-		}
-
-		uint result = raymarch(distance,distance_adv,from,lights.data[i].direction);
-
-		if (result != cell_index) {
-			continue; //was occluded
-		}
-
-		vec3 light = lights.data[i].color * albedo.rgb * attenuation;
-
-#ifdef MODE_ANISOTROPIC
-		for(uint j=0;j<6;j++) {
-			accum[j]+=max(0.0,dot(accum_dir,-light_dir))*light+emission;
-		}
-#else
-		if (normal.w < 0.5) {
-			accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission;
-		} else {
-			//all directions
-			accum+=light+emission;
-		}
-#endif
-
-	}
-
-#ifdef MODE_ANISOTROPIC
-
-	vec3 accum_total = accum[0]+accum[1]+accum[2]+accum[3]+accum[4]+accum[5];
-	float accum_total_energy = max(dot(accum_total,GREY_VEC),0.00001);
-	vec3 iso_positive = vec3(dot(aniso[0],GREY_VEC),dot(aniso[2],GREY_VEC),dot(aniso[4],GREY_VEC))/vec3(accum_total_energy);
-	vec3 iso_negative = vec3(dot(aniso[1],GREY_VEC),dot(aniso[3],GREY_VEC),dot(aniso[5],GREY_VEC))/vec3(accum_total_energy);
-
-	//store in 3D textures, total color, and isotropic magnitudes
-#else
-	//store in 3D texture pos, accum
-	imageStore(color_tex,ivec3(posu),vec4(accum,albedo.a));
-#endif
-
-}

+ 353 - 0
servers/visual/rasterizer_rd/shaders/giprobe_write.glsl

@@ -0,0 +1,353 @@
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+#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;
+
+#define LIGHT_TYPE_DIRECTIONAL 0
+#define LIGHT_TYPE_OMNI 1
+#define LIGHT_TYPE_SPOT 2
+
+#ifdef MODE_COMPUTE_LIGHT
+
+struct Light {
+
+	uint type;
+	float energy;
+	float radius;
+	float attenuation;
+
+	vec3 color;
+	float spot_angle_radians;
+
+	vec3 position;
+	float spot_attenuation;
+
+	vec3 direction;
+	bool has_shadow;
+};
+
+
+layout(set=0,binding=3,std140) uniform Lights {
+    Light data[MAX_LIGHTS];
+} lights;
+
+#endif
+
+layout(push_constant, binding = 0, std430) uniform Params {
+
+	ivec3 limits;
+	uint stack_size;
+
+	float emission_scale;
+	float propagation;
+	float dynamic_range;
+
+	uint light_count;
+	uint cell_offset;
+	uint cell_count;
+	uint pad[2];
+
+} params;
+
+
+layout(set=0,binding=4,std140) uniform Outputs {
+    vec4 data[];
+} output;
+
+
+
+#ifdef MODE_COMPUTE_LIGHT
+
+uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) {
+
+	uint result = NO_CHILDREN;
+
+	ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z));
+
+	while (distance > -distance_adv) { //use this to avoid precision errors
+
+		uint cell = 0;
+
+		ivec3 pos = ivec3(from);
+
+		if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) {
+
+			ivec3 ofs = ivec3(0);
+			ivec3 half_size = size / 2;
+
+			for (int i = 0; i < params.stack_size - 1; i++) {
+
+				bvec3 greater = greaterThanEqual(pos,ofs+half_size);
+
+				ofs += mix(ivec3(0),half_size,greater);
+
+				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;
+				}
+
+				cell = cell_children.data[cell].children[child];
+				if (cell == NO_CHILDREN)
+					break;
+
+				half_size >>= ivec3(1);
+			}
+
+			if ( cell != NO_CHILDREN) {
+				return cell; //found cell!
+			}
+
+		}
+
+		from += direction * distance_adv;
+		distance -= distance_adv;
+	}
+
+	return NO_CHILDREN;
+}
+
+bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) {
+
+
+	if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) {
+
+		light_pos = pos - lights.data[light].direction * length(vec3(params.limits));
+		attenuation = 1.0;
+
+	} else {
+
+		light_pos = lights.data[light].position;
+		float distance = length(pos - light_pos);
+		if (distance >= lights.data[light].radius) {
+			return false;
+		}
+
+
+		attenuation = pow( clamp( 1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation );
+
+
+		if (lights.data[light].type==LIGHT_TYPE_SPOT) {
+
+			vec3 rel = normalize(pos - light_pos);
+			float angle = acos(dot(rel,lights.data[light].direction));
+			if (angle > lights.data[light].spot_angle_radians) {
+				return false;
+			}
+
+			float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
+			attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
+		}
+	}
+
+	return true;
+}
+
+float get_normal_advance(vec3 p_normal) {
+
+	vec3 normal = p_normal;
+	vec3 unorm = abs(normal);
+
+	if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
+		// x code
+		unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
+	} else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
+		// y code
+		unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
+	} else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
+		// z code
+		unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
+	} else {
+		// oh-no we messed up code
+		// has to be
+		unorm = vec3(1.0, 0.0, 0.0);
+	}
+
+	return 1.0 / dot(normal,unorm);
+}
+
+#endif
+
+
+
+
+void main() {
+
+	uint cell_index = gl_GlobalInvocationID.x;;
+	if (cell_index >= params.cell_count) {
+		return;
+	}
+	cell_index += 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);
+	vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo);
+
+#ifdef MODE_COMPUTE_LIGHT
+
+	vec3 pos = vec3(posu) + vec3(0.5);
+
+	vec3 emission = vec3(ivec3(cell_data.data[cell_index].emission&0x3FF,(cell_data.data[cell_index].emission>>10)&0x7FF,cell_data.data[cell_index].emission>>21)) * params.emission_scale;
+	vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal);
+
+#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));
+	const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0));
+#else
+	vec3 accum = vec3(0.0);
+#endif
+
+	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)) {
+			continue;
+		}
+
+		vec3 light_dir = pos - light_pos;
+		float distance = length(light_dir);
+		light_dir=normalize(light_dir);
+
+		if (length(normal.xyz) > 0.2 && dot(normal.xyz,light_dir)>=0) {
+			continue; //not facing the light
+		}
+
+		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;
+
+#ifdef MODE_ANISOTROPIC
+		for(uint j=0;j<6;j++) {
+			accum[j]+=max(0.0,dot(accum_dir,-light_dir))*light+emission;
+		}
+#else
+		if (length(normal.xyz) > 0.2) {
+			accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission;
+		} else {
+			//all directions
+			accum+=light+emission;
+		}
+#endif
+
+	}
+
+#ifdef MODE_ANISOTROPIC
+
+	output.data[cell_index*6+0]=vec4(accum[0],0.0);
+	output.data[cell_index*6+1]=vec4(accum[1],0.0);
+	output.data[cell_index*6+2]=vec4(accum[2],0.0);
+	output.data[cell_index*6+3]=vec4(accum[3],0.0);
+	output.data[cell_index*6+4]=vec4(accum[4],0.0);
+	output.data[cell_index*6+5]=vec4(accum[5],0.0);
+#else
+	output.data[cell_index]=vec4(accum,0.0);
+
+#endif
+
+#endif //MODE_COMPUTE_LIGHT
+
+
+#ifdef MODE_UPDATE_MIPMAPS
+
+	{
+#ifdef MODE_ANISOTROPIC
+		vec3 light_accum[6] = vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
+#else
+		vec3 light_accum = vec3(0.0);
+#endif
+		float count = 0.0;
+		for(uint i=0;i<8;i++) {
+			uint child_index = cell_children.data[cell_index].children[i];
+			if (child_index==NO_CHILDREN) {
+				continue;
+			}
+#ifdef MODE_ANISOTROPIC
+			light_accum[1] += output.data[child_index*6+0].rgb;
+			light_accum[2] += output.data[child_index*6+1].rgb;
+			light_accum[3] += output.data[child_index*6+2].rgb;
+			light_accum[4] += output.data[child_index*6+3].rgb;
+			light_accum[5] += output.data[child_index*6+4].rgb;
+			light_accum[6] += output.data[child_index*6+5].rgb;
+
+#else
+			light_accum += output.data[child_index].rgb;
+
+#endif
+
+			count+=1.0;
+		}
+
+		float divisor = mix(8.0,count,params.propagation);
+#ifdef MODE_ANISOTROPIC
+		output.data[cell_index*6+0]=vec4(light_accum[0] / divisor,0.0);
+		output.data[cell_index*6+1]=vec4(light_accum[1] / divisor,0.0);
+		output.data[cell_index*6+2]=vec4(light_accum[2] / divisor,0.0);
+		output.data[cell_index*6+3]=vec4(light_accum[3] / divisor,0.0);
+		output.data[cell_index*6+4]=vec4(light_accum[4] / divisor,0.0);
+		output.data[cell_index*6+5]=vec4(light_accum[5] / divisor,0.0);
+
+#else
+		output.data[cell_index]=vec4(light_accum / divisor,0.0);
+#endif
+
+
+
+	}
+#endif
+
+#ifdef MODE_WRITE_TEXTURE
+	{
+
+
+
+	}
+#endif
+}

+ 298 - 4
servers/visual/rasterizer_rd/shaders/scene_forward.glsl

@@ -57,7 +57,7 @@ layout(location = 6) out vec3 binormal_interp;
 #endif
 
 #ifdef USE_MATERIAL_UNIFORMS
-layout(set = 2, binding = 0, std140) uniform MaterialUniforms {
+layout(set = 3, binding = 0, std140) uniform MaterialUniforms {
 /* clang-format off */
 MATERIAL_UNIFORMS
 /* clang-format on */
@@ -73,7 +73,7 @@ VERTEX_SHADER_GLOBALS
 
 // FIXME: This triggers a Mesa bug that breaks rendering, so disabled for now.
 // See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316
-//invariant gl_Position;
+invariant gl_Position;
 
 layout(location =7) flat out uint instance_index;
 
@@ -274,7 +274,7 @@ VERTEX_SHADER_CODE
 #endif //MODE_RENDER_DEPTH
 
 #ifdef USE_OVERRIDE_POSITION
-	gl_Position = position;;
+	gl_Position = position;
 #else
 	gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
 #endif
@@ -331,7 +331,7 @@ layout(location =8) in float dp_clip;
 #define projection_matrix scene_data.projection_matrix;
 
 #ifdef USE_MATERIAL_UNIFORMS
-layout(set = 2, binding = 0, std140) uniform MaterialUniforms {
+layout(set = 3, binding = 0, std140) uniform MaterialUniforms {
 /* clang-format off */
 MATERIAL_UNIFORMS
 /* clang-format on */
@@ -918,6 +918,265 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal,float roughness
 #endif //USE_LIGHTMAP
 }
 
+#ifdef USE_VOXEL_CONE_TRACING
+
+//standard voxel cone trace
+vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+	float dist = p_bias;
+	vec4 color = vec4(0.0);
+
+	while (dist < max_distance && color.a < 0.95) {
+		float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+		vec3 uvw_pos = (pos + dist * direction) * cell_size;
+		float half_diameter = diameter * 0.5;
+		//check if outside, then break
+		if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+			break;
+		}
+		vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter));
+		float a = (1.0 - color.a);
+		color += a * scolor;
+		dist += half_diameter;
+
+	}
+
+	return color;
+}
+#if 0
+vec4 voxel_cone_trace_skiplod(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+	float dist = p_bias;
+	vec4 color = vec4(0.0);
+	float skip_lod = 1.0;
+
+	while (dist < max_distance && color.a < 0.95) {
+		float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+		vec3 uvw_pos = (pos + dist * direction) * cell_size;
+		float half_diameter = diameter * 0.5;
+		//check if outside, then break
+		if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+			break;
+		}
+		vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter));
+		float a = (1.0 - color.a);
+		color += a * scolor;
+
+		float upper_opacity = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, skip_lod).a;
+		float skip_factor = exp2( max( 0.0f, skip_lod * 0.5f - 1.0f ) ) * (1.0f - upper_opacity) + upper_opacity;
+
+		skip_factor = mix( skip_factor, 1.0f, min( -1.0 + upper_opacity * probeParams.vctSpecularSdfFactor + tan_half_angle * 50.0f, 1.0f ) );
+		skip_lod = clamp( skip_lod + (1.0f - upper_opacity) * 2.0f - 1.0f, 1.0f, probeParams.vctSpecSdfMaxMip );
+
+		dist += half_diameter * skip_factor;
+	}
+
+	return color;
+}
+#endif
+
+#ifndef GI_PROBE_HIGH_QUALITY
+//faster version for 45 degrees
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+
+vec4 voxel_cone_trace_anisotropic_45_degrees(texture3D probe,texture3D aniso_pos,texture3D aniso_neg,vec3 normal, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+	float dist = p_bias;
+	vec4 color = vec4(0.0);
+	float radius = max(0.5, tan_half_angle * dist);
+	float lod_level = log2(radius*2.0);
+
+	while (dist < max_distance && color.a < 0.95) {
+		vec3 uvw_pos = (pos + dist * direction) * cell_size;
+		//check if outside, then break
+		if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + radius * cell_size)) ) ) {
+			break;
+		}
+
+		vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level);
+		vec3 aniso_neg = textureLod(sampler3D(aniso_neg,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
+		vec3 aniso_pos = textureLod(sampler3D(aniso_pos,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
+
+		scolor.rgb*=dot(max(vec3(0.0),(normal * aniso_pos)),vec3(1.0)) + dot(max(vec3(0.0),(-normal * aniso_neg)),vec3(1.0));
+		lod_level+=1.0;
+
+		float a = (1.0 - color.a);
+		color += a * scolor;
+		dist += radius;
+		radius = max(0.5, tan_half_angle * dist);
+
+
+	}
+
+	return color;
+}
+#else
+
+vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+	float dist = p_bias;
+	vec4 color = vec4(0.0);
+	float radius = max(0.5, tan_half_angle * dist);
+	float lod_level = log2(radius*2.0);
+
+	while (dist < max_distance && color.a < 0.95) {
+		vec3 uvw_pos = (pos + dist * direction) * cell_size;
+
+		//check if outside, then break
+		if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + radius * cell_size)) ) ) {
+			break;
+		}
+		vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level);
+		lod_level+=1.0;
+
+		float a = (1.0 - color.a);
+		color += a * scolor;
+		dist += radius;
+		radius = max(0.5, tan_half_angle * dist);
+
+	}
+
+	return color;
+}
+
+#endif
+
+
+#elif defined(GI_PROBE_USE_ANISOTROPY)
+
+
+//standard voxel cone trace
+vec4 voxel_cone_trace_anisotropic(texture3D probe,texture3D aniso_pos,texture3D aniso_neg,vec3 normal, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+	float dist = p_bias;
+	vec4 color = vec4(0.0);
+
+	while (dist < max_distance && color.a < 0.95) {
+		float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+		vec3 uvw_pos = (pos + dist * direction) * cell_size;
+		float half_diameter = diameter * 0.5;
+		//check if outside, then break
+		if ( any(greaterThan(abs(uvw_pos - 0.5),vec3(0.5f + half_diameter * cell_size)) ) ) {
+			break;
+		}
+		float log2_diameter = log2(diameter);
+		vec4 scolor = textureLod(sampler3D(probe,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter);
+		vec3 aniso_neg = textureLod(sampler3D(aniso_neg,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
+		vec3 aniso_pos = textureLod(sampler3D(aniso_pos,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
+
+		scolor.rgb*=dot(max(vec3(0.0),(normal * aniso_pos)),vec3(1.0)) + dot(max(vec3(0.0),(-normal * aniso_neg)),vec3(1.0));
+
+		float a = (1.0 - color.a);
+		color += a * scolor;
+		dist += half_diameter;
+
+	}
+
+	return color;
+}
+
+
+
+#endif
+
+void gi_probe_compute(uint index, vec3 position, vec3 normal,vec3 ref_vec, mat3 normal_xform, float roughness,vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
+
+
+
+	position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
+	ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+	normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
+
+	position += normal * gi_probes.data[index].normal_bias;
+
+	//this causes corrupted pixels, i have no idea why..
+	if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
+		return;
+	}
+
+	vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+	float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
+	//float blend=1.0;
+
+	float max_distance = length(gi_probes.data[index].bounds);
+	vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
+
+	//radiance
+#ifdef GI_PROBE_HIGH_QUALITY
+
+#define MAX_CONE_DIRS 6
+	vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+			vec3(0.0, 0.0, 1.0),
+			vec3(0.866025, 0.0, 0.5),
+			vec3(0.267617, 0.823639, 0.5),
+			vec3(-0.700629, 0.509037, 0.5),
+			vec3(-0.700629, -0.509037, 0.5),
+			vec3(0.267617, -0.823639, 0.5));
+
+	float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+	float cone_angle_tan = 0.577;
+#else
+
+#define MAX_CONE_DIRS 4
+
+	vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+			vec3(0.707107, 0.0, 0.707107),
+			vec3(0.0, 0.707107, 0.707107),
+			vec3(-0.707107, 0.0, 0.707107),
+			vec3(0.0, -0.707107, 0.707107));
+
+	float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
+	float cone_angle_tan = 0.98269;
+
+#endif
+	vec3 light = vec3(0.0);
+	for (int i = 0; i < MAX_CONE_DIRS; i++) {
+
+
+		vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
+
+#ifdef GI_PROBE_HIGH_QUALITY
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+		vec4 cone_light = voxel_cone_trace_anisotropic(gi_probe_textures[gi_probes.data[index].texture_slot],gi_probe_textures[gi_probes.data[index].texture_slot+1],gi_probe_textures[gi_probes.data[index].texture_slot+2],normalize(mix(dir,normal,gi_probes.data[index].anisotropy_strength)),cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#else
+		vec4 cone_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#endif // GI_PROBE_USE_ANISOTROPY
+
+#else
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+		vec4 cone_light = voxel_cone_trace_anisotropic_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot],gi_probe_textures[gi_probes.data[index].texture_slot+1],gi_probe_textures[gi_probes.data[index].texture_slot+2],normalize(mix(dir,normal,gi_probes.data[index].anisotropy_strength)),cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#else
+		vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#endif // GI_PROBE_USE_ANISOTROPY
+
+#endif
+		if (gi_probes.data[index].blend_ambient) {
+			cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95));
+		}
+		light+=cone_weights[i] * cone_light.rgb;
+	}
+
+	light *= gi_probes.data[index].dynamic_range;
+
+	out_diff += vec4(light * blend, blend);
+
+	//irradiance
+
+	vec4 irr_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
+	if (gi_probes.data[index].blend_ambient) {
+		irr_light.rgb = mix(environment,irr_light.rgb, min(1.0, irr_light.a / 0.95));
+	}
+	irr_light.rgb *= gi_probes.data[index].dynamic_range;
+	//irr_light=vec3(0.0);
+
+	out_spec += vec4(irr_light.rgb * blend, blend);
+}
+
+#endif //USE_VOXEL_CONE_TRACING
+
 #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
 
 
@@ -1118,7 +1377,42 @@ FRAGMENT_SHADER_CODE
 
 	//lightmap capture
 
+#ifdef USE_VOXEL_CONE_TRACING
+	{ // process giprobes
+		uint index1 = instances.data[instance_index].gi_offset&0xFFFF;
+		if (index1!=0xFFFF) {
+			vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
+			//find arbitrary tangent and bitangent, then build a matrix
+			vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+			vec3 tangent = normalize(cross(v0, normal));
+			vec3 bitangent = normalize(cross(tangent, normal));
+			mat3 normal_mat = mat3(tangent, bitangent, normal);
+
+			vec4 amb_accum = vec4(0.0);
+			vec4 spec_accum = vec4(0.0);
+
+			gi_probe_compute(index1, vertex, normal, ref_vec,normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum );
+
+			uint index2 = instances.data[instance_index].gi_offset>>16;
+
+			if (index2!=0xFFFF) {
+				gi_probe_compute(index2, vertex, normal, ref_vec,normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum );
+			}
+
+			if (amb_accum.a > 0.0) {
+				amb_accum.rgb /= amb_accum.a;
+			}
+
+			if (spec_accum.a > 0.0) {
+				spec_accum.rgb /= spec_accum.a;
+			}
+
+			specular_light = spec_accum.rgb;
+			ambient_light = amb_accum.rgb;
 
+		}
+	}
+#endif
 	{ // process reflections
 
 

+ 59 - 64
servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl

@@ -9,22 +9,7 @@ layout(push_constant, binding = 0, std430) uniform DrawCall {
 
 
 
-/* Set 0 Scene data, screen and sources (changes the least) */
-
-layout(set=0,binding=1) uniform texture2D depth_buffer;
-layout(set=0,binding=2) uniform texture2D color_buffer;
-layout(set=0,binding=3) uniform texture2D normal_buffer;
-layout(set=0,binding=4) uniform texture2D roughness_limit;
-
-#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-
-layout(set = 0, binding = 5) uniform textureCubeArray radiance_cubemap;
-
-#else
-
-layout(set = 0, binding = 5) uniform textureCube radiance_cubemap;
-
-#endif
+/* Set 0 Scene data that never changes, ever */
 
 
 #define SAMPLER_NEAREST_CLAMP 0
@@ -40,11 +25,11 @@ layout(set = 0, binding = 5) uniform textureCube radiance_cubemap;
 #define SAMPLER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC_REPEAT 10
 #define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
 
-layout(set = 0, binding = 6) uniform sampler material_samplers[12];
+layout(set = 0, binding = 1) uniform sampler material_samplers[12];
 
-layout(set = 0, binding = 7) uniform sampler shadow_sampler;
+layout(set = 0, binding = 2) uniform sampler shadow_sampler;
 
-layout(set=0,binding=8,std140) uniform SceneData {
+layout(set=0,binding=3,std140) uniform SceneData {
 
 	mat4 projection_matrix;
 	mat4 inv_projection_matrix;
@@ -149,28 +134,10 @@ struct InstanceData {
 };
 
 
-layout(set=0,binding=9,std430)  buffer Instances {
+layout(set=0,binding=4,std430)  buffer Instances {
     InstanceData data[];
 } instances;
 
-struct ReflectionData {
-
-	vec3 box_extents;
-	float index;
-	vec3 box_offset;
-	uint mask;
-	vec4 params; // intensity, 0, interior , boxproject
-	vec4 ambient; // ambient color, energy
-	mat4 local_matrix; // up to here for spot and omni, rest is for directional
-	// notes: for ambientblend, use distance to edge to blend between already existing global environment
-};
-
-layout(set=0,binding=10,std140) uniform ReflectionProbeData {
-	ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
-} reflections;
-
-layout(set=0,binding=11) uniform textureCubeArray reflection_atlas;
-
 struct LightData { //this structure needs to be 128 bits
 
 	vec3 position;
@@ -185,11 +152,25 @@ struct LightData { //this structure needs to be 128 bits
 	mat4 shadow_matrix;
 };
 
-layout(set=0,binding=12,std140) uniform Lights {
+layout(set=0,binding=5,std140) uniform Lights {
 	LightData data[MAX_LIGHT_DATA_STRUCTS];
 } lights;
 
-layout(set=0,binding=13) uniform texture2D shadow_atlas;
+struct ReflectionData {
+
+	vec3 box_extents;
+	float index;
+	vec3 box_offset;
+	uint mask;
+	vec4 params; // intensity, 0, interior , boxproject
+	vec4 ambient; // ambient color, energy
+	mat4 local_matrix; // up to here for spot and omni, rest is for directional
+	// notes: for ambientblend, use distance to edge to blend between already existing global environment
+};
+
+layout(set=0,binding=6,std140) uniform ReflectionProbeData {
+	ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
+} reflections;
 
 struct DirectionalLightData {
 
@@ -211,51 +192,65 @@ struct DirectionalLightData {
 
 };
 
-layout(set=0,binding=14,std140) uniform DirectionalLights {
+layout(set=0,binding=7,std140) uniform DirectionalLights {
 	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
 } directional_lights;
 
-layout(set=0,binding=15) uniform texture2D directional_shadow_atlas;
+struct GIProbeData {
+	mat4 xform;
+	vec3 bounds;
+	float dynamic_range;
 
-/*
-layout(set=0,binding=15,std430)  buffer Skeletons {
-    vec4 data[];
-} skeletons;
-*/
+	float bias;
+	float normal_bias;
+	bool blend_ambient;
+	uint texture_slot;
 
-/* Set 1 Instancing (Multimesh) */
+	float anisotropy_strength;
+	uint pad0;
+	uint pad1;
+	uint pad2;
+};
 
-//layout(set = 1, binding = 0) uniform textureBuffer multimesh_transforms;
+layout(set=0,binding=8,std140) uniform GIProbes {
+	GIProbeData data[MAX_GI_PROBES];
+} gi_probes;
 
-layout(set=1,binding=0,std430) buffer Transforms {
-    vec4 data[];
-} transforms;
+layout(set=0,binding=9) uniform texture3D gi_probe_textures[MAX_GI_PROBE_TEXTURES];
 
 
-/* Set 2 Instancing (Multimesh) data */
+/* Set 1, Scene data that changes per render pass */
 
-#if 0
+
+layout(set=1,binding=0) uniform texture2D depth_buffer;
+layout(set=1,binding=1) uniform texture2D color_buffer;
+layout(set=1,binding=2) uniform texture2D normal_buffer;
+layout(set=1,binding=3) uniform texture2D roughness_limit;
 
 #ifdef USE_RADIANCE_CUBEMAP_ARRAY
 
-layout(set = 3, binding = 2) uniform textureCubeArray reflection_probes[MAX_REFLECTION_PROBES];
+layout(set = 1, binding = 4) uniform textureCubeArray radiance_cubemap;
 
 #else
 
-layout(set = 3, binding = 2) uniform textureCube reflection_probes[MAX_REFLECTION_PROBES];
+layout(set = 1, binding = 4) uniform textureCube radiance_cubemap;
 
 #endif
 
 
-#ifdef USE_VOXEL_CONE_TRACING
+layout(set=1,binding=5) uniform textureCubeArray reflection_atlas;
 
-layout(set = 3, binding = 4) uniform texture3D gi_probe[2];
+layout(set=1,binding=6) uniform texture2D shadow_atlas;
 
-#ifdef USE_ANISOTROPIC_VOXEL_CONE_TRACING
-layout(set = 3, binding = 5) uniform texture3D gi_probe_aniso_pos[2];
-layout(set = 3, binding = 6) uniform texture3D gi_probe_aniso_neg[2];
-#endif
+layout(set=1,binding=7) uniform texture2D directional_shadow_atlas;
+
+
+/* Set 2 Skeleton & Instancing (Multimesh) */
+
+layout(set=2,binding=0,std430) buffer Transforms {
+    vec4 data[];
+} transforms;
+
+/* Set 3 User Material */
 
 
-#endif
-#endif

+ 11 - 8
servers/visual/rendering_device.h

@@ -412,7 +412,8 @@ public:
 
 	enum TextureSliceType {
 		TEXTURE_SLICE_2D,
-		TEXTURE_SLICE_CUBEMAP
+		TEXTURE_SLICE_CUBEMAP,
+		TEXTURE_SLICE_3D,
 	};
 
 	virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0;
@@ -425,6 +426,8 @@ public:
 	virtual bool texture_is_valid(RID p_texture) = 0;
 
 	virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false) = 0;
+	virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false) = 0;
+
 	/*********************/
 	/**** FRAMEBUFFER ****/
 	/*********************/
@@ -903,15 +906,13 @@ public:
 
 	enum InitialAction {
 		INITIAL_ACTION_CLEAR, //start rendering and clear the framebuffer (supply params)
-		INITIAL_ACTION_KEEP_COLOR, //start rendering, but keep attached color texture contents (depth will be cleared)
-		INITIAL_ACTION_KEEP_COLOR_AND_DEPTH, //start rendering, but keep attached color and depth texture contents (depth will be cleared)
+		INITIAL_ACTION_KEEP, //start rendering, but keep attached color texture contents (depth will be cleared)
 		INITIAL_ACTION_CONTINUE, //continue rendering (framebuffer must have been left in "continue" state as final action prevously)
 		INITIAL_ACTION_MAX
 	};
 
 	enum FinalAction {
-		FINAL_ACTION_READ_COLOR_AND_DEPTH, //will no longer render to it, allows attached textures to be read again, but depth buffer contents will be dropped (Can't be read from)
-		FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, //will no longer render to it, allows attached textures to be read again
+		FINAL_ACTION_READ, //will no longer render to it, allows attached textures to be read again, but depth buffer contents will be dropped (Can't be read from)
 		FINAL_ACTION_DISCARD, // discard contents after rendering
 		FINAL_ACTION_CONTINUE, //will continue rendering later, attached textures can't be read until re-bound with "finish"
 		FINAL_ACTION_MAX
@@ -920,8 +921,8 @@ public:
 	typedef int64_t DrawListID;
 
 	virtual DrawListID draw_list_begin_for_screen(int p_screen = 0, const Color &p_clear_color = Color()) = 0;
-	virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), const Rect2 &p_region = Rect2()) = 0;
-	virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), const Rect2 &p_region = Rect2()) = 0;
+	virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()) = 0;
+	virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()) = 0;
 
 	virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) = 0;
 	virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
@@ -930,7 +931,7 @@ public:
 	virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0;
 	virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) = 0;
 
-	virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1) = 0;
+	virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0) = 0;
 
 	virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0;
 	virtual void draw_list_disable_scissor(DrawListID p_list) = 0;
@@ -948,6 +949,8 @@ public:
 	virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
 	virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) = 0;
 	virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0;
+	virtual void compute_list_add_barrier(ComputeListID p_list) = 0;
+
 	virtual void compute_list_end() = 0;
 
 	/***************/

+ 15 - 15
servers/visual/visual_server_raster.h

@@ -344,17 +344,20 @@ public:
 
 	BIND0R(RID, gi_probe_create)
 
-	BIND2(gi_probe_set_bounds, RID, const AABB &)
-	BIND1RC(AABB, gi_probe_get_bounds, RID)
-
-	BIND2(gi_probe_set_cell_size, RID, float)
-	BIND1RC(float, gi_probe_get_cell_size, RID)
+	BIND7(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &)
 
-	BIND2(gi_probe_set_to_cell_xform, RID, const Transform &)
+	BIND1RC(AABB, gi_probe_get_bounds, RID)
+	BIND1RC(Vector3i, gi_probe_get_octree_size, RID)
+	BIND1RC(PoolVector<uint8_t>, gi_probe_get_octree_cells, RID)
+	BIND1RC(PoolVector<uint8_t>, gi_probe_get_data_cells, RID)
+	BIND1RC(PoolVector<int>, gi_probe_get_level_counts, RID)
 	BIND1RC(Transform, gi_probe_get_to_cell_xform, RID)
 
-	BIND2(gi_probe_set_dynamic_range, RID, int)
-	BIND1RC(int, gi_probe_get_dynamic_range, RID)
+	BIND2(gi_probe_set_dynamic_range, RID, float)
+	BIND1RC(float, gi_probe_get_dynamic_range, RID)
+
+	BIND2(gi_probe_set_propagation, RID, float)
+	BIND1RC(float, gi_probe_get_propagation, RID)
 
 	BIND2(gi_probe_set_energy, RID, float)
 	BIND1RC(float, gi_probe_get_energy, RID)
@@ -365,17 +368,14 @@ public:
 	BIND2(gi_probe_set_normal_bias, RID, float)
 	BIND1RC(float, gi_probe_get_normal_bias, RID)
 
-	BIND2(gi_probe_set_propagation, RID, float)
-	BIND1RC(float, gi_probe_get_propagation, RID)
-
 	BIND2(gi_probe_set_interior, RID, bool)
 	BIND1RC(bool, gi_probe_is_interior, RID)
 
-	BIND2(gi_probe_set_compress, RID, bool)
-	BIND1RC(bool, gi_probe_is_compressed, RID)
+	BIND2(gi_probe_set_use_two_bounces, RID, bool)
+	BIND1RC(bool, gi_probe_is_using_two_bounces, RID)
 
-	BIND2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &)
-	BIND1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID)
+	BIND2(gi_probe_set_anisotropy_strength, RID, float)
+	BIND1RC(float, gi_probe_get_anisotropy_strength, RID)
 
 	/* LIGHTMAP CAPTURE */
 

Datei-Diff unterdrückt, da er zu groß ist
+ 152 - 953
servers/visual/visual_server_scene.cpp


+ 8 - 112
servers/visual/visual_server_scene.h

@@ -48,6 +48,7 @@ public:
 		MAX_INSTANCE_CULL = 65536,
 		MAX_LIGHTS_CULLED = 4096,
 		MAX_REFLECTION_PROBES_CULLED = 4096,
+		MAX_GI_PROBES_CULLED = 4096,
 		MAX_ROOM_CULL = 32,
 		MAX_EXTERIOR_PORTALS = 128,
 	};
@@ -324,77 +325,16 @@ public:
 			Transform transform;
 			Color color;
 			float energy;
+			float bake_energy;
 			float radius;
 			float attenuation;
 			float spot_angle;
 			float spot_attenuation;
-			bool visible;
-
-			bool operator==(const LightCache &p_cache) {
-
-				return (type == p_cache.type &&
-						transform == p_cache.transform &&
-						color == p_cache.color &&
-						energy == p_cache.energy &&
-						radius == p_cache.radius &&
-						attenuation == p_cache.attenuation &&
-						spot_angle == p_cache.spot_angle &&
-						spot_attenuation == p_cache.spot_attenuation &&
-						visible == p_cache.visible);
-			}
-
-			bool operator!=(const LightCache &p_cache) {
-
-				return !operator==(p_cache);
-			}
-
-			LightCache() {
-
-				type = VS::LIGHT_DIRECTIONAL;
-				energy = 1.0;
-				radius = 1.0;
-				attenuation = 1.0;
-				spot_angle = 1.0;
-				spot_attenuation = 1.0;
-				visible = true;
-			}
-		};
-
-		struct LocalData {
-			uint16_t pos[3];
-			uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights
-		};
-
-		struct CompBlockS3TC {
-			uint32_t offset; //offset in mipmap
-			uint32_t source_count; //sources
-			uint32_t sources[16]; //id for each source
-			uint8_t alpha[8]; //alpha block is pre-computed
+			bool has_shadow;
 		};
 
-		struct Dynamic {
-
-			Map<RID, LightCache> light_cache;
-			Map<RID, LightCache> light_cache_changes;
-			PoolVector<int> light_data;
-			PoolVector<LocalData> local_data;
-			Vector<Vector<uint32_t> > level_cell_lists;
-			RID probe_data;
-			bool enabled;
-			int bake_dynamic_range;
-			RasterizerStorage::GIProbeCompression compression;
-
-			Vector<PoolVector<uint8_t> > mipmaps_3d;
-			Vector<PoolVector<CompBlockS3TC> > mipmaps_s3tc; //for s3tc
-
-			int updating_stage;
-			float propagate;
-
-			int grid_size[3];
-
-			Transform light_to_cell_xform;
-
-		} dynamic;
+		Vector<LightCache> light_cache;
+		Vector<RID> light_instances;
 
 		RID probe_instance;
 
@@ -407,7 +347,6 @@ public:
 				update_element(this) {
 			invalid = true;
 			base_version = 0;
-			dynamic.updating_stage = GI_UPDATE_STAGE_CHECK;
 		}
 	};
 
@@ -436,6 +375,8 @@ public:
 	int directional_light_count;
 	RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
 	int reflection_probe_cull_count;
+	RID gi_probe_instance_cull_result[MAX_GI_PROBES_CULLED];
+	int gi_probe_cull_count;
 
 	RID_PtrOwner<Instance> instance_owner;
 
@@ -477,6 +418,7 @@ public:
 
 	_FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario);
 
+	bool _render_reflection_probe_step(Instance *p_instance, int p_step);
 	void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true);
 	void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
 	void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
@@ -485,52 +427,6 @@ public:
 	void render_camera(RID p_render_buffers, Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas);
 	void update_dirty_instances();
 
-	//probes
-	struct GIProbeDataHeader {
-
-		uint32_t version;
-		uint32_t cell_subdiv;
-		uint32_t width;
-		uint32_t height;
-		uint32_t depth;
-		uint32_t cell_count;
-		uint32_t leaf_cell_count;
-	};
-
-	struct GIProbeDataCell {
-
-		uint32_t children[8];
-		uint32_t albedo;
-		uint32_t emission;
-		uint32_t normal;
-		uint32_t level_alpha;
-	};
-
-	enum {
-		GI_UPDATE_STAGE_CHECK,
-		GI_UPDATE_STAGE_LIGHTING,
-		GI_UPDATE_STAGE_UPLOADING,
-	};
-
-	void _gi_probe_bake_thread();
-	static void _gi_probe_bake_threads(void *);
-
-	volatile bool probe_bake_thread_exit;
-	Thread *probe_bake_thread;
-	SemaphoreOld *probe_bake_sem;
-	Mutex *probe_bake_mutex;
-	List<Instance *> probe_bake_list;
-
-	bool _render_reflection_probe_step(Instance *p_instance, int p_step);
-	void _gi_probe_fill_local_data(int p_idx, int p_level, int p_x, int p_y, int p_z, const GIProbeDataCell *p_cell, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, Vector<uint32_t> *prev_cell);
-
-	_FORCE_INLINE_ uint32_t _gi_bake_find_cell(const GIProbeDataCell *cells, int x, int y, int z, int p_cell_subdiv);
-	void _bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell *p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, float p_propagate);
-	void _bake_gi_probe_light(const GIProbeDataHeader *header, const GIProbeDataCell *cells, InstanceGIProbeData::LocalData *local_data, const uint32_t *leaves, int p_leaf_count, const InstanceGIProbeData::LightCache &light_cache, int p_sign);
-	void _bake_gi_probe(Instance *p_gi_probe);
-	bool _check_gi_probe(Instance *p_gi_probe);
-	void _setup_gi_probe(Instance *p_instance);
-
 	void render_probes();
 
 	bool free(RID p_rid);

+ 15 - 15
servers/visual/visual_server_wrap_mt.h

@@ -268,17 +268,20 @@ public:
 
 	FUNCRID(gi_probe)
 
-	FUNC2(gi_probe_set_bounds, RID, const AABB &)
-	FUNC1RC(AABB, gi_probe_get_bounds, RID)
-
-	FUNC2(gi_probe_set_cell_size, RID, float)
-	FUNC1RC(float, gi_probe_get_cell_size, RID)
+	FUNC7(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &)
 
-	FUNC2(gi_probe_set_to_cell_xform, RID, const Transform &)
+	FUNC1RC(AABB, gi_probe_get_bounds, RID)
+	FUNC1RC(Vector3i, gi_probe_get_octree_size, RID)
+	FUNC1RC(PoolVector<uint8_t>, gi_probe_get_octree_cells, RID)
+	FUNC1RC(PoolVector<uint8_t>, gi_probe_get_data_cells, RID)
+	FUNC1RC(PoolVector<int>, gi_probe_get_level_counts, RID)
 	FUNC1RC(Transform, gi_probe_get_to_cell_xform, RID)
 
-	FUNC2(gi_probe_set_dynamic_range, RID, int)
-	FUNC1RC(int, gi_probe_get_dynamic_range, RID)
+	FUNC2(gi_probe_set_dynamic_range, RID, float)
+	FUNC1RC(float, gi_probe_get_dynamic_range, RID)
+
+	FUNC2(gi_probe_set_propagation, RID, float)
+	FUNC1RC(float, gi_probe_get_propagation, RID)
 
 	FUNC2(gi_probe_set_energy, RID, float)
 	FUNC1RC(float, gi_probe_get_energy, RID)
@@ -289,17 +292,14 @@ public:
 	FUNC2(gi_probe_set_normal_bias, RID, float)
 	FUNC1RC(float, gi_probe_get_normal_bias, RID)
 
-	FUNC2(gi_probe_set_propagation, RID, float)
-	FUNC1RC(float, gi_probe_get_propagation, RID)
-
 	FUNC2(gi_probe_set_interior, RID, bool)
 	FUNC1RC(bool, gi_probe_is_interior, RID)
 
-	FUNC2(gi_probe_set_compress, RID, bool)
-	FUNC1RC(bool, gi_probe_is_compressed, RID)
+	FUNC2(gi_probe_set_use_two_bounces, RID, bool)
+	FUNC1RC(bool, gi_probe_is_using_two_bounces, RID)
 
-	FUNC2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &)
-	FUNC1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID)
+	FUNC2(gi_probe_set_anisotropy_strength, RID, float)
+	FUNC1RC(float, gi_probe_get_anisotropy_strength, RID)
 
 	/* LIGHTMAP CAPTURE */
 

+ 8 - 0
servers/visual_server.cpp

@@ -1710,6 +1710,10 @@ void VisualServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &VisualServer::reflection_probe_set_enable_shadows);
 	ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &VisualServer::reflection_probe_set_cull_mask);
 
+#ifndef _MSC_VER
+#warning TODO all giprobe methods need re-binding
+#endif
+#if 0
 	ClassDB::bind_method(D_METHOD("gi_probe_create"), &VisualServer::gi_probe_create);
 	ClassDB::bind_method(D_METHOD("gi_probe_set_bounds", "probe", "bounds"), &VisualServer::gi_probe_set_bounds);
 	ClassDB::bind_method(D_METHOD("gi_probe_get_bounds", "probe"), &VisualServer::gi_probe_get_bounds);
@@ -1733,6 +1737,7 @@ void VisualServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("gi_probe_is_interior", "probe"), &VisualServer::gi_probe_is_interior);
 	ClassDB::bind_method(D_METHOD("gi_probe_set_compress", "probe", "enable"), &VisualServer::gi_probe_set_compress);
 	ClassDB::bind_method(D_METHOD("gi_probe_is_compressed", "probe"), &VisualServer::gi_probe_is_compressed);
+#endif
 
 	ClassDB::bind_method(D_METHOD("lightmap_capture_create"), &VisualServer::lightmap_capture_create);
 	ClassDB::bind_method(D_METHOD("lightmap_capture_set_bounds", "capture", "bounds"), &VisualServer::lightmap_capture_set_bounds);
@@ -2297,6 +2302,9 @@ VisualServer::VisualServer() {
 	GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size.mobile", 128);
 	GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_count", 64);
 
+	GLOBAL_DEF("rendering/quality/gi_probes/anisotropic", false);
+	GLOBAL_DEF("rendering/quality/gi_probes/high_quality", false);
+
 	GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false);
 	GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true);
 	GLOBAL_DEF("rendering/quality/shading/force_lambert_over_burley", false);

+ 27 - 24
servers/visual_server.h

@@ -465,38 +465,38 @@ public:
 
 	virtual RID gi_probe_create() = 0;
 
-	virtual void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds) = 0;
-	virtual AABB gi_probe_get_bounds(RID p_probe) const = 0;
+	virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) = 0;
 
-	virtual void gi_probe_set_cell_size(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_cell_size(RID p_probe) const = 0;
+	virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
+	virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
+	virtual PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
+	virtual PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
+	virtual PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
+	virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform) = 0;
-	virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const = 0;
+	virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
+	virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data) = 0;
-	virtual PoolVector<int> gi_probe_get_dynamic_data(RID p_probe) const = 0;
+	virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
+	virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_dynamic_range(RID p_probe, int p_range) = 0;
-	virtual int gi_probe_get_dynamic_range(RID p_probe) const = 0;
+	virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
+	virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_energy(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_energy(RID p_probe) const = 0;
+	virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
+	virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_bias(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_bias(RID p_probe) const = 0;
+	virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
+	virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_normal_bias(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_normal_bias(RID p_probe) const = 0;
+	virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
+	virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_propagation(RID p_probe, float p_range) = 0;
-	virtual float gi_probe_get_propagation(RID p_probe) const = 0;
+	virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
+	virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
 
-	virtual void gi_probe_set_interior(RID p_probe, bool p_enable) = 0;
-	virtual bool gi_probe_is_interior(RID p_probe) const = 0;
-
-	virtual void gi_probe_set_compress(RID p_probe, bool p_enable) = 0;
-	virtual bool gi_probe_is_compressed(RID p_probe) const = 0;
+	virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
+	virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
 
 	/* LIGHTMAP CAPTURE */
 
@@ -650,7 +650,10 @@ public:
 		VIEWPORT_DEBUG_DRAW_LIGHTING,
 		VIEWPORT_DEBUG_DRAW_OVERDRAW,
 		VIEWPORT_DEBUG_DRAW_WIREFRAME,
-		VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS
+		VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO,
+		VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING,
+		VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS,
+		VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
 
 	};
 

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.