diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 16e25039f86..b85641e48f9 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2656,7 +2656,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; image_memory_barrier.newLayout = src_tex->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2677,7 +2677,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; image_memory_barrier.newLayout = dst_tex->layout; diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index b6edf5f0796..c2b3e693d4b 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -60,6 +60,9 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(VkDebugU strstr(pCallbackData->pMessage, "must be a memory object") != NULL) { return VK_FALSE; } + if (strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != NULL) { + return VK_FALSE; + } if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { strcat(prefix, "VERBOSE : "); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 45ceb862986..5a332fe0f98 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -298,6 +298,7 @@ void GeometryInstance::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_dynamic_gi"), "set_flag", "get_flag", FLAG_USE_DYNAMIC_GI); ADD_GROUP("LOD", "lod_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance"); @@ -313,6 +314,7 @@ void GeometryInstance::_bind_methods() { BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY); BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT); + BIND_ENUM_CONSTANT(FLAG_USE_DYNAMIC_GI); BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE); BIND_ENUM_CONSTANT(FLAG_MAX); } diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index f115748952c..c1d6c2b0153 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -87,6 +87,7 @@ class GeometryInstance : public VisualInstance { public: enum Flags { FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT, + FLAG_USE_DYNAMIC_GI = VS::INSTANCE_FLAG_USE_DYNAMIC_GI, FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, FLAG_MAX = VS::INSTANCE_FLAG_MAX, }; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 9d59f87edd5..5a39a6dbfd8 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -140,7 +140,8 @@ public: bool mirror : 8; bool receive_shadows : 8; bool visible : 8; - bool baked_light : 4; //this flag is only to know if it actually did use baked light + bool baked_light : 2; //this flag is only to know if it actually did use baked light + bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light bool redraw_if_visible : 4; float depth; //used for sorting @@ -151,6 +152,9 @@ public: RID lightmap; Vector lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader + AABB aabb; + AABB transformed_aabb; + virtual void dependency_deleted(RID p_dependency) = 0; virtual void dependency_changed(bool p_aabb, bool p_dependencies) = 0; @@ -204,6 +208,7 @@ public: layer_mask = 1; instance_version = 0; baked_light = false; + dynamic_gi = false; redraw_if_visible = false; lightmap_capture = NULL; } @@ -233,11 +238,12 @@ public: virtual RID gi_probe_instance_create(RID p_gi_probe) = 0; virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; virtual bool gi_probe_needs_update(RID p_probe) const = 0; - virtual void gi_probe_update(RID p_probe, const Vector &p_light_instances) = 0; + virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 0; virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0; + virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void set_scene_pass(uint64_t p_pass) = 0; virtual void set_time(double p_time) = 0; diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp index 55974846f2e..867120db047 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp @@ -308,9 +308,11 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) { if (depth_draw == DEPTH_DRAW_OPAQUE) { depth_stencil.enable_depth_write = false; //alpha does not draw depth } - } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS)) { + } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { //none, blend state contains nothing + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way } else { blend_state = blend_state_opaque; //writes to normal and roughness in opaque way } @@ -326,6 +328,9 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) { //none, leave empty } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { blend_state = blend_state_opaque; //writes to normal and roughness in opaque way + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else { //specular write blend_state = blend_state_opaque_specular; @@ -601,7 +606,7 @@ bool RasterizerSceneForwardRD::free(RID p_rid) { return false; } -void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count) { +void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth) { for (int i = 0; i < p_element_count; i++) { @@ -637,6 +642,10 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, } } + if (p_for_depth) { + id.gi_offset = 0xFFFFFFFF; + continue; + } //forward uint32_t reflection_count = 0; @@ -850,6 +859,9 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; } break; + case PASS_MODE_DEPTH_MATERIAL: { + shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; + } break; } RenderPipelineVertexFormatCacheRD *pipeline = nullptr; @@ -939,12 +951,12 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l } } -void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) { +void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y) { //CameraMatrix projection = p_cam_projection; //projection.flip_y(); // Vulkan and modern APIs use Y-Down CameraMatrix correction; - correction.set_depth_correction(!p_reflection_probe.is_valid()); + correction.set_depth_correction(p_flip_y); CameraMatrix projection = correction * p_cam_projection; //store camera into ubo @@ -1236,7 +1248,7 @@ void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_insta return; } - if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + if (p_pass_mode != PASS_MODE_DEPTH_MATERIAL && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { //shader does not use discard and does not write a vertex position, use generic material if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) { p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); @@ -1837,7 +1849,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows); _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment); _setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform); - _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas); + _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid()); render_list.clear(); _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr); @@ -1896,7 +1908,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count); + _fill_instances(render_list.elements, render_list.element_count, false); bool can_continue = true; //unless the middle buffers are needed bool debug_giprobes = debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || debug_draw == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; @@ -1952,7 +1964,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co render_list.sort_by_reverse_depth_and_priority(true); - _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count); + _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false); { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); @@ -2087,7 +2099,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase ** scene_state.ubo.z_far = p_zfar; scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID()); + _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true); render_list.clear(); @@ -2101,7 +2113,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase ** render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count); + _fill_instances(render_list.elements, render_list.element_count, true); { //regular forward for now @@ -2111,6 +2123,47 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase ** } } +void RasterizerSceneForwardRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { + RENDER_TIMESTAMP("Setup Rendering Shadow"); + + _update_render_base_uniform_set(); + + render_pass++; + + scene_state.ubo.shadow_z_offset = 0; + scene_state.ubo.shadow_z_slope_scale = 0; + scene_state.ubo.z_far = 0; + scene_state.ubo.dual_paraboloid_side = 0; + + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false); + + render_list.clear(); + + PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; + _fill_render_list(p_cull_result, p_cull_count, pass_mode, true); + + _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID()); + + RENDER_TIMESTAMP("Render Material"); + + render_list.sort_by_key(false); + + _fill_instances(render_list.elements, render_list.element_count, true); + + { + //regular forward for now + Vector clear; + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true); + RD::get_singleton()->draw_list_end(); + } +} + void RasterizerSceneForwardRD::_update_render_base_uniform_set() { if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || gi_probe_slots_are_dirty()) { @@ -2425,6 +2478,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_BUFFER\n"); shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_ROUGHNESS_BUFFER\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); shader_versions.push_back(""); shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); shader_versions.push_back("\n#define USE_VOXEL_CONE_TRACING\n"); diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h index 2d057b58405..6e88a04e6d2 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h @@ -45,6 +45,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { SHADER_VERSION_DEPTH_PASS_DP, SHADER_VERSION_DEPTH_PASS_WITH_NORMAL, SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, SHADER_VERSION_COLOR_PASS, SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, SHADER_VERSION_VCT_COLOR_PASS, @@ -519,14 +520,15 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { PASS_MODE_DEPTH, PASS_MODE_DEPTH_NORMAL, PASS_MODE_DEPTH_NORMAL_ROUGHNESS, + PASS_MODE_DEPTH_MATERIAL, }; - void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas); + void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y); void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows); void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment); void _setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform); - void _fill_instances(RenderList::Element **p_elements, int p_element_count); + void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth); void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi); _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index); _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index); @@ -540,6 +542,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { protected: virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip); + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); public: virtual void set_time(double p_time); diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index f039bae766d..5633a8e2efc 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -1245,7 +1245,7 @@ bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const { return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe); } -void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector &p_light_instances) { +void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND(!gi_probe); @@ -1266,6 +1266,13 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector &p_light_ gi_probe->mipmaps.clear(); } + for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) { + RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture); + RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth); + } + + gi_probe->dynamic_maps.clear(); + Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); if (octree_size != Vector3i()) { @@ -1354,6 +1361,21 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector &p_light_ u.ids.push_back(gi_probe->write_buffer); uniforms.push_back(u); } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 9; + u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 10; + u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + } + { Vector copy_uniforms = uniforms; if (i == 0) { @@ -1376,13 +1398,6 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector &p_light_ u.ids.push_back(gi_probe->texture); copy_uniforms.push_back(u); } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 6; - u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); - copy_uniforms.push_back(u); - } if (gi_probe_use_anisotropy) { { @@ -1436,138 +1451,579 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, const Vector &p_light_ gi_probe->mipmaps.push_back(mipmap); } + + { + uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z); + uint32_t oversample = nearest_power_of_2_templated(4); + int mipmap_index = 0; + + while (mipmap_index < gi_probe->mipmaps.size()) { + GIProbeInstance::DynamicMap dmap; + + if (oversample > 0) { + dmap.size = dynamic_map_size * (1 << oversample); + dmap.mipmap = -1; + oversample--; + } else { + dmap.size = dynamic_map_size >> mipmap_index; + dmap.mipmap = mipmap_index; + mipmap_index++; + } + + RD::TextureFormat dtf; + dtf.width = dmap.size; + dtf.height = dmap.size; + dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + + if (gi_probe->dynamic_maps.size() == 0) { + dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } + dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + + if (gi_probe->dynamic_maps.size() == 0) { + //render depth for first one + dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; + dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + } + + //just use depth as-is + dtf.format = RD::DATA_FORMAT_R32_SFLOAT; + dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + + if (gi_probe->dynamic_maps.size() == 0) { + + dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + + Vector fb; + fb.push_back(dmap.albedo); + fb.push_back(dmap.normal); + fb.push_back(dmap.orm); + fb.push_back(dmap.texture); //emission + fb.push_back(dmap.depth); + fb.push_back(dmap.fb_depth); + + dmap.fb = RD::get_singleton()->framebuffer_create(fb); + + { + Vector uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 3; + u.ids.push_back(gi_probe_lights_uniform); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 5; + u.ids.push_back(dmap.albedo); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 6; + u.ids.push_back(dmap.normal); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 7; + u.ids.push_back(dmap.orm); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 8; + u.ids.push_back(dmap.fb_depth); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 9; + u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 10; + u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 11; + u.ids.push_back(dmap.texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 12; + u.ids.push_back(dmap.depth); + uniforms.push_back(u); + } + + dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0); + } + } else { + bool plot = dmap.mipmap >= 0; + bool write = dmap.mipmap < (gi_probe->mipmaps.size() - 1); + + Vector uniforms; + + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 5; + u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 6; + u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth); + uniforms.push_back(u); + } + + if (write) { + + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 7; + u.ids.push_back(dmap.texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 8; + u.ids.push_back(dmap.depth); + uniforms.push_back(u); + } + } + + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 9; + u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 10; + u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + } + + if (plot) { + + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 11; + u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture); + uniforms.push_back(u); + } + if (gi_probe_is_anisotropic()) { + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 12; + u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[0]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 13; + u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[1]); + uniforms.push_back(u); + } + } + } + + dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT], 0); + } + + gi_probe->dynamic_maps.push_back(dmap); + } + } } gi_probe->last_probe_data_version = data_version; gi_probe_slots_dirty = true; + p_update_light_instances = true; //just in case } // UDPDATE TIME - uint32_t light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size()); - { - Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe); - Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse(); - //update lights - - 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); + if (gi_probe->has_dynamic_object_data) { + //if it has dynamic object data, it needs to be cleared + RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true); } - // PROCESS MIPMAPS - if (gi_probe->mipmaps.size()) { - //can update mipmaps + uint32_t light_count = 0; - Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe); + if (p_update_light_instances || p_dynamic_object_count > 0) { - GIProbePushConstant push_constant; + light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size()); - 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); + { + 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 - /* 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(); + 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); - int passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1; - int wg_size = 64; - int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X); + 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; - for (int pass = 0; pass < passes; pass++) { + 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); - 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]); - } + 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); + } + } + + if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) { + // PROCESS MIPMAPS + if (gi_probe->mipmaps.size()) { + //can update mipmaps + + Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe); + + GIProbePushConstant push_constant; + + push_constant.limits[0] = probe_size.x; + push_constant.limits[1] = probe_size.y; + push_constant.limits[2] = probe_size.z; + push_constant.stack_size = gi_probe->mipmaps.size(); + push_constant.emission_scale = 1.0; + push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe); + push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe); + push_constant.light_count = light_count; + push_constant.aniso_strength = storage->gi_probe_get_anisotropy_strength(gi_probe->probe); + + /* print_line("probe update to version " + itos(gi_probe->last_probe_version)); + print_line("propagation " + rtos(push_constant.propagation)); + print_line("dynrange " + rtos(push_constant.dynamic_range)); + */ + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + int passes; + if (p_update_light_instances) { + passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1; + } else { + passes = 1; //only re-blitting is necessary + } + int wg_size = 64; + int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X); + + for (int pass = 0; pass < passes; pass++) { + + if (p_update_light_instances) { + + for (int i = 0; i < gi_probe->mipmaps.size(); i++) { + if (i == 0) { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]); + } else if (i == 1) { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]); + } + + if (pass == 1 || i > 0) { + RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done + } + if (pass == 0 || i > 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0); + } + + push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset; + push_constant.cell_count = gi_probe->mipmaps[i].cell_count; + + int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1; + while (wg_todo) { + int wg_count = MIN(wg_todo, wg_limit_x); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); + wg_todo -= wg_count; + push_constant.cell_offset += wg_count * wg_size; + } + } - if (pass == 1 || i > 0) { RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done } - if (pass == 0 || i > 0) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0); - } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0); - } - 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_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]); - int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1; - while (wg_todo) { - int wg_count = MIN(wg_todo, wg_limit_x); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); - wg_todo -= wg_count; - push_constant.cell_offset += wg_count * wg_size; + for (int i = 0; i < gi_probe->mipmaps.size(); i++) { + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0); + + push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset; + push_constant.cell_count = gi_probe->mipmaps[i].cell_count; + + int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1; + while (wg_todo) { + int wg_count = MIN(wg_todo, wg_limit_x); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); + wg_todo -= wg_count; + push_constant.cell_offset += wg_count * wg_size; + } } } - RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done + RD::get_singleton()->compute_list_end(); + } + } - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]); + gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again - for (int i = 0; i < gi_probe->mipmaps.size(); i++) { + if (p_dynamic_object_count && gi_probe->dynamic_maps.size()) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0); + Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); + int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z); - push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset; - push_constant.cell_count = gi_probe->mipmaps[i].cell_count; + Transform oversample_scale; + oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier)); - int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1; - while (wg_todo) { - int wg_count = MIN(wg_todo, wg_limit_x); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); - wg_todo -= wg_count; - push_constant.cell_offset += wg_count * wg_size; + Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(gi_probe->probe); + Transform to_world_xform = gi_probe->transform * to_cell.affine_inverse(); + Transform to_probe_xform = to_world_xform.affine_inverse(); + + AABB probe_aabb(Vector3(), octree_size); + + //this could probably be better parallelized in compute.. + for (int i = 0; i < p_dynamic_object_count; i++) { + + InstanceBase *instance = p_dynamic_objects[i]; + //not used, so clear + instance->depth_layer = 0; + instance->depth = 0; + + //transform aabb to giprobe + AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb); + + //this needs to wrap to grid resolution to avoid jitter + //also extend margin a bit just in case + Vector3i begin = aabb.position - Vector3i(1, 1, 1); + Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1); + + for (int j = 0; j < 3; j++) { + if ((end[j] - begin[j]) & 1) { + end[j]++; //for half extents split, it needs to be even } + begin[j] = MAX(begin[j], 0); + end[j] = MIN(end[j], octree_size[j] * multiplier); + } + + //aabb = aabb.intersection(probe_aabb); //intersect + aabb.position = begin; + aabb.size = end - begin; + + //print_line("aabb: " + aabb); + + for (int j = 0; j < 6; j++) { + + //if (j != 0 && j != 3) { + // continue; + //} + static const Vector3 render_z[6] = { + Vector3(1, 0, 0), + Vector3(0, 1, 0), + Vector3(0, 0, 1), + Vector3(-1, 0, 0), + Vector3(0, -1, 0), + Vector3(0, 0, -1), + }; + static const Vector3 render_up[6] = { + Vector3(0, 1, 0), + Vector3(0, 0, 1), + Vector3(0, 1, 0), + Vector3(0, 1, 0), + Vector3(0, 0, 1), + Vector3(0, 1, 0), + }; + + Vector3 render_dir = render_z[j]; + Vector3 up_dir = render_up[j]; + + Vector3 center = aabb.position + aabb.size * 0.5; + Transform xform; + xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir); + + Vector3 x_dir = xform.basis.get_axis(0).abs(); + int x_axis = int(Vector3(0, 1, 2).dot(x_dir)); + Vector3 y_dir = xform.basis.get_axis(1).abs(); + int y_axis = int(Vector3(0, 1, 2).dot(y_dir)); + Vector3 z_dir = -xform.basis.get_axis(2); + int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs())); + + Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]); + bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0); + bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0); + bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0); + + CameraMatrix cm; + cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]); + + _render_material(to_world_xform * xform, cm, true, &instance, 1, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); + + GIProbeDynamicPushConstant push_constant; + zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant)); + push_constant.limits[0] = octree_size.x; + push_constant.limits[1] = octree_size.y; + push_constant.limits[2] = octree_size.z; + push_constant.light_count = p_light_instances.size(); + push_constant.x_dir[0] = x_dir[0]; + push_constant.x_dir[1] = x_dir[1]; + push_constant.x_dir[2] = x_dir[2]; + push_constant.y_dir[0] = y_dir[0]; + push_constant.y_dir[1] = y_dir[1]; + push_constant.y_dir[2] = y_dir[2]; + push_constant.z_dir[0] = z_dir[0]; + push_constant.z_dir[1] = z_dir[1]; + push_constant.z_dir[2] = z_dir[2]; + push_constant.z_base = xform.origin[z_axis]; + push_constant.z_sign = (z_flip ? -1.0 : 1.0); + push_constant.pos_multiplier = float(1.0) / multiplier; + push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe); + push_constant.flip_x = x_flip; + push_constant.flip_y = y_flip; + push_constant.rect_pos[0] = rect.position[0]; + push_constant.rect_pos[1] = rect.position[1]; + push_constant.rect_size[0] = rect.size[0]; + push_constant.rect_size[1] = rect.size[1]; + push_constant.prev_rect_ofs[0] = 0; + push_constant.prev_rect_ofs[1] = 0; + push_constant.prev_rect_size[0] = 0; + push_constant.prev_rect_size[1] = 0; + push_constant.keep_downsample_color = true; + + //process lighting + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[0].uniform_set, 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); + //print_line("rect: " + itos(i) + ": " + rect); + + for (int k = 1; k < gi_probe->dynamic_maps.size(); k++) { + + // enlarge the rect if needed so all pixels fit when downscaled, + // this ensures downsampling is smooth and optimal because no pixels are left behind + + //x + if (rect.position.x & 1) { + rect.size.x++; + push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal + } else { + push_constant.prev_rect_ofs[0] = 0; + } + if (rect.size.x & 1) { + rect.size.x++; + } + + rect.position.x >>= 1; + rect.size.x = MAX(1, rect.size.x >> 1); + + //y + if (rect.position.y & 1) { + rect.size.y++; + push_constant.prev_rect_ofs[1] = 1; + } else { + push_constant.prev_rect_ofs[1] = 0; + } + if (rect.size.y & 1) { + rect.size.y++; + } + + rect.position.y >>= 1; + rect.size.y = MAX(1, rect.size.y >> 1); + + //shrink limits to ensure plot does not go outside map + if (gi_probe->dynamic_maps[i].mipmap > 0) { + for (int l = 0; l < 3; l++) { + push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1); + } + } + + //print_line("rect: " + itos(i) + ": " + rect); + push_constant.rect_pos[0] = rect.position[0]; + push_constant.rect_pos[1] = rect.position[1]; + push_constant.prev_rect_size[0] = push_constant.rect_size[0]; + push_constant.prev_rect_size[1] = push_constant.rect_size[1]; + push_constant.rect_size[0] = rect.size[0]; + push_constant.rect_size[1] = rect.size[1]; + push_constant.keep_downsample_color = gi_probe->dynamic_maps[i].mipmap <= 0; + ; + + RD::get_singleton()->compute_list_add_barrier(compute_list); + + if (gi_probe->dynamic_maps[k].mipmap < 0) { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]); + } else if (k < gi_probe->dynamic_maps.size() - 1) { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]); + } else { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[k].uniform_set, 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); + } + + RD::get_singleton()->compute_list_end(); } } - RD::get_singleton()->compute_list_end(); + gi_probe->has_dynamic_object_data = true; //clear until dynamic object data is used again } gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe); @@ -1584,6 +2040,7 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis CameraMatrix transform = (p_camera_with_transform * CameraMatrix(gi_probe->transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(gi_probe->probe).affine_inverse()); int level = 0; + Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); GIProbeDebugPushConstant push_constant; push_constant.alpha = p_alpha; @@ -1591,7 +2048,10 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset; push_constant.level = level; - int cell_count = gi_probe->mipmaps[level].cell_count; + push_constant.bounds[0] = octree_size.x >> level; + push_constant.bounds[1] = octree_size.y >> level; + push_constant.bounds[2] = octree_size.z >> level; + push_constant.pad = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -1643,8 +2103,15 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis } } + int cell_count; + if (!p_emission && p_lighting && gi_probe->has_dynamic_object_data) { + cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2]; + } else { + cell_count = gi_probe->mipmaps[level].cell_count; + } + giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0); - RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? GI_PROBE_DEBUG_LIGHT : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0); RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant)); RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36); @@ -1875,6 +2342,11 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas } } +void RasterizerSceneRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { + + _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region); +} + bool RasterizerSceneRD::free(RID p_rid) { if (render_buffers_owner.owns(p_rid)) { @@ -1903,6 +2375,11 @@ bool RasterizerSceneRD::free(RID p_rid) { RD::get_singleton()->free(gi_probe->anisotropy[1]); } + for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) { + RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture); + RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth); + } + gi_probe_slots.write[gi_probe->slot] = RID(); gi_probe_instance_owner.free(p_rid); @@ -2002,6 +2479,10 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { versions.push_back("\n#define MODE_SECOND_BOUNCE\n"); versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n"); versions.push_back("\n#define MODE_WRITE_TEXTURE\n"); + versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n"); + versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n"); + versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n"); + versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n"); giprobe_shader.initialize(versions, defines); giprobe_lighting_shader_version = giprobe_shader.version_create(); @@ -2021,6 +2502,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { versions.push_back("\n#define MODE_DEBUG_COLOR\n"); versions.push_back("\n#define MODE_DEBUG_LIGHT\n"); versions.push_back("\n#define MODE_DEBUG_EMISSION\n"); + versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n"); giprobe_debug_shader.initialize(versions, defines); giprobe_debug_shader_version = giprobe_debug_shader.version_create(); diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h index d05c9a9328f..4712ad92c9a 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h @@ -26,6 +26,7 @@ protected: virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip) = 0; + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); @@ -155,6 +156,26 @@ private: uint32_t pad; }; + struct GIProbeDynamicPushConstant { + + int32_t limits[3]; + uint32_t light_count; + int32_t x_dir[3]; + float z_base; + int32_t y_dir[3]; + float z_sign; + int32_t z_dir[3]; + float pos_multiplier; + uint32_t rect_pos[2]; + uint32_t rect_size[2]; + uint32_t prev_rect_ofs[2]; + uint32_t prev_rect_size[2]; + uint32_t flip_x; + uint32_t flip_y; + float dynamic_range; + uint32_t keep_downsample_color; + }; + struct GIProbeInstance { RID probe; @@ -174,6 +195,21 @@ private: }; Vector mipmaps; + struct DynamicMap { + RID texture; //color normally, or emission on first pass + RID fb_depth; //actual depth buffer for the first pass, float depth for later passes + RID depth; //actual depth buffer for the first pass, float depth for later passes + RID normal; //normal buffer for the first pass + RID albedo; //emission buffer for the first pass + RID orm; //orm buffer for the first pass + RID fb; //used for rendering, only valid on first map + RID uniform_set; + uint32_t size; + int mipmap; // mipmap to write to, -1 if no mipmap assigned + }; + + Vector dynamic_maps; + int slot = -1; uint32_t last_probe_version = 0; uint32_t last_probe_data_version = 0; @@ -181,6 +217,8 @@ private: uint64_t last_pass = 0; uint32_t render_index = 0; + bool has_dynamic_object_data = false; + Transform transform; }; @@ -198,6 +236,10 @@ private: GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE, GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP, GI_PROBE_SHADER_VERSION_WRITE_TEXTURE, + GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING, + GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE, + GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT, + GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT, GI_PROBE_SHADER_VERSION_MAX }; GiprobeShaderRD giprobe_shader; @@ -211,6 +253,7 @@ private: GI_PROBE_DEBUG_COLOR, GI_PROBE_DEBUG_LIGHT, GI_PROBE_DEBUG_EMISSION, + GI_PROBE_DEBUG_LIGHT_FULL, GI_PROBE_DEBUG_MAX }; @@ -220,6 +263,8 @@ private: float dynamic_range; float alpha; uint32_t level; + int32_t bounds[3]; + uint32_t pad; }; GiprobeDebugShaderRD giprobe_debug_shader; @@ -662,7 +707,8 @@ public: RID gi_probe_instance_create(RID p_base); void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); bool gi_probe_needs_update(RID p_probe) const; - void gi_probe_update(RID p_probe, const Vector &p_light_instances); + void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects); + _FORCE_INLINE_ uint32_t gi_probe_instance_get_slot(RID p_probe) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); return gi_probe->slot; @@ -726,6 +772,8 @@ public: void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); + void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); + virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; } _FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; } diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp index 28ecda081da..4c5b9b94fbb 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -3558,41 +3558,19 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t bool data_version_changed = false; - if (gi_probe->octree_buffer_size != p_octree_cells.size() || gi_probe->data_buffer_size != p_data_cells.size()) { - //buffer size changed, clear if needed - if (gi_probe->octree_buffer.is_valid()) { - RD::get_singleton()->free(gi_probe->octree_buffer); - RD::get_singleton()->free(gi_probe->data_buffer); - - gi_probe->octree_buffer = RID(); - gi_probe->data_buffer = RID(); - gi_probe->octree_buffer_size = 0; - gi_probe->data_buffer_size = 0; - gi_probe->cell_count = 0; + if (gi_probe->octree_buffer.is_valid()) { + RD::get_singleton()->free(gi_probe->octree_buffer); + RD::get_singleton()->free(gi_probe->data_buffer); + if (gi_probe->sdf_texture.is_valid()) { + RD::get_singleton()->free(gi_probe->sdf_texture); } - data_version_changed = true; - - } else if (gi_probe->octree_buffer_size) { - //they are the same and size did not change.. - //update - - PoolVector::Read rc = p_octree_cells.read(); - PoolVector::Read rd = p_data_cells.read(); - - RD::get_singleton()->buffer_update(gi_probe->octree_buffer, 0, gi_probe->octree_buffer_size, rc.ptr()); - RD::get_singleton()->buffer_update(gi_probe->data_buffer, 0, gi_probe->data_buffer_size, rd.ptr()); - } - - if (gi_probe->level_counts.size() != p_level_counts.size()) { - data_version_changed = true; - } else { - for (int i = 0; i < p_level_counts.size(); i++) { - if (gi_probe->level_counts[i] != p_level_counts[i]) { - data_version_changed = true; - break; - } - } + gi_probe->sdf_texture = RID(); + gi_probe->octree_buffer = RID(); + gi_probe->data_buffer = RID(); + gi_probe->octree_buffer_size = 0; + gi_probe->data_buffer_size = 0; + gi_probe->cell_count = 0; } gi_probe->to_cell_xform = p_to_cell_xform; @@ -3600,7 +3578,7 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t gi_probe->octree_size = p_octree_size; gi_probe->level_counts = p_level_counts; - if (p_octree_cells.size() && gi_probe->octree_buffer.is_null()) { + if (p_octree_cells.size()) { ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32 uint32_t cell_count = p_octree_cells.size() / 32; @@ -3612,13 +3590,80 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t gi_probe->octree_buffer_size = p_octree_cells.size(); gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells); gi_probe->data_buffer_size = p_data_cells.size(); - data_version_changed = true; + + { + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.width = gi_probe->octree_size.x; + tf.height = gi_probe->octree_size.y; + tf.depth = gi_probe->octree_size.z; + tf.type = RD::TEXTURE_TYPE_3D; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM); + tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT); + gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + RID shared_tex; + { + + RD::TextureView tv; + tv.format_override = RD::DATA_FORMAT_R8_UINT; + shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture); + } + //update SDF texture + Vector uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.ids.push_back(gi_probe->octree_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(gi_probe->data_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 3; + u.ids.push_back(shared_tex); + uniforms.push_back(u); + } + + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0); + + { + uint32_t push_constant[4] = { 0, 0, 0, 0 }; + + for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) { + push_constant[0] += gi_probe->level_counts[i]; + } + push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1]; + + print_line("offset: " + itos(push_constant[0])); + print_line("size: " + itos(push_constant[1])); + //create SDF + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4); + RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4); + RD::get_singleton()->compute_list_end(); + } + + RD::get_singleton()->free(uniform_set); + RD::get_singleton()->free(shared_tex); + } } gi_probe->version++; - if (data_version_changed) { - gi_probe->data_version++; - } + gi_probe->data_version++; + gi_probe->instance_dependency.instance_notify_changed(true, false); } @@ -3794,6 +3839,13 @@ RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const { return gi_probe->data_buffer; } +RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { + GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); + ERR_FAIL_COND_V(!gi_probe, RID()); + + return gi_probe->sdf_texture; +} + /* RENDER TARGET API */ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { @@ -4583,110 +4635,121 @@ RasterizerStorageRD::RasterizerStorageRD() { { { //vertex - PoolVector buffer; - buffer.resize(sizeof(float) * 3); - { - PoolVector::Write w = buffer.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 0.0; - fptr[1] = 0.0; - fptr[2] = 0.0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } - { //normal - PoolVector buffer; - buffer.resize(sizeof(float) * 3); - { - PoolVector::Write w = buffer.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 1.0; - fptr[1] = 0.0; - fptr[2] = 0.0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } - - { //tangent - PoolVector buffer; - buffer.resize(sizeof(float) * 4); - { - PoolVector::Write w = buffer.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 1.0; - fptr[1] = 0.0; - fptr[2] = 0.0; - fptr[3] = 0.0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } - - { //color - PoolVector buffer; - buffer.resize(sizeof(float) * 4); - { - PoolVector::Write w = buffer.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 1.0; - fptr[1] = 1.0; - fptr[2] = 1.0; - fptr[3] = 1.0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } - - { //tex uv 1 - PoolVector buffer; - buffer.resize(sizeof(float) * 2); - { - PoolVector::Write w = buffer.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 0.0; - fptr[1] = 0.0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } - { //tex uv 2 - PoolVector buffer; - buffer.resize(sizeof(float) * 2); - { - PoolVector::Write w = buffer.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 0.0; - fptr[1] = 0.0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } - - { //bones - PoolVector buffer; - buffer.resize(sizeof(uint32_t) * 4); - { - PoolVector::Write w = buffer.write(); - uint32_t *fptr = (uint32_t *)w.ptr(); - fptr[0] = 0; - fptr[1] = 0; - fptr[2] = 0; - fptr[3] = 0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } - - { //weights - PoolVector buffer; - buffer.resize(sizeof(float) * 4); - { - PoolVector::Write w = buffer.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 0.0; - fptr[1] = 0.0; - fptr[2] = 0.0; - fptr[3] = 0.0; - } - mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); - } + PoolVector buffer; + buffer.resize(sizeof(float) * 3); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + fptr[2] = 0.0; } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} + +{ //normal + PoolVector buffer; + buffer.resize(sizeof(float) * 3); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 1.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} + +{ //tangent + PoolVector buffer; + buffer.resize(sizeof(float) * 4); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 1.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + fptr[3] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} + +{ //color + PoolVector buffer; + buffer.resize(sizeof(float) * 4); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 1.0; + fptr[1] = 1.0; + fptr[2] = 1.0; + fptr[3] = 1.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} + +{ //tex uv 1 + PoolVector buffer; + buffer.resize(sizeof(float) * 2); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} +{ //tex uv 2 + PoolVector buffer; + buffer.resize(sizeof(float) * 2); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} + +{ //bones + PoolVector buffer; + buffer.resize(sizeof(uint32_t) * 4); + { + PoolVector::Write w = buffer.write(); + uint32_t *fptr = (uint32_t *)w.ptr(); + fptr[0] = 0; + fptr[1] = 0; + fptr[2] = 0; + fptr[3] = 0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} + +{ //weights + PoolVector buffer; + buffer.resize(sizeof(float) * 4); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + fptr[3] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); +} +} + +{ + Vector sdf_versions; + sdf_versions.push_back(""); //one only + giprobe_sdf_shader.initialize(sdf_versions); + giprobe_sdf_shader_version = giprobe_sdf_shader.version_create(); + giprobe_sdf_shader.version_set_compute_code(giprobe_sdf_shader_version, "", "", "", Vector()); + giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0); + giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader); +} } RasterizerStorageRD::~RasterizerStorageRD() { diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h index 289a2ae5a82..63713c6add5 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -35,6 +35,7 @@ #include "servers/visual/rasterizer.h" #include "servers/visual/rasterizer_rd/rasterizer_effects_rd.h" #include "servers/visual/rasterizer_rd/shader_compiler_rd.h" +#include "servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h" #include "servers/visual/rendering_device.h" class RasterizerStorageRD : public RasterizerStorage { @@ -407,6 +408,7 @@ private: RID octree_buffer; RID data_buffer; + RID sdf_texture; uint32_t octree_buffer_size = 0; uint32_t data_buffer_size = 0; @@ -435,6 +437,11 @@ private: RasterizerScene::InstanceDependency instance_dependency; }; + GiprobeSdfShaderRD giprobe_sdf_shader; + RID giprobe_sdf_shader_version; + RID giprobe_sdf_shader_version_shader; + RID giprobe_sdf_shader_pipeline; + mutable RID_Owner gi_probe_owner; /* RENDER TARGET */ @@ -999,6 +1006,8 @@ public: RID gi_probe_get_octree_buffer(RID p_gi_probe) const; RID gi_probe_get_data_buffer(RID p_gi_probe) const; + RID gi_probe_get_sdf_texture(RID p_gi_probe); + /* LIGHTMAP CAPTURE */ void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {} diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub index bce700f7b02..ff83b46a9b2 100644 --- a/servers/visual/rasterizer_rd/shaders/SCsub +++ b/servers/visual/rasterizer_rd/shaders/SCsub @@ -13,4 +13,6 @@ if 'RD_GLSL' in env['BUILDERS']: env.RD_GLSL('copy.glsl'); env.RD_GLSL('giprobe.glsl'); env.RD_GLSL('giprobe_debug.glsl'); + env.RD_GLSL('giprobe_sdf.glsl'); + diff --git a/servers/visual/rasterizer_rd/shaders/giprobe.glsl b/servers/visual/rasterizer_rd/shaders/giprobe.glsl index a723490e8b2..d7560583564 100644 --- a/servers/visual/rasterizer_rd/shaders/giprobe.glsl +++ b/servers/visual/rasterizer_rd/shaders/giprobe.glsl @@ -4,8 +4,18 @@ VERSION_DEFINES +#ifdef MODE_DYNAMIC + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#else + layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; +#endif + +#ifndef MODE_DYNAMIC + #define NO_CHILDREN 0xFFFFFFFF #define GREY_VEC vec3(0.33333,0.33333,0.33333) @@ -28,11 +38,14 @@ layout(set=0,binding=2,std430) buffer CellDataBuffer { CellData data[]; } cell_data; + +#endif // MODE DYNAMIC + #define LIGHT_TYPE_DIRECTIONAL 0 #define LIGHT_TYPE_OMNI 1 #define LIGHT_TYPE_SPOT 2 -#ifdef MODE_COMPUTE_LIGHT +#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING) struct Light { @@ -64,7 +77,6 @@ layout(set=0,binding=3,std140) uniform Lights { #ifdef MODE_SECOND_BOUNCE layout (set=0,binding=5) uniform texture3D color_texture; -layout (set=0,binding=6) uniform sampler texture_sampler; #ifdef MODE_ANISOTROPIC layout (set=0,binding=7) uniform texture3D aniso_pos_texture; @@ -73,6 +85,7 @@ layout (set=0,binding=8) uniform texture3D aniso_neg_texture; #endif // MODE_SECOND_BOUNCE +#ifndef MODE_DYNAMIC layout(push_constant, binding = 0, std430) uniform Params { @@ -96,6 +109,11 @@ layout(set=0,binding=4,std430) buffer Outputs { vec4 data[]; } outputs; +#endif // MODE DYNAMIC + +layout (set=0,binding=9) uniform texture3D texture_sdf; +layout (set=0,binding=10) uniform sampler texture_sampler; + #ifdef MODE_WRITE_TEXTURE layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex; @@ -111,63 +129,97 @@ layout (r16ui,set=0,binding=7) uniform restrict writeonly uimage3D aniso_neg_tex #endif -#ifdef MODE_COMPUTE_LIGHT +#ifdef MODE_DYNAMIC -uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) { +layout(push_constant, binding = 0, std430) uniform Params { - uint result = NO_CHILDREN; + ivec3 limits; + uint light_count; + ivec3 x_dir; + float z_base; + ivec3 y_dir; + float z_sign; + ivec3 z_dir; + float pos_multiplier; + ivec2 rect_pos; + ivec2 rect_size; + ivec2 prev_rect_ofs; + ivec2 prev_rect_size; + bool flip_x; + bool flip_y; + float dynamic_range; + bool keep_downsample_color; - ivec3 size = ivec3(max(max(params.limits.x,params.limits.y),params.limits.z)); +} params; - while (distance > -distance_adv) { //use this to avoid precision errors +#ifdef MODE_DYNAMIC_LIGHTING - uint cell = 0; +layout (rgba8,set=0,binding=5) uniform restrict readonly image2D source_albedo; +layout (rgba8,set=0,binding=6) uniform restrict readonly image2D source_normal; +layout (rgba8,set=0,binding=7) uniform restrict readonly image2D source_orm; +//layout (set=0,binding=8) uniform texture2D source_depth; +layout (rgba16f,set=0,binding=11) uniform restrict image2D emission; +layout (r32f,set=0,binding=12) uniform restrict image2D depth; - ivec3 pos = ivec3(from); +#endif - if (all(greaterThanEqual(pos,ivec3(0))) && all(lessThan(pos,size))) { +#ifdef MODE_DYNAMIC_SHRINK - ivec3 ofs = ivec3(0); - ivec3 half_size = size / 2; +layout (rgba16f,set=0,binding=5) uniform restrict readonly image2D source_light; +layout (r32f,set=0,binding=6) uniform restrict readonly image2D source_depth; - for (int i = 0; i < params.stack_size - 1; i++) { +#ifdef MODE_DYNAMIC_SHRINK_WRITE - bvec3 greater = greaterThanEqual(pos,ofs+half_size); +layout (rgba16f,set=0,binding=7) uniform restrict writeonly image2D light; +layout (r32f,set=0,binding=8) uniform restrict writeonly image2D depth; - ofs += mix(ivec3(0),half_size,greater); +#endif // MODE_DYNAMIC_SHRINK_WRITE - uint child = 0; //wonder if this can be done faster - if (greater.x) { - child|=1; - } - if (greater.y) { - child|=2; - } - if (greater.z) { - child|=4; - } +#ifdef MODE_DYNAMIC_SHRINK_PLOT - cell = cell_children.data[cell].children[child]; - if (cell == NO_CHILDREN) - break; +layout (rgba8,set=0,binding=11) uniform restrict image3D color_texture; - half_size >>= ivec3(1); - } +#ifdef MODE_ANISOTROPIC - if ( cell != NO_CHILDREN) { - return cell; //found cell! - } +layout (r16ui,set=0,binding=12) uniform restrict writeonly uimage3D aniso_pos_texture; +layout (r16ui,set=0,binding=13) uniform restrict writeonly uimage3D aniso_neg_texture; +#endif // MODE ANISOTROPIC + +#endif //MODE_DYNAMIC_SHRINK_PLOT + +#endif // MODE_DYNAMIC_SHRINK + +//layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex; + + +#endif // MODE DYNAMIC + +#if defined(MODE_COMPUTE_LIGHT) || defined(MODE_DYNAMIC_LIGHTING) + +float raymarch(float distance,float distance_adv,vec3 from,vec3 direction) { + + + + vec3 cell_size = 1.0 / vec3(params.limits); + + while (distance > 0.0) { //use this to avoid precision errors + float advance = texture(sampler3D(texture_sdf,texture_sampler),from * cell_size).r * 255.0 - 1.0; + if (advance<0.0) { + break; } - from += direction * distance_adv; - distance -= distance_adv; + advance = max(distance_adv, advance - mod(advance, distance_adv)); //should always advance in multiples of distance_adv + + from += direction * advance; + distance -= advance; } - return NO_CHILDREN; + return max(0.0,distance); + } -bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) { +bool compute_light_vector(uint light, vec3 pos,out float attenuation, out vec3 light_pos) { if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) { @@ -226,13 +278,84 @@ float get_normal_advance(vec3 p_normal) { return 1.0 / dot(normal,unorm); } -#endif +void clip_segment(vec4 plane, vec3 begin, inout vec3 end) { + + vec3 segment = begin - end; + float den = dot(plane.xyz,segment); + + //printf("den is %i\n",den); + if (den < 0.0001) { + return; + } + + float dist = (dot(plane.xyz,begin) - plane.w) / den; + + if (dist < 0.0001 || dist > 1.0001) { + return; + } + + end = begin + segment * -dist; +} + +bool compute_light_at_pos(uint index, vec3 pos, vec3 normal, inout vec3 light, inout vec3 light_dir) { + float attenuation; + vec3 light_pos; + + if (!compute_light_vector(index,pos,attenuation,light_pos)) { + return false; + } + + light_dir = normalize(pos - light_pos); + + if (attenuation < 0.01 || (length(normal) > 0.2 && dot(normal,light_dir)>=0)) { + return false; //not facing the light, or attenuation is near zero + } + + if (lights.data[index].has_shadow) { + + float distance_adv = get_normal_advance(light_dir); + + + vec3 to = pos; + to-= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion + + //clip + clip_segment(mix(vec4(-1.0,0.0,0.0,0.0),vec4(1.0,0.0,0.0,float(params.limits.x-1)),bvec4(light_dir.x < 0.0)),to,light_pos); + clip_segment(mix(vec4(0.0,-1.0,0.0,0.0),vec4(0.0,1.0,0.0,float(params.limits.y-1)),bvec4(light_dir.y < 0.0)),to,light_pos); + clip_segment(mix(vec4(0.0,0.0,-1.0,0.0),vec4(0.0,0.0,1.0,float(params.limits.z-1)),bvec4(light_dir.z < 0.0)),to,light_pos); + + + float distance = length(to-light_pos); + if (distance < 0.1) { + return false; // hit + } + + distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always + light_pos = to - light_dir * distance; + + //from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion + float dist = raymarch(distance,distance_adv,light_pos,light_dir); + + if (dist > distance_adv) { + return false; + } + + + } + + light = lights.data[index].color * attenuation * lights.data[index].energy; + return true; +} + +#endif // MODE COMPUTE LIGHT void main() { +#ifndef MODE_DYNAMIC + uint cell_index = gl_GlobalInvocationID.x;; if (cell_index >= params.cell_count) { return; @@ -242,6 +365,8 @@ void main() { uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21); vec4 albedo = unpackUnorm4x8(cell_data.data[cell_index].albedo); +#endif + /////////////////COMPUTE LIGHT/////////////////////////////// #ifdef MODE_COMPUTE_LIGHT @@ -249,7 +374,7 @@ void main() { vec3 pos = vec3(posu) + vec3(0.5); vec3 emission = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0); - vec4 normal = unpackSnorm4x8(cell_data.data[cell_index].normal); + vec3 normal = unpackSnorm4x8(cell_data.data[cell_index].normal).xyz; #ifdef MODE_ANISOTROPIC vec3 accum[6]=vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0)); @@ -260,41 +385,13 @@ void main() { for(uint i=0;i 0.2 && dot(normal.xyz,light_dir)>=0)) { - continue; //not facing the light, or attenuation is near zero - } - - if (lights.data[i].has_shadow) { - - float distance_adv = get_normal_advance(light_dir); - - - distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always - - vec3 from = pos - light_dir * distance; //approximate - from -= sign(light_dir)*0.45; //go near the edge towards the light direction to avoid self occlusion - - - - uint result = raymarch(distance,distance_adv,from,light_dir); - - if (result != cell_index) { - continue; //was occluded - } - } - - vec3 light = lights.data[i].color * albedo.rgb * attenuation * lights.data[i].energy; + light*= albedo.rgb; #ifdef MODE_ANISOTROPIC for(uint j=0;j<6;j++) { @@ -302,11 +399,11 @@ void main() { accum[j]+=max(0.0,dot(accum_dirs[j],-light_dir))*light; } #else - if (length(normal.xyz) > 0.2) { - accum+=max(0.0,dot(normal.xyz,-light_dir))*light; + if (length(normal) > 0.2) { + accum+=max(0.0,dot(normal,-light_dir))*light; } else { //all directions - accum+=light+emission; + accum+=light; } #endif } @@ -314,12 +411,17 @@ void main() { #ifdef MODE_ANISOTROPIC - outputs.data[cell_index*6+0]=vec4(accum[0] + emission,0.0); - outputs.data[cell_index*6+1]=vec4(accum[1] + emission,0.0); - outputs.data[cell_index*6+2]=vec4(accum[2] + emission,0.0); - outputs.data[cell_index*6+3]=vec4(accum[3] + emission,0.0); - outputs.data[cell_index*6+4]=vec4(accum[4] + emission,0.0); - outputs.data[cell_index*6+5]=vec4(accum[5] + emission,0.0); + for(uint i=0;i<6;i++) { + vec3 light = accum[i]; + if (length(normal) > 0.2) { + light += max(0.0,dot(accum_dirs[i],-normal)) * emission; + } else { + light += emission; + } + + outputs.data[cell_index*6+i] = vec4(light,0.0); + } + #else outputs.data[cell_index]=vec4(accum + emission,0.0); @@ -540,4 +642,167 @@ void main() { } #endif + +///////////////////DYNAMIC LIGHTING///////////////////////////// + +#ifdef MODE_DYNAMIC + + ivec2 pos_xy = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(pos_xy,params.rect_size))) { + return; //out of bounds + } + + ivec2 uv_xy = pos_xy; + if (params.flip_x) { + uv_xy.x = params.rect_size.x - pos_xy.x - 1; + } + if (params.flip_y) { + uv_xy.y = params.rect_size.y - pos_xy.y - 1; + } + + +#ifdef MODE_DYNAMIC_LIGHTING + + + { + + + float z = params.z_base + imageLoad(depth,uv_xy).x * params.z_sign; + + ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) + abs(params.z_dir) * int(z); + + vec3 normal = imageLoad(source_normal,uv_xy).xyz * 2.0 - 1.0; + normal = vec3(params.x_dir) * normal.x * mix(1.0,-1.0,params.flip_x) + vec3(params.y_dir) * normal.y * mix(1.0,-1.0,params.flip_y) - vec3(params.z_dir) * normal.z; + + + + + vec4 albedo = imageLoad(source_albedo,uv_xy); + + //determine the position in space + + vec3 accum = vec3(0.0); + for(uint i=0;i>1) - params.prev_rect_ofs; + if (any(lessThan(ofs,ivec2(0))) || any(greaterThanEqual(ofs,params.prev_rect_size))) { + continue; + } + if (params.flip_x) { + ofs.x = params.prev_rect_size.x - ofs.x - 1; + } + if (params.flip_y) { + ofs.y = params.prev_rect_size.y - ofs.y - 1; + } + + vec4 light = imageLoad(source_light,ofs); + if (light.a==0.0) { //ignore empty + continue; + } + accum += light; + float z = imageLoad(source_depth,ofs).x; + accum_z += z*0.5; //shrink half too + count+=1.0; + } + + + accum/=4.0; + + if (count==0.0) { + accum_z=0.0; //avoid nan + } else { + accum_z/=count; + } + +#ifdef MODE_DYNAMIC_SHRINK_WRITE + + imageStore(light,uv_xy,accum); + imageStore(depth,uv_xy,vec4(accum_z)); +#endif + +#ifdef MODE_DYNAMIC_SHRINK_PLOT + + + if (accum.a<0.001) { + return; //do not blit if alpha is too low + } + + ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) + abs(params.z_dir) * int(accum_z); + + float z_frac = fract(accum_z); + + for(int i = 0; i< 2; i++) { + ivec3 pos3d = pos + abs(params.z_dir) * i; + if (any(lessThan(pos3d,ivec3(0))) || any(greaterThanEqual(pos3d,params.limits))) { + //skip if offlimits + continue; + } + vec4 color_blit = accum * (i==0 ? 1.0 - z_frac : z_frac ); + vec4 color = imageLoad(color_texture,pos3d); + color.rgb *=params.dynamic_range; + +#if 0 + color.rgb = mix(color.rgb,color_blit.rgb,color_blit.a); + color.a+=color_blit.a; +#else + + + float sa = 1.0 - color_blit.a; + vec4 result; + result.a = color.a * sa + color_blit.a; + if (result.a==0.0) { + result = vec4(0.0); + } else { + result.rgb = (color.rgb * color.a * sa + color_blit.rgb * color_blit.a) / result.a; + color = result; + } + +#endif + color.rgb /= params.dynamic_range; + imageStore(color_texture,pos3d,color); + //imageStore(color_texture,pos3d,vec4(1,1,1,1)); + +#ifdef MODE_ANISOTROPIC + //do not care about anisotropy for dynamic objects, just store full lit in all directions + imageStore(aniso_pos_texture,pos3d,uvec4(0xFFFF)); + imageStore(aniso_neg_texture,pos3d,uvec4(0xFFFF)); + +#endif // ANISOTROPIC + } +#endif // MODE_DYNAMIC_SHRINK_PLOT + + + } +#endif + +#endif // MODE DYNAMIC } diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl index 71ecaffde7a..7218d2da3a5 100644 --- a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl +++ b/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl @@ -32,6 +32,8 @@ layout(push_constant, binding = 0, std430) uniform Params { float dynamic_range; float alpha; uint level; + ivec3 bounds; + uint pad; } params; @@ -80,10 +82,13 @@ void main() { vec3 vertex = cube_triangles[gl_VertexIndex] * 0.5 + 0.5; - +#ifdef MODE_DEBUG_LIGHT_FULL + uvec3 posu = uvec3( gl_InstanceIndex % params.bounds.x, (gl_InstanceIndex / params.bounds.x) % params.bounds.y,gl_InstanceIndex / (params.bounds.y * params.bounds.x) ); +#else uint cell_index = gl_InstanceIndex + params.cell_offset; uvec3 posu = uvec3(cell_data.data[cell_index].position&0x7FF,(cell_data.data[cell_index].position>>11)&0x3FF,cell_data.data[cell_index].position>>21); +#endif #ifdef MODE_DEBUG_EMISSION color_interp.xyz = vec3(uvec3(cell_data.data[cell_index].emission & 0x1ff,(cell_data.data[cell_index].emission >> 9) & 0x1ff,(cell_data.data[cell_index].emission >> 18) & 0x1ff)) * pow(2.0, float(cell_data.data[cell_index].emission >> 27) - 15.0 - 9.0); @@ -138,16 +143,24 @@ void main() { color_interp.xyz *= strength; #else - color_interp.xyz = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)).xyz * params.dynamic_range; + color_interp = texelFetch(sampler3D(color_tex,tex_sampler),ivec3(posu),int(params.level)); + color_interp.xyz * params.dynamic_range; #endif #endif float scale = (1<>11)&0x3FF,cell_data.data[i].position>>21)); + float dist = length(pos-posu); + if (dist < closest_dist) { + closest_dist = dist; + } + } + + uint dist_8; + + if (closest_dist<0.0001) { // same cell + dist_8=0; //equals to -1 + } else { + dist_8 = clamp(uint(closest_dist),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid + } + + imageStore(sdf_tex,ivec3(gl_GlobalInvocationID),uvec4(dist_8)); + //imageStore(sdf_tex,pos,uvec4(pos*2,0)); +} + + +#if 0 +layout(push_constant, binding = 0, std430) uniform Params { + + ivec3 limits; + uint stack_size; +} params; + + +float distance_to_aabb(ivec3 pos, ivec3 aabb_pos, ivec3 aabb_size) { + + vec3 delta = vec3(max(ivec3(0),max(aabb_pos - pos, pos - (aabb_pos + aabb_size - ivec3(1))))); + return length(delta); +} + +void main() { + + ivec3 pos = ivec3(gl_GlobalInvocationID); + + uint stack[10]=uint[](0,0,0,0,0,0,0,0,0,0); + uint stack_indices[10]=uint[](0,0,0,0,0,0,0,0,0,0); + ivec3 stack_positions[10]=ivec3[](ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0),ivec3(0)); + + const uint cell_orders[8]=uint[]( + 0x11f58d1, + 0xe2e70a, + 0xd47463, + 0xbb829c, + 0x8d11f5, + 0x70ae2e, + 0x463d47, + 0x29cbb8 + ); + + bool cell_found = false; + bool cell_found_exact = false; + ivec3 closest_cell_pos; + float closest_distance = MAX_DISTANCE; + int stack_pos = 0; + + while(true) { + + uint index = stack_indices[stack_pos]>>24; + + if (index == 8) { + //go up + if (stack_pos==0) { + break; //done going through octree + } + stack_pos--; + continue; + } + + stack_indices[stack_pos] = (stack_indices[stack_pos]&((1<<24)-1))|((index + 1)<<24); + + + uint cell_index = (stack_indices[stack_pos]>>(index*3))&0x7; + uint child_cell = cell_children.data[stack[stack_pos]].children[cell_index]; + + if (child_cell == NO_CHILDREN) { + continue; + } + + ivec3 child_cell_size = params.limits >> (stack_pos+1); + ivec3 child_cell_pos = stack_positions[stack_pos]; + + child_cell_pos+=mix(ivec3(0),child_cell_size,bvec3(uvec3(index&1,index&2,index&4)!=uvec3(0))); + + bool is_leaf = stack_pos == (params.stack_size-2); + + if (child_cell_pos==pos && is_leaf) { + //we may actually end up in the exact cell. + //if this happens, just abort + cell_found_exact=true; + break; + } + + if (cell_found) { + //discard by distance + float distance = distance_to_aabb(pos,child_cell_pos,child_cell_size); + if (distance >= closest_distance) { + continue; //pointless, just test next child + } else if (is_leaf) { + //closer than what we have AND end of stack, save and continue + closest_cell_pos = child_cell_pos; + closest_distance = distance; + continue; + } + } else if (is_leaf) { + //first solid cell we find, save and continue + closest_distance = distance_to_aabb(pos,child_cell_pos,child_cell_size); + closest_cell_pos = child_cell_pos; + cell_found=true; + continue; + } + + + + + bvec3 direction = greaterThan(( pos - ( child_cell_pos + (child_cell_size >>1) ) ) , ivec3(0) ); + uint cell_order = 0; + cell_order|=mix(0,1,direction.x); + cell_order|=mix(0,2,direction.y); + cell_order|=mix(0,4,direction.z); + + stack[stack_pos+1]=child_cell; + stack_indices[stack_pos+1]=cell_orders[cell_order]; //start counting + stack_positions[stack_pos+1]=child_cell_pos; + stack_pos++; //go up stack + + } + + uint dist_8; + + if (cell_found_exact) { + dist_8=0; //equals to -1 + } else { + float closest_distance = length(vec3(pos-closest_cell_pos)); + dist_8 = clamp(uint(closest_distance),0,254) + 1; //conservative, 0 is 1, so <1 is considered solid + } + + imageStore(sdf_tex,pos,uvec4(dist_8)); + +} +#endif diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl index a54a84536a9..1ffccdc4ee3 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl @@ -344,17 +344,30 @@ FRAGMENT_SHADER_GLOBALS /* clang-format on */ +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MATERIAL + +layout(location = 0) out vec4 albedo_output_buffer; +layout(location = 1) out vec4 normal_output_buffer; +layout(location = 2) out vec4 orm_output_buffer; +layout(location = 3) out vec4 emission_output_buffer; +layout(location = 4) out float depth_output_buffer; + +#endif + +#else // RENDER DEPTH + #ifdef MODE_MULTIPLE_RENDER_TARGETS layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) #else -#ifndef MODE_RENDER_DEPTH layout(location = 0) out vec4 frag_color; #endif -#endif +#endif // RENDER DEPTH @@ -1668,6 +1681,29 @@ FRAGMENT_SHADER_CODE #ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MATERIAL + + albedo_output_buffer.rgb = albedo; + albedo_output_buffer.a = alpha; + + normal_output_buffer.rgb = normal * 0.5 + 0.5; + normal_output_buffer.a = 0.0; + depth_output_buffer.r = -vertex.z; + +#if defined(AO_USED) + orm_output_buffer.r = ao; +#else + orm_output_buffer.r = 0.0; +#endif + orm_output_buffer.g = roughness; + orm_output_buffer.b = metallic; + orm_output_buffer.a = sss_strength; + + emission_output_buffer.rgb = emission; + emission_output_buffer.a = 0.0; +#endif + //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 8d38cf02b3e..1ce4f47d75e 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -170,7 +170,12 @@ void *VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance pinfo.geometry = A; pinfo.L = geom->gi_probes.push_back(B); - List::Element *E = gi_probe->geometries.push_back(pinfo); + List::Element *E; + if (A->dynamic_gi) { + E = gi_probe->dynamic_geometries.push_back(pinfo); + } else { + E = gi_probe->geometries.push_back(pinfo); + } geom->gi_probes_dirty = true; @@ -240,7 +245,11 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance List::Element *E = reinterpret_cast::Element *>(udata); geom->gi_probes.erase(E->get().L); - gi_probe->geometries.erase(E); + if (A->dynamic_gi) { + gi_probe->dynamic_geometries.erase(E); + } else { + gi_probe->geometries.erase(E); + } geom->gi_probes_dirty = true; @@ -842,12 +851,32 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF Instance *instance = instance_owner.getornull(p_instance); ERR_FAIL_COND(!instance); + ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK)); + switch (p_flags) { case VS::INSTANCE_FLAG_USE_BAKED_LIGHT: { instance->baked_light = p_enabled; + } break; + case VS::INSTANCE_FLAG_USE_DYNAMIC_GI: { + + if (p_enabled == instance->dynamic_gi) { + //bye, redundant + return; + } + + if (instance->octree_id != 0) { + //remove from octree, it needs to be re-paired + instance->scenario->octree.erase(instance->octree_id); + instance->octree_id = 0; + _instance_queue_update(instance, true, true); + } + + //once out of octree, can be changed + instance->dynamic_gi = p_enabled; + } break; case VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { @@ -2431,7 +2460,7 @@ void VisualServerScene::render_probes() { cache_count = idx; } - bool update_probe = VSG::scene_render->gi_probe_needs_update(probe->probe_instance); + bool update_lights = VSG::scene_render->gi_probe_needs_update(probe->probe_instance); if (cache_dirty) { probe->light_cache.resize(cache_count); @@ -2490,13 +2519,37 @@ void VisualServerScene::render_probes() { } } - update_probe = true; + update_lights = true; } - if (update_probe) { - VSG::scene_render->gi_probe_update(probe->probe_instance, probe->light_instances); + instance_cull_count = 0; + for (List::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { + if (instance_cull_count < MAX_INSTANCE_CULL) { + Instance *ins = E->get().geometry; + InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; + + if (geom->gi_probes_dirty) { + //giprobes may be dirty, so update + int l = 0; + //only called when reflection probe AABB enter/exit this geometry + ins->gi_probe_instances.resize(geom->gi_probes.size()); + + for (List::Element *F = geom->gi_probes.front(); F; F = F->next()) { + + InstanceGIProbeData *gi_probe2 = static_cast(F->get()->base_data); + + ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance; + } + + geom->gi_probes_dirty = false; + } + + instance_cull_result[instance_cull_count++] = E->get().geometry; + } } + VSG::scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RasterizerScene::InstanceBase **)instance_cull_result); + gi_probe_update_list.remove(gi_probe); gi_probe = next; diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index b4ff26653bf..3034d06d6b7 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -156,8 +156,6 @@ public: SelfList update_item; - AABB aabb; - AABB transformed_aabb; AABB *custom_aabb; // would using aabb directly with a bool be better? float extra_margin; uint32_t object_id; @@ -316,6 +314,7 @@ public: }; List geometries; + List dynamic_geometries; Set lights; diff --git a/servers/visual_server.h b/servers/visual_server.h index 3523afc3050..deab05b4da4 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -834,6 +834,7 @@ public: enum InstanceFlags { INSTANCE_FLAG_USE_BAKED_LIGHT, + INSTANCE_FLAG_USE_DYNAMIC_GI, INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, INSTANCE_FLAG_MAX };