summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2019-10-03 17:39:08 -0300
committerJuan Linietsky <reduzio@gmail.com>2020-02-11 12:03:20 +0100
commitacf0f6c8a7955517ef71ec95c683a6ff7bd5f437 (patch)
tree2bbadc4c770579be1f63317363b1843efff4d6f1
parent52f96abd8ba4323ff358f34683f9502ec24b9961 (diff)
GIProbes working.
-rw-r--r--core/class_db.cpp13
-rw-r--r--core/class_db.h1
-rw-r--r--core/io/resource_format_binary.cpp2
-rw-r--r--core/io/resource_loader.cpp3
-rw-r--r--core/math/vector3.h10
-rw-r--r--core/math/vector3i.cpp25
-rw-r--r--core/math/vector3i.h242
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp356
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h41
-rw-r--r--drivers/vulkan/vulkan_context.cpp5
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.cpp2
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.h2
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp103
-rw-r--r--editor/plugins/spatial_editor_plugin.h9
-rw-r--r--editor/spatial_editor_gizmos.cpp4
-rw-r--r--editor/spatial_editor_gizmos.h3
-rw-r--r--scene/3d/baked_lightmap.cpp10
-rw-r--r--scene/3d/baked_lightmap.h2
-rw-r--r--scene/3d/gi_probe.cpp343
-rw-r--r--scene/3d/gi_probe.h78
-rw-r--r--scene/3d/voxel_light_baker.cpp2486
-rw-r--r--scene/3d/voxelizer.cpp1108
-rw-r--r--scene/3d/voxelizer.h (renamed from scene/3d/voxel_light_baker.h)116
-rw-r--r--scene/main/viewport.h6
-rw-r--r--scene/register_scene_types.cpp4
-rw-r--r--scene/resources/mesh.cpp25
-rw-r--r--scene/resources/resource_format_text.cpp2
-rw-r--r--servers/visual/rasterizer.h65
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp4
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp16
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp826
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h31
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp563
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.h179
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp265
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.h95
-rw-r--r--servers/visual/rasterizer_rd/shaders/SCsub3
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe.glsl543
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl160
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl241
-rw-r--r--servers/visual/rasterizer_rd/shaders/giprobe_write.glsl353
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_forward.glsl302
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl123
-rw-r--r--servers/visual/rendering_device.h19
-rw-r--r--servers/visual/visual_server_raster.h30
-rw-r--r--servers/visual/visual_server_scene.cpp1122
-rw-r--r--servers/visual/visual_server_scene.h120
-rw-r--r--servers/visual/visual_server_wrap_mt.h30
-rw-r--r--servers/visual_server.cpp8
-rw-r--r--servers/visual_server.h51
51 files changed, 5064 insertions, 5088 deletions
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 8800f51778..a2941d70f6 100644
--- a/core/class_db.cpp
+++ b/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;
diff --git a/core/class_db.h b/core/class_db.h
index 34301d6cba..404b04f2d0 100644
--- a/core/class_db.h
+++ b/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);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 97dca98185..7325532b6f 100644
--- a/core/io/resource_format_binary.cpp
+++ b/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);
}
///////////////////////////////////////////////////////////
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index b6e75dd0e7..0ee6478fa2 100644
--- a/core/io/resource_loader.cpp
+++ b/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 "";
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 4ad3017109..3bf8644af9 100644
--- a/core/math/vector3.h
+++ b/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;
diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp
new file mode 100644
index 0000000000..d5e05c1398
--- /dev/null
+++ b/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));
+}
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
new file mode 100644
index 0000000000..cb2e2bdd2d
--- /dev/null
+++ b/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
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 7e9d11137e..118679a8b5 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/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
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 2781fc71e2..d487f4612e 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/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();
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index f232073f47..34ce79ab02 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/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 : ");
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6256dff967..e7cda66d3c 100644
--- a/editor/editor_node.cpp
+++ b/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)));
diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp
index 7db936ccb8..6bc9562c5a 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.cpp
+++ b/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
diff --git a/editor/plugins/baked_lightmap_editor_plugin.h b/editor/plugins/baked_lightmap_editor_plugin.h
index 8b94257a62..818cdfe8fa 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.h
+++ b/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
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 7c7585ff12..5fdc2eadaf 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/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)));
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 790e058fe8..7bd8ffa54c 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/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;
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index 3541b132da..1163621815 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/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() {
diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h
index 81b62981ac..b786aa2b50 100644
--- a/editor/spatial_editor_gizmos.h
+++ b/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);
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index d199e53db5..31a80bc2db 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/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
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h
index 895a52aad8..0633ffa641 100644
--- a/scene/3d/baked_lightmap.h
+++ b/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
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 99bc78f5d2..32afcc7935 100644
--- a/scene/3d/gi_probe.cpp
+++ b/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);
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
index 7c58f862e4..7cb4b435c5 100644
--- a/scene/3d/gi_probe.h
+++ b/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;
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
deleted file mode 100644
index 412c53e36b..0000000000
--- a/scene/3d/voxel_light_baker.cpp
+++ /dev/null
@@ -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;
-}
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
new file mode 100644
index 0000000000..2aa2f79f43
--- /dev/null
+++ b/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;
+}
diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxelizer.h
index 7e78a19830..37de6b782e 100644
--- a/scene/3d/voxel_light_baker.h
+++ b/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
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 469665676c..831bb77c0f 100644
--- a/scene/main/viewport.h
+++ b/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 {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index de7600d417..957e41ce9b 100644
--- a/scene/register_scene_types.cpp
+++ b/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>();
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 6765a15208..571415a045 100644
--- a/scene/resources/mesh.cpp
+++ b/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);
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 849fb087ba..9779f9c9ca 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/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) {
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 02d44c5c5d..85e2b8aadc 100644
--- a/servers/visual/rasterizer.h
+++ b/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 {
diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
index 0da86f23a7..b6228bf165 100644
--- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
+++ b/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;
{
diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
index 1e32594118..3d3298d0c1 100644
--- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
+++ b/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);
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
index e44955d666..3fda64c536 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
@@ -267,7 +267,7 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) {
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
@@ -500,7 +500,7 @@ void RasterizerSceneForwardRD::MaterialData::update_parameters(const Map<StringN
}
}
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), 2);
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), 3);
}
RasterizerSceneForwardRD::MaterialData::~MaterialData() {
if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
@@ -576,7 +576,12 @@ void RasterizerSceneForwardRD::RenderBufferDataForward::configure(RID p_render_t
color_fb = RD::get_singleton()->framebuffer_create(fb);
}
+ {
+ Vector<RID> fb;
+ fb.push_back(depth);
+ depth_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
{
Vector<RID> fb;
fb.push_back(color);
@@ -697,6 +702,39 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements,
id.flags |= omni_count << 3;
id.flags |= spot_count << 6;
id.flags |= decal_count << 9;
+
+ if (!e->instance->gi_probe_instances.empty()) {
+ uint32_t written = 0;
+ for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) {
+ RID probe = e->instance->gi_probe_instances[j];
+ int slot = gi_probe_instance_get_slot(probe);
+ if (slot < 0) {
+ continue; //unallocated, dont render
+ }
+
+ if (render_pass != gi_probe_instance_get_render_pass(probe)) {
+ continue; //not rendered in this frame
+ }
+
+ uint32_t index = gi_probe_instance_get_render_index(probe);
+
+ if (written == 0) {
+ id.gi_offset = index;
+ written = 1;
+ } else {
+ id.gi_offset = index << 16;
+ written = 2;
+ break;
+ }
+ }
+ if (written == 0) {
+ id.gi_offset = 0xFFFFFFFF;
+ } else if (written == 1) {
+ id.gi_offset |= 0xFFFF0000;
+ }
+ } else {
+ id.gi_offset = 0xFFFFFFFF;
+ }
}
RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true);
@@ -711,7 +749,8 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
//global scope bindings
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, 0);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_pass_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, 2);
MaterialData *prev_material = nullptr;
// ShaderData *prev_shader = nullptr;
@@ -752,7 +791,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
case VS::INSTANCE_MESH: {
primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index);
if (e->instance->skeleton.is_valid()) {
- xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, 1);
+ xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, 2);
}
} break;
case VS::INSTANCE_MULTIMESH: {
@@ -760,7 +799,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
ERR_CONTINUE(!mesh.is_valid()); //should be a bug
primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index);
- xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, 1);
+ xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, 2);
} break;
case VS::INSTANCE_IMMEDIATE: {
@@ -863,14 +902,14 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
}
if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, 2);
prev_xforms_uniform_set = xforms_uniform_set;
}
if (material != prev_material) {
//update uniform set
if (material->uniform_set.is_valid()) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, 2);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, 3);
}
prev_material = material;
@@ -1449,6 +1488,59 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r
}
}
+void RasterizerSceneForwardRD::_setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform) {
+
+ int index = 0;
+
+ for (int i = 0; i < p_gi_probe_probe_cull_count; i++) {
+
+ RID rpi = p_gi_probe_probe_cull_result[i];
+
+ if (index >= (int)scene_state.max_gi_probes) {
+ continue;
+ }
+
+ int slot = gi_probe_instance_get_slot(rpi);
+ if (slot < 0) {
+ continue; //not usable
+ }
+
+ RID base_probe = gi_probe_instance_get_base_probe(rpi);
+
+ GIProbeData &gi_probe_ubo = scene_state.gi_probes[index];
+
+ Transform to_cell = gi_probe_instance_get_transform_to_cell(rpi) * p_camera_transform;
+
+ store_transform(to_cell, gi_probe_ubo.xform);
+
+ Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+
+ gi_probe_ubo.bounds[0] = bounds.x;
+ gi_probe_ubo.bounds[1] = bounds.y;
+ gi_probe_ubo.bounds[2] = bounds.z;
+
+ gi_probe_ubo.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
+ gi_probe_ubo.bias = storage->gi_probe_get_bias(base_probe);
+ gi_probe_ubo.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
+ gi_probe_ubo.blend_ambient = !storage->gi_probe_is_interior(base_probe);
+ gi_probe_ubo.texture_slot = gi_probe_instance_get_slot(rpi);
+ gi_probe_ubo.anisotropy_strength = storage->gi_probe_get_anisotropy_strength(base_probe);
+
+ if (gi_probe_is_anisotropic()) {
+ gi_probe_ubo.texture_slot *= 3;
+ }
+
+ gi_probe_instance_set_render_index(rpi, index);
+ gi_probe_instance_set_render_pass(rpi, render_pass);
+
+ index++;
+ }
+
+ if (index) {
+ RD::get_singleton()->buffer_update(scene_state.gi_probe_buffer, 0, index * sizeof(GIProbeData), scene_state.gi_probes, true);
+ }
+}
+
void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows) {
uint32_t light_count = 0;
@@ -1632,7 +1724,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
}
}
-void RasterizerSceneForwardRD::_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) {
+void RasterizerSceneForwardRD::_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) {
RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)p_buffer_data;
@@ -1664,6 +1756,8 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
RENDER_TIMESTAMP("Setup 3D Scene");
+ _update_render_base_uniform_set();
+
bool using_shadows = true;
if (p_reflection_probe.is_valid()) {
@@ -1687,6 +1781,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
RID render_target;
Size2 screen_pixel_size;
RID opaque_framebuffer;
+ RID depth_framebuffer;
RID alpha_framebuffer;
if (render_buffer) {
@@ -1695,6 +1790,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
render_target = render_buffer->render_target;
opaque_framebuffer = render_buffer->color_fb;
+ depth_framebuffer = render_buffer->depth_fb;
alpha_framebuffer = opaque_framebuffer;
} else if (p_reflection_probe.is_valid()) {
@@ -1703,6 +1799,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
screen_pixel_size.height = 1.0 / resolution;
opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass);
+ depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_reflection_probe, p_reflection_probe_pass);
alpha_framebuffer = opaque_framebuffer;
if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
@@ -1715,337 +1812,11 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
_setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
+ _setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform);
_setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas);
-#if 0
- for (int i = 0; i < p_light_cull_count; i++) {
-
- ERR_BREAK(i >= RenderList::MAX_LIGHTS);
-
- LightInstance *li = light_instance_owner.getornull(p_light_cull_result[i]);
- if (li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] > CMP_EPSILON) {
- state.used_contact_shadows = true;
- }
- }
-#endif
-#if 0
- // Do depth prepass if it's explicitly enabled
- bool use_depth_prepass = storage->config.use_depth_prepass;
-
- // If contact shadows are used then we need to do depth prepass even if it's otherwise disabled
- use_depth_prepass = use_depth_prepass || state.used_contact_shadows;
-
- // Never do depth prepass if effects are disabled or if we render overdraws
- use_depth_prepass = use_depth_prepass && storage->frame.current_rt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS];
- use_depth_prepass = use_depth_prepass && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
-
- if (use_depth_prepass) {
- //pre z pass
-
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- glDrawBuffers(0, NULL);
-
- glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
-
- glColorMask(0, 0, 0, 0);
- glClearDepth(1.0f);
- glClear(GL_DEPTH_BUFFER_BIT);
-
- render_list.clear();
- _fill_render_list(p_cull_result, p_cull_count, true, false);
- render_list.sort_by_key(false);
- state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, true);
- _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, 0, false, false, true, false, false);
- state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, false);
-
- glColorMask(1, 1, 1, 1);
-
- if (state.used_contact_shadows) {
-
- _prepare_depth_texture();
- _bind_depth_texture();
- }
-
- fb_cleared = true;
- render_pass++;
- state.used_depth_prepass = true;
- } else {
- state.used_depth_prepass = false;
- }
-
- _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_shadow_atlas);
- _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_reflection_atlas, env);
-
- bool use_mrt = false;
-#endif
-
render_list.clear();
_fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
-#if 0
- //
-
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
-
- //rendering to a probe cubemap side
- ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe);
- GLuint current_fbo;
-
- if (probe) {
-
- ReflectionAtlas *ref_atlas = reflection_atlas_owner.getornull(probe->atlas);
- ERR_FAIL_COND(!ref_atlas);
-
- int target_size = ref_atlas->size / ref_atlas->subdiv;
-
- int cubemap_index = reflection_cubemaps.size() - 1;
-
- for (int i = reflection_cubemaps.size() - 1; i >= 0; i--) {
- //find appropriate cubemap to render to
- if (reflection_cubemaps[i].size > target_size * 2)
- break;
-
- cubemap_index = i;
- }
-
- current_fbo = reflection_cubemaps[cubemap_index].fbo_id[p_reflection_probe_pass];
- use_mrt = false;
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false);
-
- glViewport(0, 0, reflection_cubemaps[cubemap_index].size, reflection_cubemaps[cubemap_index].size);
- glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
-
- } else {
-
- use_mrt = env && (state.used_sss || env->ssao_enabled || env->ssr_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); //only enable MRT rendering if any of these is enabled
- //effects disabled and transparency also prevent using MRTs
- use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT];
- use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS];
- use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
- use_mrt = use_mrt && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS);
-
- glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
-
- if (use_mrt) {
-
- current_fbo = storage->frame.current_rt->buffers.fbo;
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, true);
-
- Vector<GLenum> draw_buffers;
- draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
- draw_buffers.push_back(GL_COLOR_ATTACHMENT1);
- draw_buffers.push_back(GL_COLOR_ATTACHMENT2);
- if (state.used_sss) {
- draw_buffers.push_back(GL_COLOR_ATTACHMENT3);
- }
- glDrawBuffers(draw_buffers.size(), draw_buffers.ptr());
-
- Color black(0, 0, 0, 0);
- glClearBufferfv(GL_COLOR, 1, black.components); // specular
- glClearBufferfv(GL_COLOR, 2, black.components); // normal metal rough
- if (state.used_sss) {
- glClearBufferfv(GL_COLOR, 3, black.components); // normal metal rough
- }
-
- } else {
-
- if (storage->frame.current_rt->buffers.active) {
- current_fbo = storage->frame.current_rt->buffers.fbo;
- } else {
- current_fbo = storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo;
- }
-
- glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false);
-
- Vector<GLenum> draw_buffers;
- draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
- glDrawBuffers(draw_buffers.size(), draw_buffers.ptr());
- }
- }
-
- if (!fb_cleared) {
- glClearDepth(1.0f);
- glClear(GL_DEPTH_BUFFER_BIT);
- }
-
- Color clear_color(0, 0, 0, 0);
-
- RasterizerStorageGLES3::Sky *sky = NULL;
- Ref<CameraFeed> feed;
- GLuint env_radiance_tex = 0;
-
- if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
- clear_color = Color(0, 0, 0, 0);
- storage->frame.clear_request = false;
- } else if (!probe && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
- clear_color = Color(0, 0, 0, 0);
- storage->frame.clear_request = false;
-
- } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR) {
-
- if (storage->frame.clear_request) {
-
- clear_color = storage->frame.clear_request_color.to_linear();
- storage->frame.clear_request = false;
- }
-
- } else if (env->bg_mode == VS::ENV_BG_CANVAS) {
-
- clear_color = env->bg_color.to_linear();
- storage->frame.clear_request = false;
- } else if (env->bg_mode == VS::ENV_BG_COLOR) {
-
- clear_color = env->bg_color.to_linear();
- storage->frame.clear_request = false;
- } else if (env->bg_mode == VS::ENV_BG_SKY) {
-
- storage->frame.clear_request = false;
-
- } else if (env->bg_mode == VS::ENV_BG_COLOR_SKY) {
-
- clear_color = env->bg_color.to_linear();
- storage->frame.clear_request = false;
-
- } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) {
- feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id);
- storage->frame.clear_request = false;
- } else {
- storage->frame.clear_request = false;
- }
-
- if (!env || env->bg_mode != VS::ENV_BG_KEEP) {
- glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular
- }
-
- VS::EnvironmentBG bg_mode = (!env || (probe && env->bg_mode == VS::ENV_BG_CANVAS)) ? VS::ENV_BG_CLEAR_COLOR : env->bg_mode; //if no environment, or canvas while rendering a probe (invalid use case), use color.
-
- if (env) {
- switch (bg_mode) {
- case VS::ENV_BG_COLOR_SKY:
- case VS::ENV_BG_SKY:
-
- sky = storage->sky_owner.getornull(env->sky);
-
- if (sky) {
- env_radiance_tex = sky->radiance;
- }
- break;
- case VS::ENV_BG_CANVAS:
- //copy canvas to 3d buffer and convert it to linear
-
- glDisable(GL_BLEND);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true);
-
- storage->shaders.copy.bind();
-
- _copy_screen(true, true);
-
- //turn off everything used
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false);
-
- //restore
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- break;
- case VS::ENV_BG_CAMERA_FEED:
- if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) {
- // copy our camera feed to our background
-
- glDisable(GL_BLEND);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, true);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true);
-
- if (feed->get_datatype() == CameraFeed::FEED_RGB) {
- RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE);
-
- VS::get_singleton()->texture_bind(camera_RGBA, 0);
- } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) {
- RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE);
-
- VS::get_singleton()->texture_bind(camera_YCbCr, 0);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true);
-
- } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) {
- RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE);
- RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE);
-
- VS::get_singleton()->texture_bind(camera_Y, 0);
- VS::get_singleton()->texture_bind(camera_CbCr, 1);
-
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, true);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true);
- };
-
- storage->shaders.copy.bind();
- storage->shaders.copy.set_uniform(CopyShaderGLES3::DISPLAY_TRANSFORM, feed->get_transform());
-
- _copy_screen(true, true);
-
- //turn off everything used
- storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, false);
-
- //restore
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- } else {
- // don't have a feed, just show greenscreen :)
- clear_color = Color(0.0, 1.0, 0.0, 1.0);
- }
- break;
- default: {
- }
- }
- }
-
- if (probe && probe->probe_ptr->interior) {
- env_radiance_tex = 0; //for rendering probe interiors, radiance must not be used.
- }
-
- state.texscreen_copied = false;
-
- glBlendEquation(GL_FUNC_ADD);
-
- if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- } else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_BLEND);
- }
-#endif
RID radiance_cubemap;
bool draw_sky = false;
@@ -2097,27 +1868,50 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
RENDER_TIMESTAMP("Render Opaque Pass");
- _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, p_reflection_atlas);
+ _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, p_reflection_atlas);
render_list.sort_by_key(false);
_fill_instances(render_list.elements, render_list.element_count);
bool can_continue = true; //unless the middle buffers are needed
+ bool debug_giprobes = debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING;
bool using_separate_specular = false;
+ bool depth_pre_pass = depth_framebuffer.is_valid();
+ if (depth_pre_pass) { //depth pre pass
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, PASS_MODE_DEPTH, render_buffer == nullptr);
+ RD::get_singleton()->draw_list_end();
+ }
+
{
+ bool will_continue = (can_continue || draw_sky || debug_giprobes);
//regular forward for now
Vector<Color> c;
c.push_back(clear_color.to_linear());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP_COLOR : RD::INITIAL_ACTION_CLEAR, (can_continue || draw_sky) ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH, c);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, render_buffer == nullptr);
RD::get_singleton()->draw_list_end();
}
+ if (debug_giprobes) {
+ //debug giprobes
+ bool will_continue = (can_continue || draw_sky);
+ CameraMatrix dc;
+ dc.set_depth_correction(true);
+ CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse());
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
+ for (int i = 0; i < p_gi_probe_cull_count; i++) {
+ _debug_giprobe(p_gi_probe_cull_result[i], draw_list, opaque_framebuffer, cm, debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, 1.0);
+ }
+ RD::get_singleton()->draw_list_end();
+ }
+
if (draw_sky) {
RENDER_TIMESTAMP("Render Sky");
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
_draw_sky(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), p_environment, p_cam_projection, p_cam_transform, 1.0);
RD::get_singleton()->draw_list_end();
@@ -2128,93 +1922,6 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
}
}
- //_render_list
-#if 0
- if (state.directional_light_count == 0) {
- directional_light = NULL;
- _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, false, shadow_atlas != NULL);
- } else {
- for (int i = 0; i < state.directional_light_count; i++) {
- directional_light = directional_lights[i];
- if (i > 0) {
- glEnable(GL_BLEND);
- }
- _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0);
- _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, i > 0, shadow_atlas != NULL);
- }
- }
-
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false);
-
- if (use_mrt) {
- GLenum gldb = GL_COLOR_ATTACHMENT0;
- glDrawBuffers(1, &gldb);
- }
-
- if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || (!storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW))) {
-
- /*
- if (use_mrt) {
- glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); //switch to alpha fbo for sky, only diffuse/ambient matters
- */
-
- if (sky && sky->panorama.is_valid())
- _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation);
- }
-
- //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true);
- //glColorMask(1,1,1,1);
-
- //state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false);
-
- if (use_mrt) {
-
- _render_mrts(env, p_cam_projection);
- } else {
- // Here we have to do the blits/resolves that otherwise are done in the MRT rendering, in particular
- // - prepare screen texture for any geometry that uses a shader with screen texture
- // - prepare depth texture for any geometry that uses a shader with depth texture
-
- bool framebuffer_dirty = false;
-
- if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_screen_texture) {
- glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- glReadBuffer(GL_COLOR_ATTACHMENT0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo);
- glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
- _blur_effect_buffer();
- framebuffer_dirty = true;
- }
-
- if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_depth_texture) {
- _prepare_depth_texture();
- framebuffer_dirty = true;
- }
-
- if (framebuffer_dirty) {
- // Restore framebuffer
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo);
- glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
- }
- }
-
- if (storage->frame.current_rt && state.used_depth_texture && storage->frame.current_rt->buffers.active) {
- _bind_depth_texture();
- }
-
- if (storage->frame.current_rt && state.used_screen_texture && storage->frame.current_rt->buffers.active) {
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color);
- }
-
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
-#endif
-
RENDER_TIMESTAMP("Render Transparent Pass");
render_list.sort_by_reverse_depth_and_priority(true);
@@ -2222,7 +1929,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
_fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count);
{
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP_COLOR_AND_DEPTH, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr);
RD::get_singleton()->draw_list_end();
}
@@ -2266,7 +1973,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
storage->render_target_disable_clear_request(render_buffer->render_target);
- if (false) {
+ if (render_buffer && debug_draw == VS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
if (p_shadow_atlas.is_valid()) {
RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas);
Size2 rtsize = storage->render_target_get_size(render_buffer->render_target);
@@ -2275,7 +1982,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
}
}
- if (false) {
+ if (render_buffer && debug_draw == VS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) {
if (directional_shadow_get_texture().is_valid()) {
RID shadow_atlas_texture = directional_shadow_get_texture();
Size2 rtsize = storage->render_target_get_size(render_buffer->render_target);
@@ -2345,6 +2052,8 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
RENDER_TIMESTAMP("Setup Rendering Shadow");
+ _update_render_base_uniform_set();
+
render_pass++;
scene_state.ubo.shadow_z_offset = p_bias;
@@ -2360,7 +2069,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
_fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
- _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID());
+ _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID());
RENDER_TIMESTAMP("Render Shadow");
@@ -2370,16 +2079,142 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
{
//regular forward for now
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true);
RD::get_singleton()->draw_list_end();
}
}
-void RasterizerSceneForwardRD::_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) {
+void RasterizerSceneForwardRD::_update_render_base_uniform_set() {
+
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || gi_probe_slots_are_dirty()) {
+
+ if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.uniform_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.light_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.reflection_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.gi_probe_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ int slot_count = gi_probe_get_slots().size();
+ if (gi_probe_is_anisotropic()) {
+ u.ids.resize(slot_count * 3);
+ } else {
+ u.ids.resize(slot_count);
+ }
+ for (int i = 0; i < slot_count; i++) {
+
+ RID probe = gi_probe_get_slots()[i];
+
+ if (gi_probe_is_anisotropic()) {
+ if (probe.is_null()) {
+ RID empty_tex = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ u.ids.write[i * 3 + 0] = empty_tex;
+ u.ids.write[i * 3 + 1] = empty_tex;
+ u.ids.write[i * 3 + 2] = empty_tex;
+ } else {
+ u.ids.write[i * 3 + 0] = gi_probe_instance_get_texture(probe);
+ u.ids.write[i * 3 + 1] = gi_probe_instance_get_aniso_texture(probe, 0);
+ u.ids.write[i * 3 + 2] = gi_probe_instance_get_aniso_texture(probe, 1);
+ }
+ } else {
+ if (probe.is_null()) {
+ u.ids.write[i] = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ } else {
+ u.ids.write[i] = gi_probe_instance_get_texture(probe);
+ }
+ }
+ }
+
+ uniforms.push_back(u);
+ }
+
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 0);
+
+ gi_probe_slots_make_not_dirty();
+ }
+}
+
+void RasterizerSceneForwardRD::_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) {
- if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
- RD::get_singleton()->free(render_base_uniform_set);
+ if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) {
+ RD::get_singleton()->free(render_pass_uniform_set);
}
//default render buffer and scene state uniform set
@@ -2387,7 +2222,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
- u.binding = 1;
+ u.binding = 0;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_depth_buffer.is_valid() ? p_depth_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
u.ids.push_back(texture);
@@ -2395,7 +2230,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
}
{
RD::Uniform u;
- u.binding = 2;
+ u.binding = 1;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_color_buffer.is_valid() ? p_color_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
@@ -2403,7 +2238,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
}
{
RD::Uniform u;
- u.binding = 3;
+ u.binding = 2;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_normal_buffer.is_valid() ? p_normal_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
u.ids.push_back(texture);
@@ -2412,7 +2247,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 3;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_roughness_limit_buffer.is_valid() ? p_roughness_limit_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
@@ -2421,7 +2256,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 4;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = p_radiance_cubemap.is_valid() ? p_radiance_cubemap : storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
u.ids.push_back(texture);
@@ -2429,62 +2264,10 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
}
{
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.resize(12);
- RID *ids_ptr = u.ids.ptrw();
- ids_ptr[0] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 7;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(shadow_sampler);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 8;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.uniform_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 9;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(scene_state.instance_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 10;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.reflection_buffer);
- uniforms.push_back(u);
- }
-
- {
RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID();
RD::Uniform u;
- u.binding = 11;
+ u.binding = 5;
u.type = RD::UNIFORM_TYPE_TEXTURE;
if (ref_texture.is_valid()) {
u.ids.push_back(ref_texture);
@@ -2496,15 +2279,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 12;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.light_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 13;
+ u.binding = 6;
u.type = RD::UNIFORM_TYPE_TEXTURE;
if (p_shadow_atlas.is_valid()) {
u.ids.push_back(shadow_atlas_get_texture(p_shadow_atlas));
@@ -2516,15 +2291,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
{
RD::Uniform u;
- u.binding = 14;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.directional_light_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 15;
+ u.binding = 7;
u.type = RD::UNIFORM_TYPE_TEXTURE;
if (directional_shadow_get_texture().is_valid()) {
u.ids.push_back(directional_shadow_get_texture());
@@ -2534,7 +2301,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
uniforms.push_back(u);
}
- render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 0);
+ render_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 1);
}
RasterizerSceneForwardRD *RasterizerSceneForwardRD::singleton = NULL;
@@ -2543,6 +2310,10 @@ void RasterizerSceneForwardRD::set_time(double p_time) {
time = p_time;
}
+void RasterizerSceneForwardRD::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {
+ debug_draw = p_debug_draw;
+}
+
RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storage) :
RasterizerSceneRD(p_storage) {
singleton = this;
@@ -2577,7 +2348,6 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
{ //lights
scene_state.max_lights = MIN(65536, uniform_max_size) / sizeof(LightData);
uint32_t light_buffer_size = scene_state.max_lights * sizeof(LightData);
- print_line("ID: " + itos(sizeof(InstanceData)));
scene_state.lights = memnew_arr(LightData, scene_state.max_lights);
scene_state.light_buffer = RD::get_singleton()->uniform_buffer_create(light_buffer_size);
defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n";
@@ -2589,6 +2359,32 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(scene_state.max_directional_lights) + "\n";
}
+ { //giprobes
+ int slot_count = gi_probe_get_slots().size();
+ if (gi_probe_is_anisotropic()) {
+ slot_count *= 3;
+ defines += "\n#define GI_PROBE_USE_ANISOTROPY\n";
+ }
+ if (gi_probe_is_high_quality()) {
+ defines += "\n#define GI_PROBE_HIGH_QUALITY\n";
+ }
+ defines += "\n#define MAX_GI_PROBE_TEXTURES " + itos(slot_count) + "\n";
+
+ uint32_t giprobe_buffer_size;
+ if (uniform_max_size < 65536) {
+ //Yes, you guessed right, ARM again
+ giprobe_buffer_size = uniform_max_size;
+ } else {
+ giprobe_buffer_size = 65536;
+ }
+
+ giprobe_buffer_size = MIN(sizeof(GIProbeData) * gi_probe_get_slots().size(), giprobe_buffer_size);
+ scene_state.max_gi_probes = giprobe_buffer_size / sizeof(GIProbeData);
+ scene_state.gi_probes = memnew_arr(GIProbeData, scene_state.max_gi_probes);
+ scene_state.gi_probe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * scene_state.max_gi_probes);
+ defines += "\n#define MAX_GI_PROBES " + itos(scene_state.max_gi_probes) + "\n";
+ }
+
Vector<String> shader_versions;
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
@@ -2733,7 +2529,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
- actions.texture_layout_set = 2;
+ actions.texture_layout_set = 3;
actions.base_uniform_string = "material.";
actions.base_varying_index = 10;
@@ -2777,7 +2573,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
u.binding = 0;
uniforms.push_back(u);
- default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 1);
+ default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 2);
}
{
@@ -2792,8 +2588,8 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
RasterizerSceneForwardRD::~RasterizerSceneForwardRD() {
//clear base uniform set if still valid
- if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
- RD::get_singleton()->free(render_base_uniform_set);
+ if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) {
+ RD::get_singleton()->free(render_pass_uniform_set);
}
{
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
index 73d48c5fe8..f62fe11de7 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
+++ b/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);
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
index 888568e21a..e292f9c69b 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/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);
}
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
index 97e1d08d90..cb32880e13 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
+++ b/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);
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
index cd2f48b328..28ecda081d 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/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)) {
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
index 6cdc21c2f0..289a2ae5a8 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
+++ b/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 */
diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub
index 660523e29f..bce700f7b0 100644
--- a/servers/visual/rasterizer_rd/shaders/SCsub
+++ b/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');
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe.glsl b/servers/visual/rasterizer_rd/shaders/giprobe.glsl
new file mode 100644
index 0000000000..35b8d6ba6b
--- /dev/null
+++ b/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
+}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
new file mode 100644
index 0000000000..deaeb771b9
--- /dev/null
+++ b/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;
+}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl
deleted file mode 100644
index cec25f86f9..0000000000
--- a/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl
+++ /dev/null
@@ -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
-
-}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_write.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_write.glsl
new file mode 100644
index 0000000000..01d33c28de
--- /dev/null
+++ b/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
+}
diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
index 711da3be9b..95e64f8778 100644
--- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
+++ b/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
diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
index 81cf47b192..c59d5ed756 100644
--- a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
+++ b/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
diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h
index d0afb3f13b..f5a212b076 100644
--- a/servers/visual/rendering_device.h
+++ b/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;
/***************/
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index 510296f11c..38f5c1ec58 100644
--- a/servers/visual/visual_server_raster.h
+++ b/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 */
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index f240f91b12..f7b118bfe5 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -336,23 +336,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
if (instance->base_type != VS::INSTANCE_NONE) {
//free anything related to that base
- if (instance->base_type == VS::INSTANCE_GI_PROBE) {
- //if gi probe is baking, wait until done baking, else race condition may happen when removing it
- //from octree
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
-
- //make sure probes are done baking
- while (!probe_bake_list.empty()) {
- OS::get_singleton()->delay_usec(1);
- }
- //make sure this one is done baking
-
- while (gi_probe->dynamic.updating_stage == GI_UPDATE_STAGE_LIGHTING) {
- //wait until bake is done if it's baking
- OS::get_singleton()->delay_usec(1);
- }
- }
-
if (scenario && instance->octree_id) {
scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
instance->octree_id = 0;
@@ -392,9 +375,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
if (gi_probe->update_element.in_list()) {
gi_probe_update_list.remove(&gi_probe->update_element);
}
- if (gi_probe->dynamic.probe_data.is_valid()) {
- VSG::storage->free(gi_probe->dynamic.probe_data);
- }
if (instance->lightmap_capture) {
Instance *capture = (Instance *)instance->lightmap_capture;
@@ -476,7 +456,7 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
gi_probe_update_list.add(&gi_probe->update_element);
}
- gi_probe->probe_instance = VSG::scene_render->gi_probe_instance_create();
+ gi_probe->probe_instance = VSG::scene_render->gi_probe_instance_create(p_base);
} break;
default: {
@@ -891,6 +871,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
reflection_probe->reflection_dirty = true;
}
+ if (p_instance->base_type == VS::INSTANCE_GI_PROBE) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
+
+ VSG::scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform);
+ }
+
if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
VSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
@@ -1849,6 +1836,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
light_cull_count = 0;
reflection_probe_cull_count = 0;
+ gi_probe_cull_count = 0;
//light_samplers_culled=0;
@@ -1925,6 +1913,11 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
gi_probe_update_list.add(&gi_probe->update_element);
}
+ if (gi_probe_cull_count < MAX_GI_PROBES_CULLED) {
+ gi_probe_instance_cull_result[gi_probe_cull_count] = gi_probe->probe_instance;
+ gi_probe_cull_count++;
+ }
+
} else if (((1 << ins->base_type) & VS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
keep = true;
@@ -2173,7 +2166,7 @@ void VisualServerScene::_render_scene(RID p_render_buffers, const Transform p_ca
/* PROCESS GEOMETRY AND DRAW SCENE */
RENDER_TIMESTAMP("Render Scene ");
- VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
+ VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
}
void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
@@ -2188,7 +2181,7 @@ void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario,
else
environment = scenario->fallback_environment;
RENDER_TIMESTAMP("Render Empty Scene ");
- VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
+ VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
#endif
}
@@ -2265,898 +2258,6 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
return false;
}
-void VisualServerScene::_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) {
-
- if ((uint32_t)p_level == p_header->cell_subdiv - 1) {
-
- Vector3 emission;
- emission.x = (p_cell[p_idx].emission >> 24) / 255.0;
- emission.y = ((p_cell[p_idx].emission >> 16) & 0xFF) / 255.0;
- emission.z = ((p_cell[p_idx].emission >> 8) & 0xFF) / 255.0;
- float l = (p_cell[p_idx].emission & 0xFF) / 255.0;
- l *= 8.0;
-
- emission *= l;
-
- p_local_data[p_idx].energy[0] = uint16_t(emission.x * 1024); //go from 0 to 1024 for light
- p_local_data[p_idx].energy[1] = uint16_t(emission.y * 1024); //go from 0 to 1024 for light
- p_local_data[p_idx].energy[2] = uint16_t(emission.z * 1024); //go from 0 to 1024 for light
- } else {
-
- p_local_data[p_idx].energy[0] = 0;
- p_local_data[p_idx].energy[1] = 0;
- p_local_data[p_idx].energy[2] = 0;
-
- int half = (1 << (p_header->cell_subdiv - 1)) >> (p_level + 1);
-
- for (int i = 0; i < 8; i++) {
-
- uint32_t child = p_cell[p_idx].children[i];
-
- if (child == 0xFFFFFFFF)
- continue;
-
- int x = p_x;
- int y = p_y;
- int z = p_z;
-
- if (i & 1)
- x += half;
- if (i & 2)
- y += half;
- if (i & 4)
- z += half;
-
- _gi_probe_fill_local_data(child, p_level + 1, x, y, z, p_cell, p_header, p_local_data, prev_cell);
- }
- }
-
- //position for each part of the mipmaped texture
- p_local_data[p_idx].pos[0] = p_x >> (p_header->cell_subdiv - p_level - 1);
- p_local_data[p_idx].pos[1] = p_y >> (p_header->cell_subdiv - p_level - 1);
- p_local_data[p_idx].pos[2] = p_z >> (p_header->cell_subdiv - p_level - 1);
-
- prev_cell[p_level].push_back(p_idx);
-}
-
-void VisualServerScene::_gi_probe_bake_threads(void *self) {
-
- VisualServerScene *vss = (VisualServerScene *)self;
- vss->_gi_probe_bake_thread();
-}
-
-void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
-
- InstanceGIProbeData *probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
-
- if (probe->dynamic.probe_data.is_valid()) {
- VSG::storage->free(probe->dynamic.probe_data);
- probe->dynamic.probe_data = RID();
- }
-
- probe->dynamic.light_data = VSG::storage->gi_probe_get_dynamic_data(p_instance->base);
-
- if (probe->dynamic.light_data.size() == 0)
- return;
- //using dynamic data
- PoolVector<int>::Read r = probe->dynamic.light_data.read();
-
- const GIProbeDataHeader *header = (GIProbeDataHeader *)r.ptr();
-
- probe->dynamic.local_data.resize(header->cell_count);
-
- int cell_count = probe->dynamic.local_data.size();
- PoolVector<InstanceGIProbeData::LocalData>::Write ldw = probe->dynamic.local_data.write();
- const GIProbeDataCell *cells = (GIProbeDataCell *)&r[16];
-
- probe->dynamic.level_cell_lists.resize(header->cell_subdiv);
-
- _gi_probe_fill_local_data(0, 0, 0, 0, 0, cells, header, ldw.ptr(), probe->dynamic.level_cell_lists.ptrw());
-
- bool compress = VSG::storage->gi_probe_is_compressed(p_instance->base);
-
- probe->dynamic.compression = compress ? VSG::storage->gi_probe_get_dynamic_data_get_preferred_compression() : RasterizerStorage::GI_PROBE_UNCOMPRESSED;
-
- probe->dynamic.probe_data = VSG::storage->gi_probe_dynamic_data_create(header->width, header->height, header->depth, probe->dynamic.compression);
-
- probe->dynamic.bake_dynamic_range = VSG::storage->gi_probe_get_dynamic_range(p_instance->base);
-
- probe->dynamic.mipmaps_3d.clear();
- probe->dynamic.propagate = VSG::storage->gi_probe_get_propagation(p_instance->base);
-
- probe->dynamic.grid_size[0] = header->width;
- probe->dynamic.grid_size[1] = header->height;
- probe->dynamic.grid_size[2] = header->depth;
-
- int size_limit = 1;
- int size_divisor = 1;
-
- if (probe->dynamic.compression == RasterizerStorage::GI_PROBE_S3TC) {
- size_limit = 4;
- size_divisor = 4;
- }
- for (int i = 0; i < (int)header->cell_subdiv; i++) {
-
- int x = header->width >> i;
- int y = header->height >> i;
- int z = header->depth >> i;
-
- //create and clear mipmap
- PoolVector<uint8_t> mipmap;
- int size = x * y * z * 4;
- size /= size_divisor;
- mipmap.resize(size);
- PoolVector<uint8_t>::Write w = mipmap.write();
- zeromem(w.ptr(), size);
- w.release();
-
- probe->dynamic.mipmaps_3d.push_back(mipmap);
-
- if (x <= size_limit || y <= size_limit || z <= size_limit)
- break;
- }
-
- probe->dynamic.updating_stage = GI_UPDATE_STAGE_CHECK;
- probe->invalid = false;
- probe->dynamic.enabled = true;
-
- Transform cell_to_xform = VSG::storage->gi_probe_get_to_cell_xform(p_instance->base);
- AABB bounds = VSG::storage->gi_probe_get_bounds(p_instance->base);
- float cell_size = VSG::storage->gi_probe_get_cell_size(p_instance->base);
-
- probe->dynamic.light_to_cell_xform = cell_to_xform * p_instance->transform.affine_inverse();
-
- VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance, p_instance->base, probe->dynamic.probe_data);
- VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance, probe->dynamic.light_to_cell_xform);
-
- VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance, bounds.size / cell_size);
-
- probe->base_version = VSG::storage->gi_probe_get_version(p_instance->base);
-
- //if compression is S3TC, fill it up
- if (probe->dynamic.compression == RasterizerStorage::GI_PROBE_S3TC) {
-
- //create all blocks
- Vector<Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> > comp_blocks;
- int mipmap_count = probe->dynamic.mipmaps_3d.size();
- comp_blocks.resize(mipmap_count);
-
- for (int i = 0; i < cell_count; i++) {
-
- const GIProbeDataCell &c = cells[i];
- const InstanceGIProbeData::LocalData &ld = ldw[i];
- int level = c.level_alpha >> 16;
- int mipmap = header->cell_subdiv - level - 1;
- if (mipmap >= mipmap_count)
- continue; //uninteresting
-
- int blockx = (ld.pos[0] >> 2);
- int blocky = (ld.pos[1] >> 2);
- int blockz = (ld.pos[2]); //compression is x/y only
-
- int blockw = (header->width >> mipmap) >> 2;
- int blockh = (header->height >> mipmap) >> 2;
-
- //print_line("cell "+itos(i)+" level "+itos(level)+"mipmap: "+itos(mipmap)+" pos: "+Vector3(blockx,blocky,blockz)+" size "+Vector2(blockw,blockh));
-
- uint32_t key = blockz * blockw * blockh + blocky * blockw + blockx;
-
- Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> &cmap = comp_blocks.write[mipmap];
-
- if (!cmap.has(key)) {
-
- InstanceGIProbeData::CompBlockS3TC k;
- k.offset = key; //use offset as counter first
- k.source_count = 0;
- cmap[key] = k;
- }
-
- InstanceGIProbeData::CompBlockS3TC &k = cmap[key];
- ERR_CONTINUE(k.source_count == 16);
- k.sources[k.source_count++] = i;
- }
-
- //fix the blocks, precomputing what is needed
- probe->dynamic.mipmaps_s3tc.resize(mipmap_count);
-
- for (int i = 0; i < mipmap_count; i++) {
- //print_line("S3TC level: " + itos(i) + " blocks: " + itos(comp_blocks[i].size()));
- probe->dynamic.mipmaps_s3tc.write[i].resize(comp_blocks[i].size());
- PoolVector<InstanceGIProbeData::CompBlockS3TC>::Write w = probe->dynamic.mipmaps_s3tc.write[i].write();
- int block_idx = 0;
-
- for (Map<uint32_t, InstanceGIProbeData::CompBlockS3TC>::Element *E = comp_blocks[i].front(); E; E = E->next()) {
-
- InstanceGIProbeData::CompBlockS3TC k = E->get();
-
- //PRECOMPUTE ALPHA
- int max_alpha = -100000;
- int min_alpha = k.source_count == 16 ? 100000 : 0; //if the block is not completely full, minimum is always 0, (and those blocks will map to 1, which will be zero)
-
- uint8_t alpha_block[4][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
-
- for (uint32_t j = 0; j < k.source_count; j++) {
-
- int alpha = (cells[k.sources[j]].level_alpha >> 8) & 0xFF;
- if (alpha < min_alpha)
- min_alpha = alpha;
- if (alpha > max_alpha)
- max_alpha = alpha;
- //fill up alpha block
- alpha_block[ldw[k.sources[j]].pos[0] % 4][ldw[k.sources[j]].pos[1] % 4] = alpha;
- }
-
- //use the first mode (8 adjustable levels)
- k.alpha[0] = max_alpha;
- k.alpha[1] = min_alpha;
-
- uint64_t alpha_bits = 0;
-
- if (max_alpha != min_alpha) {
-
- int idx = 0;
-
- for (int y = 0; y < 4; y++) {
- for (int x = 0; x < 4; x++) {
-
- //subtract minimum
- uint32_t a = uint32_t(alpha_block[x][y]) - min_alpha;
- //convert range to 3 bits
- a = int((a * 7.0 / (max_alpha - min_alpha)) + 0.5);
- a = MIN(a, 7); //just to be sure
- a = 7 - a; //because range is inverted in this mode
- if (a == 0) {
- //do none, remain
- } else if (a == 7) {
- a = 1;
- } else {
- a = a + 1;
- }
-
- alpha_bits |= uint64_t(a) << (idx * 3);
- idx++;
- }
- }
- }
-
- k.alpha[2] = (alpha_bits >> 0) & 0xFF;
- k.alpha[3] = (alpha_bits >> 8) & 0xFF;
- k.alpha[4] = (alpha_bits >> 16) & 0xFF;
- k.alpha[5] = (alpha_bits >> 24) & 0xFF;
- k.alpha[6] = (alpha_bits >> 32) & 0xFF;
- k.alpha[7] = (alpha_bits >> 40) & 0xFF;
-
- w[block_idx++] = k;
- }
- }
- }
-}
-
-void VisualServerScene::_gi_probe_bake_thread() {
-
- while (true) {
-
- probe_bake_sem->wait();
- if (probe_bake_thread_exit) {
- break;
- }
-
- Instance *to_bake = NULL;
-
- probe_bake_mutex->lock();
-
- if (!probe_bake_list.empty()) {
- to_bake = probe_bake_list.front()->get();
- probe_bake_list.pop_front();
- }
- probe_bake_mutex->unlock();
-
- if (!to_bake)
- continue;
-
- _bake_gi_probe(to_bake);
- }
-}
-
-uint32_t VisualServerScene::_gi_bake_find_cell(const GIProbeDataCell *cells, int x, int y, int z, int p_cell_subdiv) {
-
- uint32_t cell = 0;
-
- int ofs_x = 0;
- int ofs_y = 0;
- int ofs_z = 0;
- int size = 1 << (p_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 < p_cell_subdiv - 1; i++) {
-
- const GIProbeDataCell *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 == 0xFFFFFFFF)
- return 0xFFFFFFFF;
-
- half >>= 1;
- }
-
- return cell;
-}
-
-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);
-}
-
-void VisualServerScene::_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) {
-
- int light_r = int(light_cache.color.r * light_cache.energy * 1024.0) * p_sign;
- int light_g = int(light_cache.color.g * light_cache.energy * 1024.0) * p_sign;
- int light_b = int(light_cache.color.b * light_cache.energy * 1024.0) * p_sign;
-
- float limits[3] = { float(header->width), float(header->height), float(header->depth) };
- Plane clip[3];
- int clip_planes = 0;
-
- switch (light_cache.type) {
-
- case VS::LIGHT_DIRECTIONAL: {
-
- float max_len = Vector3(limits[0], limits[1], limits[2]).length() * 1.1;
-
- Vector3 light_axis = -light_cache.transform.basis.get_axis(2).normalized();
-
- 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 = limits[i] + 1;
- } else {
- clip[clip_planes].d -= 1.0;
- }
-
- clip_planes++;
- }
-
- float distance_adv = _get_normal_advance(light_axis);
-
- int success_count = 0;
-
- // uint64_t us = OS::get_singleton()->get_ticks_usec();
-
- for (int i = 0; i < p_leaf_count; i++) {
-
- uint32_t idx = leaves[i];
-
- const GIProbeDataCell *cell = &cells[idx];
- InstanceGIProbeData::LocalData *light = &local_data[idx];
-
- Vector3 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5);
- to += -light_axis.sign() * 0.47; //make it more likely to receive a ray
-
- Vector3 norm(
- (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 0) & 0xFF) / 255.0) * 2.0 - 1.0);
-
- float att = norm.dot(-light_axis);
- if (att < 0.001) {
- //not lighting towards this
- continue;
- }
-
- 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 = _gi_bake_find_cell(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z)), header->cell_subdiv);
- if (result != 0xFFFFFFFF) {
- break;
- }
-
- from += light_axis * distance_adv;
- distance -= distance_adv;
- }
-
- if (result == idx) {
- //cell hit itself! hooray!
- light->energy[0] += int32_t(light_r * att * ((cell->albedo >> 16) & 0xFF) / 255.0);
- light->energy[1] += int32_t(light_g * att * ((cell->albedo >> 8) & 0xFF) / 255.0);
- light->energy[2] += int32_t(light_b * att * ((cell->albedo) & 0xFF) / 255.0);
- success_count++;
- }
- }
-
- // print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
- // print_line("valid cells: " + itos(success_count));
-
- } break;
- case VS::LIGHT_OMNI:
- case VS::LIGHT_SPOT: {
-
- // uint64_t us = OS::get_singleton()->get_ticks_usec();
-
- Vector3 light_pos = light_cache.transform.origin;
- Vector3 spot_axis = -light_cache.transform.basis.get_axis(2).normalized();
-
- float local_radius = light_cache.radius * light_cache.transform.basis.get_axis(2).length();
-
- for (int i = 0; i < p_leaf_count; i++) {
-
- uint32_t idx = leaves[i];
-
- const GIProbeDataCell *cell = &cells[idx];
- InstanceGIProbeData::LocalData *light = &local_data[idx];
-
- Vector3 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5);
- to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray
-
- Vector3 norm(
- (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0,
- (((cells[idx].normal >> 0) & 0xFF) / 255.0) * 2.0 - 1.0);
-
- Vector3 light_axis = (to - light_pos).normalized();
- float distance_adv = _get_normal_advance(light_axis);
-
- float att = norm.dot(-light_axis);
- if (att < 0.001) {
- //not lighting towards this
- continue;
- }
-
- {
- float d = light_pos.distance_to(to);
- if (d + distance_adv > local_radius)
- continue; // too far away
-
- float dt = CLAMP((d + distance_adv) / local_radius, 0, 1);
- att *= powf(1.0 - dt, light_cache.attenuation);
- }
-
- if (light_cache.type == VS::LIGHT_SPOT) {
-
- float angle = Math::rad2deg(acos(light_axis.dot(spot_axis)));
- if (angle > light_cache.spot_angle)
- continue;
-
- float d = CLAMP(angle / light_cache.spot_angle, 0, 1);
- att *= powf(1.0 - d, light_cache.spot_attenuation);
- }
-
- 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 = limits[c] + 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 = _gi_bake_find_cell(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z)), header->cell_subdiv);
- if (result != 0xFFFFFFFF) {
- break;
- }
-
- from += light_axis * distance_adv;
- distance -= distance_adv;
- }
-
- if (result == idx) {
- //cell hit itself! hooray!
-
- light->energy[0] += int32_t(light_r * att * ((cell->albedo >> 16) & 0xFF) / 255.0);
- light->energy[1] += int32_t(light_g * att * ((cell->albedo >> 8) & 0xFF) / 255.0);
- light->energy[2] += int32_t(light_b * att * ((cell->albedo) & 0xFF) / 255.0);
- }
- }
- //print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
- } break;
- }
-}
-
-void VisualServerScene::_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) {
-
- //average light to upper level
-
- float divisor = 0;
- float sum[3] = { 0.0, 0.0, 0.0 };
-
- for (int i = 0; i < 8; i++) {
-
- uint32_t child = p_cells[p_idx].children[i];
-
- if (child == 0xFFFFFFFF)
- continue;
-
- if (p_level + 1 < (int)p_header->cell_subdiv - 1) {
- _bake_gi_downscale_light(child, p_level + 1, p_cells, p_header, p_local_data, p_propagate);
- }
-
- sum[0] += p_local_data[child].energy[0];
- sum[1] += p_local_data[child].energy[1];
- sum[2] += p_local_data[child].energy[2];
- divisor += 1.0;
- }
-
- divisor = Math::lerp((float)8.0, divisor, p_propagate);
- sum[0] /= divisor;
- sum[1] /= divisor;
- sum[2] /= divisor;
-
- //divide by eight for average
- p_local_data[p_idx].energy[0] = Math::fast_ftoi(sum[0]);
- p_local_data[p_idx].energy[1] = Math::fast_ftoi(sum[1]);
- p_local_data[p_idx].energy[2] = Math::fast_ftoi(sum[2]);
-}
-
-void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) {
-
- InstanceGIProbeData *probe_data = static_cast<InstanceGIProbeData *>(p_gi_probe->base_data);
-
- PoolVector<int>::Read r = probe_data->dynamic.light_data.read();
-
- const GIProbeDataHeader *header = (const GIProbeDataHeader *)r.ptr();
- const GIProbeDataCell *cells = (const GIProbeDataCell *)&r[16];
-
- int leaf_count = probe_data->dynamic.level_cell_lists[header->cell_subdiv - 1].size();
- const uint32_t *leaves = probe_data->dynamic.level_cell_lists[header->cell_subdiv - 1].ptr();
-
- PoolVector<InstanceGIProbeData::LocalData>::Write ldw = probe_data->dynamic.local_data.write();
-
- InstanceGIProbeData::LocalData *local_data = ldw.ptr();
-
- //remove what must be removed
- for (Map<RID, InstanceGIProbeData::LightCache>::Element *E = probe_data->dynamic.light_cache.front(); E; E = E->next()) {
-
- RID rid = E->key();
- const InstanceGIProbeData::LightCache &lc = E->get();
-
- if ((!probe_data->dynamic.light_cache_changes.has(rid) || probe_data->dynamic.light_cache_changes[rid] != lc) && lc.visible) {
- //erase light data
-
- _bake_gi_probe_light(header, cells, local_data, leaves, leaf_count, lc, -1);
- }
- }
-
- //add what must be added
- for (Map<RID, InstanceGIProbeData::LightCache>::Element *E = probe_data->dynamic.light_cache_changes.front(); E; E = E->next()) {
-
- RID rid = E->key();
- const InstanceGIProbeData::LightCache &lc = E->get();
-
- if ((!probe_data->dynamic.light_cache.has(rid) || probe_data->dynamic.light_cache[rid] != lc) && lc.visible) {
- //add light data
-
- _bake_gi_probe_light(header, cells, local_data, leaves, leaf_count, lc, 1);
- }
- }
-
- SWAP(probe_data->dynamic.light_cache_changes, probe_data->dynamic.light_cache);
-
- //downscale to lower res levels
- _bake_gi_downscale_light(0, 0, cells, header, local_data, probe_data->dynamic.propagate);
-
- //plot result to 3D texture!
-
- if (probe_data->dynamic.compression == RasterizerStorage::GI_PROBE_UNCOMPRESSED) {
-
- for (int i = 0; i < (int)header->cell_subdiv; i++) {
-
- int stage = header->cell_subdiv - i - 1;
-
- if (stage >= probe_data->dynamic.mipmaps_3d.size())
- continue; //no mipmap for this one
-
- //print_line("generating mipmap stage: " + itos(stage));
- int level_cell_count = probe_data->dynamic.level_cell_lists[i].size();
- const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[i].ptr();
-
- PoolVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d.write[stage].write();
- uint8_t *mipmapw = lw.ptr();
-
- uint32_t sizes[3] = { header->width >> stage, header->height >> stage, header->depth >> stage };
-
- for (int j = 0; j < level_cell_count; j++) {
-
- uint32_t idx = level_cells[j];
-
- uint32_t r2 = (uint32_t(local_data[idx].energy[0]) / probe_data->dynamic.bake_dynamic_range) >> 2;
- uint32_t g = (uint32_t(local_data[idx].energy[1]) / probe_data->dynamic.bake_dynamic_range) >> 2;
- uint32_t b = (uint32_t(local_data[idx].energy[2]) / probe_data->dynamic.bake_dynamic_range) >> 2;
- uint32_t a = (cells[idx].level_alpha >> 8) & 0xFF;
-
- uint32_t mm_ofs = sizes[0] * sizes[1] * (local_data[idx].pos[2]) + sizes[0] * (local_data[idx].pos[1]) + (local_data[idx].pos[0]);
- mm_ofs *= 4; //for RGBA (4 bytes)
-
- mipmapw[mm_ofs + 0] = uint8_t(MIN(r2, 255));
- mipmapw[mm_ofs + 1] = uint8_t(MIN(g, 255));
- mipmapw[mm_ofs + 2] = uint8_t(MIN(b, 255));
- mipmapw[mm_ofs + 3] = uint8_t(MIN(a, 255));
- }
- }
- } else if (probe_data->dynamic.compression == RasterizerStorage::GI_PROBE_S3TC) {
-
- int mipmap_count = probe_data->dynamic.mipmaps_3d.size();
-
- for (int mmi = 0; mmi < mipmap_count; mmi++) {
-
- PoolVector<uint8_t>::Write mmw = probe_data->dynamic.mipmaps_3d.write[mmi].write();
- int block_count = probe_data->dynamic.mipmaps_s3tc[mmi].size();
- PoolVector<InstanceGIProbeData::CompBlockS3TC>::Read mmr = probe_data->dynamic.mipmaps_s3tc[mmi].read();
-
- for (int i = 0; i < block_count; i++) {
-
- const InstanceGIProbeData::CompBlockS3TC &b = mmr[i];
-
- uint8_t *blockptr = &mmw[b.offset * 16];
- copymem(blockptr, b.alpha, 8); //copy alpha part, which is precomputed
-
- Vector3 colors[16];
-
- for (uint32_t j = 0; j < b.source_count; j++) {
-
- colors[j].x = (local_data[b.sources[j]].energy[0] / float(probe_data->dynamic.bake_dynamic_range)) / 1024.0;
- colors[j].y = (local_data[b.sources[j]].energy[1] / float(probe_data->dynamic.bake_dynamic_range)) / 1024.0;
- colors[j].z = (local_data[b.sources[j]].energy[2] / float(probe_data->dynamic.bake_dynamic_range)) / 1024.0;
- }
- //super quick and dirty compression
- //find 2 most further apart
- float distance = 0;
- Vector3 from, to;
-
- if (b.source_count == 16) {
- //all cells are used so, find minmax between them
- int further_apart[2] = { 0, 0 };
- for (uint32_t j = 0; j < b.source_count; j++) {
- for (uint32_t k = j + 1; k < b.source_count; k++) {
- float d = colors[j].distance_squared_to(colors[k]);
- if (d > distance) {
- distance = d;
- further_apart[0] = j;
- further_apart[1] = k;
- }
- }
- }
-
- from = colors[further_apart[0]];
- to = colors[further_apart[1]];
-
- } else {
- //if a block is missing, the priority is that this block remains black,
- //otherwise the geometry will appear deformed
- //correct shape wins over correct color in this case
- //average all colors first
- Vector3 average;
-
- for (uint32_t j = 0; j < b.source_count; j++) {
- average += colors[j];
- }
- average.normalize();
- //find max distance in normal from average
- for (uint32_t j = 0; j < b.source_count; j++) {
- float d = average.dot(colors[j]);
- distance = MAX(d, distance);
- }
-
- from = Vector3(); //from black
- to = average * distance;
- //find max distance
- }
-
- int indices[16];
- uint16_t color_0 = 0;
- color_0 = CLAMP(int(from.x * 31), 0, 31) << 11;
- color_0 |= CLAMP(int(from.y * 63), 0, 63) << 5;
- color_0 |= CLAMP(int(from.z * 31), 0, 31);
-
- uint16_t color_1 = 0;
- color_1 = CLAMP(int(to.x * 31), 0, 31) << 11;
- color_1 |= CLAMP(int(to.y * 63), 0, 63) << 5;
- color_1 |= CLAMP(int(to.z * 31), 0, 31);
-
- if (color_1 > color_0) {
- SWAP(color_1, color_0);
- SWAP(from, to);
- }
-
- if (distance > 0) {
-
- Vector3 dir = (to - from).normalized();
-
- for (uint32_t j = 0; j < b.source_count; j++) {
-
- float d = (colors[j] - from).dot(dir) / distance;
- indices[j] = int(d * 3 + 0.5);
-
- static const int index_swap[4] = { 0, 3, 1, 2 };
-
- indices[j] = index_swap[CLAMP(indices[j], 0, 3)];
- }
- } else {
- for (uint32_t j = 0; j < b.source_count; j++) {
- indices[j] = 0;
- }
- }
-
- //by default, 1 is black, otherwise it will be overridden by source
-
- uint32_t index_block[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-
- for (uint32_t j = 0; j < b.source_count; j++) {
-
- int x = local_data[b.sources[j]].pos[0] % 4;
- int y = local_data[b.sources[j]].pos[1] % 4;
-
- index_block[y * 4 + x] = indices[j];
- }
-
- uint32_t encode = 0;
-
- for (int j = 0; j < 16; j++) {
- encode |= index_block[j] << (j * 2);
- }
-
- blockptr[8] = color_0 & 0xFF;
- blockptr[9] = (color_0 >> 8) & 0xFF;
- blockptr[10] = color_1 & 0xFF;
- blockptr[11] = (color_1 >> 8) & 0xFF;
- blockptr[12] = encode & 0xFF;
- blockptr[13] = (encode >> 8) & 0xFF;
- blockptr[14] = (encode >> 16) & 0xFF;
- blockptr[15] = (encode >> 24) & 0xFF;
- }
- }
- }
-
- //send back to main thread to update un little chunks
- if (probe_bake_mutex) {
- probe_bake_mutex->lock();
- }
-
- probe_data->dynamic.updating_stage = GI_UPDATE_STAGE_UPLOADING;
-
- if (probe_bake_mutex) {
- probe_bake_mutex->unlock();
- }
-}
-
-bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) {
-
- InstanceGIProbeData *probe_data = static_cast<InstanceGIProbeData *>(p_gi_probe->base_data);
-
- probe_data->dynamic.light_cache_changes.clear();
-
- bool all_equal = true;
-
- for (List<Instance *>::Element *E = p_gi_probe->scenario->directional_lights.front(); E; E = E->next()) {
-
- if (!VSG::storage->light_get_use_gi(E->get()->base))
- continue;
-
- InstanceGIProbeData::LightCache lc;
- lc.type = VSG::storage->light_get_type(E->get()->base);
- lc.color = VSG::storage->light_get_color(E->get()->base);
- lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY) * VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- lc.radius = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_RANGE);
- lc.attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ATTENUATION);
- lc.spot_angle = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ANGLE);
- lc.spot_attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
- lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform;
- lc.visible = E->get()->visible;
-
- if (!probe_data->dynamic.light_cache.has(E->get()->self) || probe_data->dynamic.light_cache[E->get()->self] != lc) {
- all_equal = false;
- }
-
- probe_data->dynamic.light_cache_changes[E->get()->self] = lc;
- }
-
- for (Set<Instance *>::Element *E = probe_data->lights.front(); E; E = E->next()) {
-
- if (!VSG::storage->light_get_use_gi(E->get()->base))
- continue;
-
- InstanceGIProbeData::LightCache lc;
- lc.type = VSG::storage->light_get_type(E->get()->base);
- lc.color = VSG::storage->light_get_color(E->get()->base);
- lc.energy = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ENERGY) * VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- lc.radius = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_RANGE);
- lc.attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_ATTENUATION);
- lc.spot_angle = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ANGLE);
- lc.spot_attenuation = VSG::storage->light_get_param(E->get()->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
- lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform;
- lc.visible = E->get()->visible;
-
- if (!probe_data->dynamic.light_cache.has(E->get()->self) || probe_data->dynamic.light_cache[E->get()->self] != lc) {
- all_equal = false;
- }
-
- probe_data->dynamic.light_cache_changes[E->get()->self] = lc;
- }
-
- //lighting changed from after to before, must do some updating
- return !all_equal || probe_data->dynamic.light_cache_changes.size() != probe_data->dynamic.light_cache.size();
-}
-
void VisualServerScene::render_probes() {
/* REFLECTION PROBES */
@@ -3205,71 +2306,169 @@ void VisualServerScene::render_probes() {
SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first();
+ if (gi_probe) {
+ RENDER_TIMESTAMP("Render GI Probes");
+ }
+
while (gi_probe) {
SelfList<InstanceGIProbeData> *next = gi_probe->next();
InstanceGIProbeData *probe = gi_probe->self();
- Instance *instance_probe = probe->owner;
+ //Instance *instance_probe = probe->owner;
//check if probe must be setup, but don't do if on the lighting thread
- bool force_lighting = false;
+ bool cache_dirty = false;
+ int cache_count = 0;
+ {
- if (probe->invalid || (probe->dynamic.updating_stage == GI_UPDATE_STAGE_CHECK && probe->base_version != VSG::storage->gi_probe_get_version(instance_probe->base))) {
+ int light_cache_size = probe->light_cache.size();
+ const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr();
+ const RID *instance_caches = probe->light_instances.ptr();
- _setup_gi_probe(instance_probe);
- force_lighting = true;
- }
+ int idx = 0; //must count visible lights
+ for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+ if (cache_dirty) {
+ //do nothing, since idx must count all visible lights anyway
+ } else if (idx >= light_cache_size) {
+ cache_dirty = true;
+ } else {
- float propagate = VSG::storage->gi_probe_get_propagation(instance_probe->base);
+ const InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ if (
+ instance_caches[idx] != instance_light->instance ||
+ cache->has_shadow != VSG::storage->light_has_shadow(instance->base) ||
+ cache->type != VSG::storage->light_get_type(instance->base) ||
+ cache->transform != instance->transform ||
+ cache->color != VSG::storage->light_get_color(instance->base) ||
+ cache->energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY) ||
+ cache->bake_energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY) ||
+ cache->radius != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE) ||
+ cache->attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION) ||
+ cache->spot_angle != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE) ||
+ cache->spot_attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache_dirty = true;
+ }
+ }
- if (probe->dynamic.propagate != propagate) {
- probe->dynamic.propagate = propagate;
- force_lighting = true;
- }
+ idx++;
+ }
- if (!probe->invalid && probe->dynamic.enabled) {
+ for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
- switch (probe->dynamic.updating_stage) {
- case GI_UPDATE_STAGE_CHECK: {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+ if (cache_dirty) {
+ //do nothing, since idx must count all visible lights anyway
+ } else if (idx >= light_cache_size) {
+ cache_dirty = true;
+ } else {
- if (_check_gi_probe(instance_probe) || force_lighting) { //send to lighting thread
+ const InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ if (
+ instance_caches[idx] != instance_light->instance ||
+ cache->has_shadow != VSG::storage->light_has_shadow(instance->base) ||
+ cache->type != VSG::storage->light_get_type(instance->base) ||
+ cache->transform != instance->transform ||
+ cache->color != VSG::storage->light_get_color(instance->base) ||
+ cache->energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY) ||
+ cache->bake_energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY) ||
+ cache->radius != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE) ||
+ cache->attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION) ||
+ cache->spot_angle != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE) ||
+ cache->spot_attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache_dirty = true;
+ }
+ }
-#ifndef NO_THREADS
- probe_bake_mutex->lock();
- probe->dynamic.updating_stage = GI_UPDATE_STAGE_LIGHTING;
- probe_bake_list.push_back(instance_probe);
- probe_bake_mutex->unlock();
- probe_bake_sem->post();
+ idx++;
+ }
-#else
+ if (idx != light_cache_size) {
+ cache_dirty = true;
+ }
- _bake_gi_probe(instance_probe);
-#endif
- }
- } break;
- case GI_UPDATE_STAGE_LIGHTING: {
- //do none, wait til done!
+ cache_count = idx;
+ }
- } break;
- case GI_UPDATE_STAGE_UPLOADING: {
+ bool update_probe = VSG::scene_render->gi_probe_needs_update(probe->probe_instance);
- //uint64_t us = OS::get_singleton()->get_ticks_usec();
+ if (cache_dirty) {
+ probe->light_cache.resize(cache_count);
+ probe->light_instances.resize(cache_count);
- for (int i = 0; i < (int)probe->dynamic.mipmaps_3d.size(); i++) {
+ if (cache_count) {
+ InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw();
+ RID *instance_caches = probe->light_instances.ptrw();
- PoolVector<uint8_t>::Read r = probe->dynamic.mipmaps_3d[i].read();
- VSG::storage->gi_probe_dynamic_data_update(probe->dynamic.probe_data, 0, probe->dynamic.grid_size[2] >> i, i, r.ptr());
+ int idx = 0; //must count visible lights
+ for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
}
- probe->dynamic.updating_stage = GI_UPDATE_STAGE_CHECK;
+ InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ instance_caches[idx] = instance_light->instance;
+ cache->has_shadow = VSG::storage->light_has_shadow(instance->base);
+ cache->type = VSG::storage->light_get_type(instance->base);
+ cache->transform = instance->transform;
+ cache->color = VSG::storage->light_get_color(instance->base);
+ cache->energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY);
+ cache->bake_energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
+ cache->radius = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE);
+ cache->attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION);
+ cache->spot_angle = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
+ cache->spot_attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+ for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
- //print_line("UPLOAD TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
- } break;
+ InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ instance_caches[idx] = instance_light->instance;
+ cache->has_shadow = VSG::storage->light_has_shadow(instance->base);
+ cache->type = VSG::storage->light_get_type(instance->base);
+ cache->transform = instance->transform;
+ cache->color = VSG::storage->light_get_color(instance->base);
+ cache->energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY);
+ cache->bake_energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
+ cache->radius = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE);
+ cache->attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION);
+ cache->spot_angle = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
+ cache->spot_attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
}
+
+ update_probe = true;
+ }
+
+ if (update_probe) {
+ VSG::scene_render->gi_probe_update(probe->probe_instance, probe->light_instances);
}
- //_update_gi_probe(gi_probe->self()->owner);
+
+ gi_probe_update_list.remove(gi_probe);
gi_probe = next;
}
@@ -3527,26 +2726,9 @@ VisualServerScene *VisualServerScene::singleton = NULL;
VisualServerScene::VisualServerScene() {
-#ifndef NO_THREADS
- probe_bake_sem = SemaphoreOld::create();
- probe_bake_mutex = Mutex::create();
- probe_bake_thread = Thread::create(_gi_probe_bake_threads, this);
- probe_bake_thread_exit = false;
-#endif
-
render_pass = 1;
singleton = this;
}
VisualServerScene::~VisualServerScene() {
-
-#ifndef NO_THREADS
- probe_bake_thread_exit = true;
- probe_bake_sem->post();
- Thread::wait_to_finish(probe_bake_thread);
- memdelete(probe_bake_thread);
- memdelete(probe_bake_sem);
- memdelete(probe_bake_mutex);
-
-#endif
}
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
index 2fadd778be..b4ff26653b 100644
--- a/servers/visual/visual_server_scene.h
+++ b/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);
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index e1873e5999..37a2fffa7a 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/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 */
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index da57ab3e33..b3ce7103a9 100644
--- a/servers/visual_server.cpp
+++ b/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);
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 4c89e3d976..5408ad665b 100644
--- a/servers/visual_server.h
+++ b/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,
};