diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 9018a78c5715..070616f06196 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -512,6 +512,28 @@ CameraMatrix CameraMatrix::operator*(const CameraMatrix &p_matrix) const { return new_matrix; } +void CameraMatrix::set_depth_correction() { + + real_t *m = &matrix[0][0]; + + m[0] = 1; + m[1] = 0.0; + m[2] = 0.0; + m[3] = 0.0; + m[4] = 0.0; + m[5] = -1; + m[6] = 0.0; + m[7] = 0.0; + m[8] = 0.0; + m[9] = 0.0; + m[10] = 0.5; + m[11] = 0.0; + m[12] = 0.0; + m[13] = 0.0; + m[14] = 0.5; + m[15] = 1.0; +} + void CameraMatrix::set_light_bias() { real_t *m = &matrix[0][0]; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index a7a85fee8dc2..2a2510936790 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -50,6 +50,7 @@ struct CameraMatrix { void set_identity(); void set_zero(); void set_light_bias(); + void set_depth_correction(); void set_light_atlas_rect(const Rect2 &p_rect); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 474bbce1d652..e30bcfdd2c8a 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -216,7 +216,7 @@ public: /* SHADOW ATLAS API */ - struct ShadowAtlas { + struct ShadowAtlas { enum { QUADRANT_SHIFT = 27, @@ -288,7 +288,7 @@ public: /* REFLECTION PROBE ATLAS API */ - struct ReflectionAtlas { + struct ReflectionAtlas { int subdiv; int size; @@ -307,8 +307,7 @@ public: mutable RID_PtrOwner reflection_atlas_owner; virtual RID reflection_atlas_create(); - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_size); - virtual void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv); + virtual void reflection_atlas_configure(RID p_ref_atlas, int p_size, int p_count); /* REFLECTION CUBEMAPS */ @@ -324,7 +323,7 @@ public: /* REFLECTION PROBE INSTANCE */ - struct ReflectionProbeInstance { + struct ReflectionProbeInstance { RasterizerStorageGLES3::ReflectionProbe *probe_ptr; RID probe; @@ -364,7 +363,7 @@ public: /* ENVIRONMENT API */ - struct Environment { + struct Environment { VS::EnvironmentBG bg_mode; @@ -590,7 +589,7 @@ public: float shadow_split_offsets[4]; }; - struct LightInstance { + struct LightInstance { struct ShadowTransform { @@ -639,7 +638,7 @@ public: /* REFLECTION INSTANCE */ - struct GIProbeInstance { + struct GIProbeInstance { RID data; RasterizerStorageGLES3::GIProbe *probe; GLuint tex_cache; diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index a89183d1ccfd..8cc07c59b1a3 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1497,6 +1497,23 @@ void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mas vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL); } + +void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { + + VkBufferMemoryBarrier buffer_mem_barrier; + buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + buffer_mem_barrier.pNext = NULL; + buffer_mem_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_mem_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_mem_barrier.srcAccessMask = p_src_access; + buffer_mem_barrier.dstAccessMask = p_dst_sccess; + buffer_mem_barrier.buffer = buffer; + buffer_mem_barrier.offset = p_from; + buffer_mem_barrier.size = p_size; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 0, NULL, 1, &buffer_mem_barrier, 0, NULL); +} + /*****************/ /**** TEXTURE ****/ /*****************/ @@ -1715,7 +1732,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { - texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } else { texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } @@ -2526,6 +2543,9 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER, + "Source and destination texture must be of the same type (color or depth)."); + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; { @@ -2586,7 +2606,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_copy_region.srcOffset.y = p_from.y; image_copy_region.srcOffset.z = p_from.z; - image_copy_region.dstSubresource.aspectMask = src_tex->barrier_aspect_mask; + image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask; image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer; image_copy_region.dstSubresource.layerCount = 1; image_copy_region.dstSubresource.mipLevel = p_dst_mipmap; @@ -2712,6 +2732,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); } return vertex_buffer_owner.make_rid(buffer); @@ -3223,7 +3246,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&index_buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); + _buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); } return index_buffer_owner.make_rid(index_buffer); } @@ -3934,7 +3957,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); } return uniform_buffer_owner.make_rid(buffer); } @@ -3953,7 +3976,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); } return storage_buffer_owner.make_rid(buffer); } @@ -3976,7 +3999,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&texture_buffer.buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); + _buffer_memory_barrier(texture_buffer.buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); } VkBufferViewCreateInfo view_create_info; @@ -4400,7 +4423,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]); ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); - ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), + //if 0, then its sized on link time + ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); write.dstArrayElement = 0; @@ -4523,8 +4547,47 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint return err; } - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); + _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); +#if 0 + if (p_sync_with_draw) { + VkMemoryBarrier memoryBarrier; + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + memoryBarrier.pNext = NULL; + memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, NULL, 0, NULL); + } +#endif return err; } @@ -5145,6 +5208,47 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff return OK; } +void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, const Vector &p_clear_colors) { + Vector clear_attachments; + int color_index = 0; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + VkClearAttachment clear_at; + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + ERR_FAIL_INDEX(color_index, p_clear_colors.size()); //a bug + Color clear_color = p_clear_colors[color_index]; + clear_at.clearValue.color.float32[0] = clear_color.r; + clear_at.clearValue.color.float32[1] = clear_color.g; + clear_at.clearValue.color.float32[2] = clear_color.b; + clear_at.clearValue.color.float32[3] = clear_color.a; + clear_at.colorAttachment = color_index++; + clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + clear_at.clearValue.depthStencil.depth = 1.0; + clear_at.clearValue.depthStencil.stencil = 0; + clear_at.colorAttachment = 0; + clear_at.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (format_has_stencil(texture->format)) { + clear_at.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + ERR_CONTINUE(true); + } + clear_attachments.push_back(clear_at); + } + + VkClearRect cr; + cr.baseArrayLayer = 0; + cr.layerCount = 1; + cr.rect.offset.x = viewport_offset.x; + cr.rect.offset.y = viewport_offset.y; + cr.rect.extent.width = viewport_size.width; + cr.rect.extent.height = viewport_size.height; + + vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr); +} + RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { _THREAD_SAFE_METHOD_ @@ -5154,8 +5258,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu Point2i viewport_offset; Point2i viewport_size = framebuffer->size; + bool needs_clear_region = false; - if (p_region != Rect2()) { //check custom region + if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region Rect2i viewport(viewport_offset, viewport_size); Rect2i regioni = p_region; if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && @@ -5166,6 +5271,11 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu viewport_offset = regioni.position; viewport_size = regioni.size; + + if (p_initial_action == INITIAL_ACTION_CLEAR) { + p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH; + needs_clear_region = true; + } } if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values @@ -5196,6 +5306,10 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu draw_list_count = 0; draw_list_split = false; + if (needs_clear_region) { + _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, p_clear_colors); + } + VkViewport viewport; viewport.x = viewport_offset.x; viewport.y = viewport_offset.y; @@ -5230,7 +5344,9 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p Point2i viewport_offset; Point2i viewport_size = framebuffer->size; - if (p_region != Rect2()) { //check custom region + bool needs_clear_region = false; + + if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region Rect2i viewport(viewport_offset, viewport_size); Rect2i regioni = p_region; if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && @@ -5241,6 +5357,11 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p viewport_offset = regioni.position; viewport_size = regioni.size; + + if (p_initial_action == INITIAL_ACTION_CLEAR) { + p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH; + needs_clear_region = true; + } } if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values @@ -5340,6 +5461,9 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p #ifdef DEBUG_ENABLED draw_list[i].validation.framebuffer_format = framebuffer->format_id; #endif + if (i == 0 && needs_clear_region) { + _draw_list_insert_clear_region(&draw_list[i], framebuffer, viewport_offset, viewport_size, p_clear_colors); + } VkViewport viewport; viewport.x = viewport_offset.x; @@ -5754,6 +5878,11 @@ void RenderingDeviceVulkan::draw_list_end() { } } draw_list_bound_textures.clear(); + + // To ensure proper synchronization, we must make sure rendering is done before: + // * Some buffer is copied + // * Another render pass happens (since we may be done + _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); } #if 0 void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors) { diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index d9fb65bb474e..c4e5b789bd55 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -216,6 +216,7 @@ class RenderingDeviceVulkan : public RenderingDevice { Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32); void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw); + void _buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw); /*********************/ /**** FRAMEBUFFER ****/ @@ -790,6 +791,7 @@ class RenderingDeviceVulkan : public RenderingDevice { Vector draw_list_bound_textures; bool draw_list_unbind_textures; + void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, const Vector &p_clear_colors); Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass); Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents); _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id); diff --git a/main/main.cpp b/main/main.cpp index 02c90ce1eefd..fdc94fd896ab 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1753,6 +1753,12 @@ bool Main::start() { } #endif + { + + int directional_atlas_size = GLOBAL_GET("rendering/quality/directional_shadow/size"); + VisualServer::get_singleton()->directional_shadow_atlas_set_size(directional_atlas_size); + } + if (!editor && !project_manager) { //standard helpers that can be changed from main config diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 593d0b95b786..a64678333339 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -431,42 +431,24 @@ OmniLight::ShadowMode OmniLight::get_shadow_mode() const { return shadow_mode; } -void OmniLight::set_shadow_detail(ShadowDetail p_detail) { - - shadow_detail = p_detail; - VS::get_singleton()->light_omni_set_shadow_detail(light, VS::LightOmniShadowDetail(p_detail)); -} -OmniLight::ShadowDetail OmniLight::get_shadow_detail() const { - - return shadow_detail; -} - void OmniLight::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &OmniLight::set_shadow_mode); ClassDB::bind_method(D_METHOD("get_shadow_mode"), &OmniLight::get_shadow_mode); - ClassDB::bind_method(D_METHOD("set_shadow_detail", "detail"), &OmniLight::set_shadow_detail); - ClassDB::bind_method(D_METHOD("get_shadow_detail"), &OmniLight::get_shadow_detail); - ADD_GROUP("Omni", "omni_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_detail", PROPERTY_HINT_ENUM, "Vertical,Horizontal"), "set_shadow_detail", "get_shadow_detail"); BIND_ENUM_CONSTANT(SHADOW_DUAL_PARABOLOID); BIND_ENUM_CONSTANT(SHADOW_CUBE); - - BIND_ENUM_CONSTANT(SHADOW_DETAIL_VERTICAL); - BIND_ENUM_CONSTANT(SHADOW_DETAIL_HORIZONTAL); } OmniLight::OmniLight() : Light(VisualServer::LIGHT_OMNI) { set_shadow_mode(SHADOW_CUBE); - set_shadow_detail(SHADOW_DETAIL_HORIZONTAL); } String SpotLight::get_configuration_warning() const { diff --git a/scene/3d/light.h b/scene/3d/light.h index 272ee8d7a9f4..e7bfa3fc6344 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -183,15 +183,8 @@ public: SHADOW_CUBE, }; - // omni light - enum ShadowDetail { - SHADOW_DETAIL_VERTICAL, - SHADOW_DETAIL_HORIZONTAL - }; - private: ShadowMode shadow_mode; - ShadowDetail shadow_detail; protected: static void _bind_methods(); @@ -200,14 +193,10 @@ public: void set_shadow_mode(ShadowMode p_mode); ShadowMode get_shadow_mode() const; - void set_shadow_detail(ShadowDetail p_detail); - ShadowDetail get_shadow_detail() const; - OmniLight(); }; VARIANT_ENUM_CAST(OmniLight::ShadowMode) -VARIANT_ENUM_CAST(OmniLight::ShadowDetail) class SpotLight : public Light { diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 67a39a6b2257..f7c392f8c574 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -2075,14 +2075,10 @@ SceneTree::SceneTree() { int ref_atlas_size = GLOBAL_DEF("rendering/quality/reflections/atlas_size", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/reflections/atlas_size", PropertyInfo(Variant::INT, "rendering/quality/reflections/atlas_size", PROPERTY_HINT_RANGE, "0,8192,or_greater")); //next_power_of_2 will return a 0 as min value - int ref_atlas_subdiv = GLOBAL_DEF("rendering/quality/reflections/atlas_subdiv", 8); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/reflections/atlas_subdiv", PropertyInfo(Variant::INT, "rendering/quality/reflections/atlas_subdiv", PROPERTY_HINT_RANGE, "0,32,or_greater")); //next_power_of_2 will return a 0 as min value int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x")); root->set_msaa(Viewport::MSAA(msaa_mode)); - VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(), ref_atlas_size, ref_atlas_subdiv); - { //load default fallback environment //get possible extensions List exts; diff --git a/servers/visual/rasterizer.cpp b/servers/visual/rasterizer.cpp index 64b5c886992c..a3f93a3f8c8c 100644 --- a/servers/visual/rasterizer.cpp +++ b/servers/visual/rasterizer.cpp @@ -47,6 +47,8 @@ void RasterizerScene::InstanceDependency::instance_notify_deleted(RID p_deleted) for (Map::Element *E = instances.front(); E; E = E->next()) { E->key()->dependencies.erase(this); } + + instances.clear(); } RasterizerScene::InstanceDependency::~InstanceDependency() { diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index c6517a12ed39..7423d3ca384c 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -46,6 +46,7 @@ public: virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0; + virtual void directional_shadow_atlas_set_size(int p_size) = 0; virtual int get_directional_light_shadow_size(RID p_light_intance) = 0; virtual void set_directional_shadow_count(int p_count) = 0; @@ -107,18 +108,11 @@ public: Map instances; }; - struct InstanceCustomData { - - virtual ~InstanceCustomData() {} - }; - struct InstanceBase { VS::InstanceType base_type; RID base; - InstanceCustomData *custom_data; - RID skeleton; RID material_override; @@ -201,7 +195,6 @@ public: InstanceBase() : dependency_item(this) { - custom_data = nullptr; base_type = VS::INSTANCE_NONE; cast_shadows = VS::SHADOW_CASTING_SETTING_ON; receive_shadows = true; @@ -215,9 +208,6 @@ public: } virtual ~InstanceBase() { - if (custom_data) { - memdelete(custom_data); - } clear_dependencies(); } }; @@ -228,16 +218,10 @@ public: virtual void light_instance_mark_visible(RID p_light_instance) = 0; virtual bool light_instances_can_render_shadow_cube() const { return true; } - virtual RID reflection_atlas_create() = 0; - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_size) = 0; - virtual void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv) = 0; - virtual RID reflection_probe_instance_create(RID p_probe) = 0; virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0; - virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; - virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; - virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0; + virtual void reflection_probe_instance_begin_render(RID p_instance) = 0; virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0; virtual RID gi_probe_instance_create() = 0; @@ -245,21 +229,13 @@ public: virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) = 0; - virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; + virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0; virtual void set_scene_pass(uint64_t p_pass) = 0; virtual void set_time(double p_time) = 0; virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) = 0; - virtual void instance_create_custom_data(InstanceBase *p_instance) = 0; - virtual void instance_free_custom_data(InstanceBase *p_instance) = 0; - virtual void instance_custom_data_update_lights(InstanceBase *p_instance) = 0; - virtual void instance_custom_data_update_reflection_probes(InstanceBase *p_instance) = 0; - virtual void instance_custom_data_update_gi_probes(InstanceBase *p_instance) = 0; - virtual void instance_custom_data_update_lightmap(InstanceBase *p_instance) = 0; - virtual void instance_custom_data_update_transform(InstanceBase *p_instance) = 0; - virtual RID render_buffers_create() = 0; virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) = 0; @@ -442,7 +418,6 @@ public: virtual void light_set_use_gi(RID p_light, bool p_enable) = 0; virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) = 0; - virtual void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail) = 0; virtual void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) = 0; virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp index bf2214752d87..1dc0503027d1 100644 --- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -2375,7 +2375,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { attachments.push_back(af_color); RD::AttachmentFormat af_depth; - af_depth.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT; + af_depth.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; af_depth.usage_flags = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; attachments.push_back(af_depth); diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp index 11158db56fb4..1e3259411878 100644 --- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp @@ -39,7 +39,23 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture) { return uniform_set; } -void RasterizerEffectsRD::copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) { +void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y) { + + zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + if (p_flip_y) { + blur.push_constant.flags |= BLUR_FLAG_FLIP_Y; + } + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, Vector(), p_rect); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +void RasterizerEffectsRD::region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) { zeromem(&blur.push_constant, sizeof(BlurPushConstant)); @@ -164,6 +180,23 @@ void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_frameb RD::get_singleton()->draw_list_end(); } +void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) { + + CopyToDPPushConstant push_constant; + push_constant.bias = p_bias; + push_constant.z_far = p_z_far; + push_constant.z_near = p_z_near; + push_constant.z_flip = p_dp_flip; + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, Vector(), p_rect); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy.pipelines[COPY_MODE_CUBE_TO_DP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant)); @@ -277,6 +310,20 @@ RasterizerEffectsRD::RasterizerEffectsRD() { } } + { + // Initialize copier + Vector copy_modes; + copy_modes.push_back("\n#define MODE_CUBE_TO_DP\n"); + + copy.shader.initialize(copy_modes); + + copy.shader_version = copy.shader.version_create(); + + for (int i = 0; i < COPY_MODE_MAX; i++) { + copy.pipelines[i].setup(copy.shader.version_get_shader(copy.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } + } + RD::SamplerState sampler; sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h index 5b54ddc18dd9..8249f0aff1bf 100644 --- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h @@ -4,6 +4,7 @@ #include "core/math/camera_matrix.h" #include "render_pipeline_vertex_format_cache_rd.h" #include "servers/visual/rasterizer_rd/shaders/blur.glsl.gen.h" +#include "servers/visual/rasterizer_rd/shaders/copy.glsl.gen.h" #include "servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h" #include "servers/visual/rasterizer_rd/shaders/sky.glsl.gen.h" #include "servers/visual/rasterizer_rd/shaders/tonemap.glsl.gen.h" @@ -36,7 +37,8 @@ class RasterizerEffectsRD { BLUR_FLAG_USE_BLUR_SECTION = (1 << 1), BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2), BLUR_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3), - BLUR_FLAG_GLOW_FIRST_PASS = (1 << 4) + BLUR_FLAG_GLOW_FIRST_PASS = (1 << 4), + BLUR_FLAG_FLIP_Y = (1 << 5) }; struct BlurPushConstant { @@ -146,6 +148,25 @@ class RasterizerEffectsRD { RenderPipelineVertexFormatCacheRD pipelines[TONEMAP_MODE_MAX]; } tonemap; + struct CopyToDPPushConstant { + float bias; + float z_far; + float z_near; + uint32_t z_flip; + }; + + enum CopyMode { + COPY_MODE_CUBE_TO_DP, + COPY_MODE_MAX + }; + + struct Copy { + + CopyShaderRD shader; + RID shader_version; + RenderPipelineVertexFormatCacheRD pipelines[COPY_MODE_MAX]; + } copy; + RID default_sampler; RID index_buffer; RID index_array; @@ -155,11 +176,13 @@ class RasterizerEffectsRD { RID _get_uniform_set_from_texture(RID p_texture); public: - void copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region); + void region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region); + void copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y = false); void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region); void cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness); void render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler); void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size); + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); struct TonemapSettings { diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp index d8d1f5ec5de0..41e04ad20304 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp @@ -67,6 +67,18 @@ static _FORCE_INLINE_ void store_transform_3x3(const Transform &p_mtx, float *p_ p_array[11] = 0; } +static _FORCE_INLINE_ void store_transform_3x3_430(const Transform &p_mtx, float *p_array) { + p_array[0] = p_mtx.basis.elements[0][0]; + p_array[1] = p_mtx.basis.elements[1][0]; + p_array[2] = p_mtx.basis.elements[2][0]; + p_array[3] = p_mtx.basis.elements[0][1]; + p_array[4] = p_mtx.basis.elements[1][1]; + p_array[5] = p_mtx.basis.elements[2][1]; + p_array[6] = p_mtx.basis.elements[0][2]; + p_array[7] = p_mtx.basis.elements[1][2]; + p_array[8] = p_mtx.basis.elements[2][2]; +} + static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { for (int i = 0; i < 4; i++) { @@ -296,8 +308,8 @@ 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_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS)) { - if (k == SHADER_VERSION_DEPTH_PASS) { + } 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)) { + if (k == SHADER_VERSION_DEPTH_PASS || k == k == SHADER_VERSION_DEPTH_PASS_DP) { //none, blend state contains nothing } else { blend_state = blend_state_opaque; //writes to normal and roughness in opaque way @@ -310,7 +322,7 @@ void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) { if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_VCT_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { blend_state = blend_state_opaque; - } else if (k == SHADER_VERSION_DEPTH_PASS) { + } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { //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 @@ -583,60 +595,62 @@ bool RasterizerSceneForwardRD::free(RID p_rid) { } return false; } -/// INSTANCE DATA /// -void RasterizerSceneForwardRD::instance_create_custom_data(InstanceBase *p_instance) { - InstanceGeometryData *geom_data = memnew(InstanceGeometryData); - geom_data->ubo = RD::get_singleton()->uniform_buffer_create(sizeof(InstanceGeometryData::UBO)); - geom_data->using_lightmap_gi = p_instance->lightmap.is_valid(); - p_instance->custom_data = geom_data; -} +void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, int p_element_count) { -void RasterizerSceneForwardRD::instance_free_custom_data(InstanceBase *p_instance) { - InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; - ERR_FAIL_COND(!geom_data); - RD::get_singleton()->free(geom_data->ubo); - //uniform sets are freed as dependencies - memdelete(geom_data); - p_instance->custom_data = nullptr; -} + for (int i = 0; i < p_element_count; i++) { -void RasterizerSceneForwardRD::instance_custom_data_update_lights(InstanceBase *p_instance) { - //unused -} + const RenderList::Element *e = p_elements[i]; + InstanceData &id = scene_state.instances[i]; + store_transform(e->instance->transform, id.transform); + store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform); + id.flags = 0; + id.mask = e->instance->layer_mask; -void RasterizerSceneForwardRD::instance_custom_data_update_reflection_probes(InstanceBase *p_instance) { - //unused -} -void RasterizerSceneForwardRD::instance_custom_data_update_lightmap(InstanceBase *p_instance) { - InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; - ERR_FAIL_COND(!geom_data); + //forward - geom_data->using_lightmap_gi = p_instance->lightmap.is_valid(); + uint32_t reflection_count = 0; + uint32_t omni_count = 0; + uint32_t spot_count = 0; + uint32_t decal_count = 0; - if (geom_data->uniform_set_gi.is_valid() && RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_gi)) { - RD::get_singleton()->free(geom_data->uniform_set_gi); + if (!e->instance->light_instances.empty()) { + uint32_t light_count = e->instance->light_instances.size(); + const RID *light_ptrs = e->instance->light_instances.ptr(); + + for (uint32_t j = 0; j < light_count; j++) { + if (render_pass != light_instance_get_render_pass(light_ptrs[j])) { + continue; //not rendered this frame + } + + RID base = light_instance_get_base_light(light_ptrs[j]); + + uint32_t mask = storage->light_get_cull_mask(base); + if (!(mask & id.mask)) { + continue; //masked + } + + if (storage->light_get_type(base) == VS::LIGHT_OMNI) { + if (omni_count < 8) { + id.omni_light_indices[omni_count] = light_instance_get_index(light_ptrs[j]); + omni_count++; + } + } else { + if (spot_count < 8) { + id.omni_light_indices[spot_count] = light_instance_get_index(light_ptrs[j]); + spot_count++; + } + } + } + } + + id.flags |= reflection_count; + id.flags |= omni_count << 3; + id.flags |= spot_count << 6; + id.flags |= decal_count << 9; } - geom_data->uniform_set_gi = RID(); -} -void RasterizerSceneForwardRD::instance_custom_data_update_gi_probes(InstanceBase *p_instance) { - InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; - ERR_FAIL_COND(!geom_data); - - geom_data->using_vct_gi = p_instance->gi_probe_instances.size(); - - if (geom_data->uniform_set_gi.is_valid() && RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_gi)) { - RD::get_singleton()->free(geom_data->uniform_set_gi); - } - geom_data->uniform_set_gi = RID(); -} - -void RasterizerSceneForwardRD::instance_custom_data_update_transform(InstanceBase *p_instance) { - InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; - ERR_FAIL_COND(!geom_data); - - geom_data->ubo_dirty = true; + RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true); } /// RENDERING /// @@ -669,7 +683,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l //find cull variant ShaderData::CullVariant cull_variant; - if (p_pass_mode == PASS_MODE_SHADOW && e->instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { + if ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && e->instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; } else { bool mirror = e->instance->mirror; @@ -700,59 +714,42 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l } } - InstanceGeometryData *geom_data = (InstanceGeometryData *)e->instance->custom_data; - ShaderVersion shader_version; - RID instance_uniform_set; switch (p_pass_mode) { case PASS_MODE_COLOR: case PASS_MODE_COLOR_TRANSPARENT: { - if (p_no_gi) { - instance_uniform_set = geom_data->uniform_set_base; - shader_version = SHADER_VERSION_COLOR_PASS; - } else if (geom_data->using_lightmap_gi) { - instance_uniform_set = geom_data->uniform_set_gi; + if (e->uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; - } else if (geom_data->using_vct_gi) { - instance_uniform_set = geom_data->uniform_set_gi; + } else if (e->uses_vct) { shader_version = SHADER_VERSION_VCT_COLOR_PASS; } else { - instance_uniform_set = geom_data->uniform_set_gi; shader_version = SHADER_VERSION_COLOR_PASS; } + } break; case PASS_MODE_COLOR_SPECULAR: { - if (p_no_gi) { - instance_uniform_set = geom_data->uniform_set_base; - shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; - } else if (geom_data->using_lightmap_gi) { - instance_uniform_set = geom_data->uniform_set_gi; + if (e->uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; - } else if (geom_data->using_vct_gi) { - instance_uniform_set = geom_data->uniform_set_gi; + } else if (e->uses_vct) { shader_version = SHADER_VERSION_VCT_COLOR_PASS_WITH_SEPARATE_SPECULAR; } else { - instance_uniform_set = geom_data->uniform_set_gi; shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; } } break; - case PASS_MODE_SHADOW: { - shader_version = SHADER_VERSION_DEPTH_PASS; - instance_uniform_set = geom_data->uniform_set_base; - } break; + case PASS_MODE_SHADOW: case PASS_MODE_DEPTH: { shader_version = SHADER_VERSION_DEPTH_PASS; - instance_uniform_set = geom_data->uniform_set_base; + } break; + case PASS_MODE_SHADOW_DP: { + shader_version = SHADER_VERSION_DEPTH_PASS_DP; } break; case PASS_MODE_DEPTH_NORMAL: { shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL; - instance_uniform_set = geom_data->uniform_set_base; } break; case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; - instance_uniform_set = geom_data->uniform_set_base; } break; } @@ -812,8 +809,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l prev_material = material; } - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, instance_uniform_set, 3); - + push_constant.index = i; RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(PushConstant)); switch (e->instance->base_type) { @@ -836,10 +832,13 @@ 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, bool p_no_fog) { +void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) { - CameraMatrix projection = p_cam_projection; - projection.flip_y(); // Vulkan and modern APIs use Y-Down + //CameraMatrix projection = p_cam_projection; + //projection.flip_y(); // Vulkan and modern APIs use Y-Down + CameraMatrix correction; + correction.set_depth_correction(); + CameraMatrix projection = correction * p_cam_projection; //store camera into ubo store_camera(projection, scene_state.ubo.projection_matrix); @@ -847,6 +846,19 @@ void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_env store_transform(p_cam_transform, scene_state.ubo.camera_matrix); store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x; + scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y; + + if (p_shadow_atlas.is_valid()) { + Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); + scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x; + scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y; + } + { + Vector2 dss = directional_shadow_get_size(); + scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x; + scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y; + } //time global variables scene_state.ubo.time = time; @@ -863,7 +875,7 @@ void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_env //ambient if (ambient_src == VS::ENV_AMBIENT_SOURCE_BG && (env_bg == VS::ENV_BG_CLEAR_COLOR || env_bg == VS::ENV_BG_COLOR)) { - Color color = (p_render_target.is_valid() && env_bg == VS::ENV_BG_CLEAR_COLOR) ? storage->render_target_get_clear_request_color(p_render_target) : environment_get_bg_color(p_environment); + Color color = (p_render_target.is_valid() && env_bg == VS::ENV_BG_CLEAR_COLOR) ? (p_render_target.is_valid() ? storage->render_target_get_clear_request_color(p_render_target) : Color(0, 0, 0)) : environment_get_bg_color(p_environment); color = color.to_linear(); scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy; @@ -1024,7 +1036,7 @@ void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_env RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo, true); } -void RasterizerSceneForwardRD::_add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode) { +void RasterizerSceneForwardRD::_add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index) { RID m_src = p_instance->material_override.is_valid() ? p_instance->material_override : p_material; @@ -1047,18 +1059,18 @@ void RasterizerSceneForwardRD::_add_geometry(InstanceBase *p_instance, uint32_t ERR_FAIL_COND(!material); - _add_geometry_with_material(p_instance, p_surface, material, p_pass_mode); + _add_geometry_with_material(p_instance, p_surface, material, p_pass_mode, p_geometry_index); while (material->next_pass.is_valid()) { material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D); if (!material || !material->shader_data->valid) break; - _add_geometry_with_material(p_instance, p_surface, material, p_pass_mode); + _add_geometry_with_material(p_instance, p_surface, material, p_pass_mode, p_geometry_index); } } -void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, PassMode p_pass_mode) { +void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, PassMode p_pass_mode, uint32_t p_geometry_index) { bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); @@ -1120,8 +1132,11 @@ void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_insta e->material->shader_data->index = scene_state.current_shader_index++; } } - + e->geometry_index = p_geometry_index; e->material_index = e->material->index; + e->uses_instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH; + e->uses_lightmap = e->instance->lightmap.is_valid(); + e->uses_vct = e->instance->gi_probe_instances.size(); e->shader_index = e->shader_index; e->depth_layer = e->instance->depth_layer; e->priority = p_material->priority; @@ -1140,89 +1155,14 @@ void RasterizerSceneForwardRD::_fill_render_list(InstanceBase **p_cull_result, i scene_state.used_normal_texture = false; scene_state.used_depth_texture = false; + uint32_t geometry_index = 0; + //fill list for (int i = 0; i < p_cull_count; i++) { InstanceBase *inst = p_cull_result[i]; - InstanceGeometryData *geom_data = (InstanceGeometryData *)inst->custom_data; - - ERR_CONTINUE(!geom_data); - - if (geom_data->ubo_dirty) { - //ubo marked dirty, must be updated - InstanceGeometryData::UBO ubo; - store_transform(inst->transform, ubo.transform); - store_transform_3x3(inst->transform.basis.inverse().transposed(), ubo.normal_transform); - ubo.flags = 0; - ubo.pad[0] = 0; - ubo.pad[1] = 0; - ubo.pad[2] = 0; - RD::get_singleton()->buffer_update(geom_data->ubo, 0, sizeof(InstanceGeometryData::UBO), &ubo, true); - } - - if (p_no_gi) { - if (geom_data->uniform_set_base.is_null() || !RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_base)) { - - Vector uniforms; - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(geom_data->ubo); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; - u.binding = 1; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER)); - uniforms.push_back(u); - } - - geom_data->uniform_set_base = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 3); - } - } else { - if (geom_data->uniform_set_gi.is_null() || !RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_gi)) { - - Vector uniforms; - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(geom_data->ubo); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; - u.binding = 1; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER)); - uniforms.push_back(u); - } - - if (geom_data->using_lightmap_gi) { - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; -#ifndef _MSC_VER -#warning Need to put actual lightmap or lightmap capture texture if exists -#endif - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); - uniforms.push_back(u); - } - } else if (geom_data->using_vct_gi) { -#ifndef _MSC_VER -#warning Need to put actual vct textures here -#endif - } - - geom_data->uniform_set_gi = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 3); - } - } - //add geometry for drawing switch (inst->base_type) { @@ -1242,7 +1182,8 @@ void RasterizerSceneForwardRD::_fill_render_list(InstanceBase **p_cull_result, i RID material = inst_materials[j].is_valid() ? inst_materials[j] : materials[j]; - _add_geometry(inst, j, material, p_pass_mode); + uint32_t surface_index = storage->mesh_surface_get_render_pass_index(inst->base, j, render_pass, &geometry_index); + _add_geometry(inst, j, material, p_pass_mode, surface_index); } //mesh->last_pass=frame; @@ -1341,12 +1282,208 @@ void RasterizerSceneForwardRD::_draw_sky(RD::DrawListID p_draw_list, RD::Framebu storage->get_effects()->render_panorama(p_draw_list, p_fb_format, panorama, camera, sky_transform, 1.0, multiplier); } -void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { +void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) { + + for (uint32_t i = 0; i < p_reflection_probe_cull_count; i++) { + + RID rpi = p_reflection_probe_cull_result[i]; + + if (i >= scene_state.max_reflections) { + reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set + continue; + } + + reflection_probe_instance_set_render_index(rpi, i); + + RID base_probe = reflection_probe_instance_get_probe(rpi); + + ReflectionData &reflection_ubo = scene_state.reflections[i]; + + Vector3 extents = storage->reflection_probe_get_extents(base_probe); + + reflection_ubo.box_extents[0] = extents.x; + reflection_ubo.box_extents[1] = extents.y; + reflection_ubo.box_extents[2] = extents.z; + reflection_ubo.box_extents[3] = 0; + + Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe); + + reflection_ubo.box_offset[0] = origin_offset.x; + reflection_ubo.box_offset[1] = origin_offset.y; + reflection_ubo.box_offset[2] = origin_offset.z; + reflection_ubo.box_offset[3] = 0; + + float intensity = storage->reflection_probe_get_intensity(base_probe); + bool interior = storage->reflection_probe_is_interior(base_probe); + bool box_projection = storage->reflection_probe_is_box_projection(base_probe); + + reflection_ubo.params[0] = intensity; + reflection_ubo.params[1] = 0; + reflection_ubo.params[2] = interior ? 1.0 : 0.0; + reflection_ubo.params[3] = box_projection ? 1.0 : 0.0; + + if (interior) { + Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear(); + float interior_ambient_energy = storage->reflection_probe_get_interior_ambient_energy(base_probe); + float interior_ambient_probe_contrib = storage->reflection_probe_get_interior_ambient_probe_contribution(base_probe); + reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy; + reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy; + reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy; + reflection_ubo.ambient[3] = interior_ambient_probe_contrib; + } else { + Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear(); + if (is_environment(p_environment)) { + Color env_ambient_color = environment_get_ambient_light_color(p_environment).to_linear(); + float env_ambient_energy = environment_get_ambient_light_ambient_energy(p_environment); + ambient_linear = env_ambient_color; + ambient_linear.r *= env_ambient_energy; + ambient_linear.g *= env_ambient_energy; + ambient_linear.b *= env_ambient_energy; + } + + reflection_ubo.ambient[0] = ambient_linear.r; + reflection_ubo.ambient[1] = ambient_linear.g; + reflection_ubo.ambient[2] = ambient_linear.b; + reflection_ubo.ambient[3] = 0; //not used in exterior mode, since it just blends with regular ambient light + } + + Transform transform = reflection_probe_instance_get_transform(rpi); + Transform proj = (p_camera_inverse_transform * transform).inverse(); + store_transform(proj, reflection_ubo.local_matrix); + } + + if (p_reflection_probe_cull_count) { + RD::get_singleton()->buffer_update(scene_state.reflection_buffer, 0, MIN(scene_state.max_reflections, p_reflection_probe_cull_count) * sizeof(ReflectionData), scene_state.reflections, true); + } +} + +void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas) { + + uint32_t light_count = 0; + scene_state.ubo.directional_light_count = 0; + + for (int i = 0; i < p_light_cull_count; i++) { + + RID li = p_light_cull_result[i]; + RID base = light_instance_get_base_light(li); + + ERR_CONTINUE(base.is_null()); + + VS::LightType type = storage->light_get_type(base); + switch (type) { + + case VS::LIGHT_DIRECTIONAL: { + + if (scene_state.ubo.directional_light_count >= scene_state.max_directional_lights) { + continue; + } + } break; + case VS::LIGHT_SPOT: + case VS::LIGHT_OMNI: { + + if (light_count >= scene_state.max_lights) { + continue; + } + + Transform light_transform = light_instance_get_base_transform(li); + + LightData &light_data = scene_state.lights[light_count]; + + float sign = storage->light_is_negative(base) ? -1 : 1; + Color linear_col = storage->light_get_color(base).to_linear(); + + light_data.attenuation_energy[0] = Math::make_half_float(storage->light_get_param(base, VS::LIGHT_PARAM_ATTENUATION)); + light_data.attenuation_energy[1] = Math::make_half_float(sign * storage->light_get_param(base, VS::LIGHT_PARAM_ENERGY) * Math_PI); + + light_data.color_specular[0] = CLAMP(uint32_t(linear_col.r * 255), 0, 255); + light_data.color_specular[1] = CLAMP(uint32_t(linear_col.g * 255), 0, 255); + light_data.color_specular[2] = CLAMP(uint32_t(linear_col.b * 255), 0, 255); + light_data.color_specular[3] = CLAMP(uint32_t(storage->light_get_param(base, VS::LIGHT_PARAM_SPECULAR) * 255), 0, 255); + + light_data.inv_radius = 1.0 / MAX(0.001, storage->light_get_param(base, VS::LIGHT_PARAM_RANGE)); + + Vector3 pos = p_camera_inverse_transform.xform(light_transform.origin); + + light_data.position[0] = pos.x; + light_data.position[1] = pos.y; + light_data.position[2] = pos.z; + + Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized(); + + light_data.direction[0] = direction.x; + light_data.direction[1] = direction.y; + light_data.direction[2] = direction.z; + + light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, VS::LIGHT_PARAM_SPOT_ATTENUATION)); + light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(storage->light_get_param(base, VS::LIGHT_PARAM_SPOT_ANGLE)))); + + light_data.mask = storage->light_get_cull_mask(base); + + Color shadow_color = storage->light_get_shadow_color(base); + + bool has_shadow = storage->light_has_shadow(base); + light_data.shadow_color_enabled[0] = CLAMP(uint32_t(shadow_color.r * 255), 0, 255); + light_data.shadow_color_enabled[1] = CLAMP(uint32_t(shadow_color.g * 255), 0, 255); + light_data.shadow_color_enabled[2] = CLAMP(uint32_t(shadow_color.b * 255), 0, 255); + light_data.shadow_color_enabled[3] = has_shadow ? 255 : 0; + + light_data.atlas_rect[0] = 0; + light_data.atlas_rect[1] = 0; + light_data.atlas_rect[2] = 0; + light_data.atlas_rect[3] = 0; + + if (storage->light_has_shadow(base) && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) { + // fill in the shadow information + + Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas); + + if (type == VS::LIGHT_OMNI) { + + light_data.atlas_rect[0] = rect.position.x; + light_data.atlas_rect[1] = rect.position.y; + light_data.atlas_rect[2] = rect.size.width; + light_data.atlas_rect[3] = rect.size.height * 0.5; + + Transform proj = (p_camera_inverse_transform * light_transform).inverse(); + + store_transform(proj, light_data.shadow_matrix); + } else if (type == VS::LIGHT_SPOT) { + + Transform modelview = (p_camera_inverse_transform * light_transform).inverse(); + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + rectm.set_light_atlas_rect(rect); + + CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview; + store_camera(shadow_mtx, light_data.shadow_matrix); + } + } + + light_instance_set_index(li, light_count); + + light_count++; + } break; + } + + light_instance_set_render_pass(li, render_pass); + + //update UBO for forward rendering, blit to texture for clustered + } + + if (light_count) { + RD::get_singleton()->buffer_update(scene_state.light_buffer, 0, sizeof(LightData) * light_count, scene_state.lights, true); + } + + if (scene_state.ubo.directional_light_count) { + RD::get_singleton()->buffer_update(scene_state.directional_light_buffer, 0, sizeof(DirectionalLightData) * light_count, scene_state.directional_lights, true); + } +} + +void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)p_buffer_data; - ERR_FAIL_COND(!render_buffer); //bug out for now - //first of all, make a new render pass render_pass++; @@ -1388,14 +1525,34 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co scene_state.ubo.viewport_size[1] = vp_he.y; RID render_target; + Size2 screen_pixel_size; + RID opaque_framebuffer; + RID alpha_framebuffer; if (render_buffer) { - scene_state.ubo.screen_pixel_size[0] = 1.0 / render_buffer->width; - scene_state.ubo.screen_pixel_size[1] = 1.0 / render_buffer->height; + screen_pixel_size.width = 1.0 / render_buffer->width; + screen_pixel_size.height = 1.0 / render_buffer->height; render_target = render_buffer->render_target; + + opaque_framebuffer = render_buffer->color_fb; + alpha_framebuffer = opaque_framebuffer; + + } else if (p_reflection_probe.is_valid()) { + uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe); + screen_pixel_size.width = 1.0 / resolution; + screen_pixel_size.height = 1.0 / resolution; + + opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass); + alpha_framebuffer = opaque_framebuffer; + + } else { + ERR_FAIL(); //bug? } - _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid()); + _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas); + _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment); + _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas); + #if 0 for (int i = 0; i < p_light_cull_count; i++) { @@ -1771,10 +1928,12 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co } } - _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap); + _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, RID()); render_list.sort_by_key(false); + _fill_instances(render_list.elements, render_list.element_count); + bool can_continue = true; //unless the middle buffers are needed bool using_separate_specular = false; @@ -1782,14 +1941,14 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co //regular forward for now Vector c; c.push_back(clear_color.to_linear()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(render_buffer->color_fb, keep_color ? RD::INITIAL_ACTION_KEEP_COLOR : RD::INITIAL_ACTION_CLEAR, (can_continue || draw_sky) ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH, c); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(render_buffer->color_fb), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, render_buffer == nullptr); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP_COLOR : RD::INITIAL_ACTION_CLEAR, (can_continue || draw_sky) ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH, c); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, render_buffer == nullptr); RD::get_singleton()->draw_list_end(); } if (draw_sky) { - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(render_buffer->color_fb, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH); - _draw_sky(draw_list, RD::get_singleton()->framebuffer_get_format(render_buffer->color_fb), p_environment, p_cam_projection, p_cam_transform, 1.0); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ_COLOR_AND_DEPTH); + _draw_sky(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), p_environment, p_cam_projection, p_cam_transform, 1.0); RD::get_singleton()->draw_list_end(); if (using_separate_specular && !can_continue) { @@ -1887,9 +2046,11 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co #endif 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); + { - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(render_buffer->color_fb, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP_COLOR_AND_DEPTH, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(render_buffer->color_fb), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP_COLOR_AND_DEPTH, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr); RD::get_singleton()->draw_list_end(); } @@ -1907,7 +2068,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co } #endif if (p_reflection_probe.is_valid()) { - //rendering a probe, do no more! + //was rendering a probe, so do no more return; } @@ -1931,6 +2092,15 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co storage->render_target_disable_clear_request(render_buffer->render_target); + if (true) { + if (p_shadow_atlas.is_valid()) { + RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas); + Size2 rtsize = storage->render_target_get_size(render_buffer->render_target); + + effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(render_buffer->render_target), Rect2(Vector2(), rtsize / 2)); + } + } + #if 0 _post_process(env, p_cam_projection); // Needed only for debugging @@ -1988,8 +2158,38 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co //disable all stuff #endif } +void RasterizerSceneForwardRD::_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) { -void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap) { + render_pass++; + + scene_state.ubo.shadow_z_offset = p_bias; + scene_state.ubo.shadow_z_slope_scale = p_normal_bias; + 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, true, Vector2(1, 1), RID()); + + render_list.clear(); + + PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; + + _fill_render_list(p_cull_result, p_cull_count, pass_mode, true); + + _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), RID(), RID(), RID()); + + render_list.sort_by_key(false); + + _fill_instances(render_list.elements, render_list.element_count); + + { + //regular forward for now + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true); + RD::get_singleton()->draw_list_end(); + } +} + +void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas) { if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); @@ -2065,20 +2265,79 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer { RD::Uniform u; u.binding = 7; + u.type = RD::UNIFORM_TYPE_SAMPLER; + u.ids.push_back(shadow_sampler); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 8; u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(scene_state.uniform_buffer); uniforms.push_back(u); } + { + RD::Uniform u; + u.binding = 9; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.instance_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 10; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.reflection_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 11; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.light_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 12; + u.type = RD::UNIFORM_TYPE_TEXTURE; + if (p_shadow_atlas.is_valid()) { + u.ids.push_back(shadow_atlas_get_texture(p_shadow_atlas)); + } else { + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + } + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 13; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.directional_light_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 14; + u.type = RD::UNIFORM_TYPE_TEXTURE; + if (directional_shadow_get_texture().is_valid()) { + u.ids.push_back(directional_shadow_get_texture()); + } else { + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + } + uniforms.push_back(u); + } render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 0); } RasterizerSceneForwardRD *RasterizerSceneForwardRD::singleton = NULL; -void RasterizerSceneForwardRD::set_scene_pass(uint64_t p_pass) { - scene_pass = p_pass; -} - void RasterizerSceneForwardRD::set_time(double p_time) { time = p_time; } @@ -2097,8 +2356,53 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; } + uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); + + if (textures_per_stage <= 16) { + //ARM pretty much, and very old Intel GPUs under Linux + scene_state.max_reflection_probes_per_instance = 4; //sad + } else { + //maximum 8 + scene_state.max_reflection_probes_per_instance = 8; + } + + defines += "\n#define MAX_REFLECTION_PROBES " + itos(scene_state.max_reflection_probes_per_instance) + "\n"; + + uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE); + + { //reflections + uint32_t reflection_buffer_size; + if (uniform_max_size < 65536) { + //Yes, you guessed right, ARM again + reflection_buffer_size = uniform_max_size; + } else { + reflection_buffer_size = 65536; + } + + scene_state.max_reflections = reflection_buffer_size / sizeof(ReflectionData); + scene_state.reflections = memnew_arr(ReflectionData, scene_state.max_reflections); + scene_state.reflection_buffer = RD::get_singleton()->uniform_buffer_create(reflection_buffer_size); + defines += "\n#define MAX_REFLECTION_DATA_STRUCTS " + itos(scene_state.max_reflections) + "\n"; + } + + { //lights + scene_state.max_lights = MIN(65536, uniform_max_size) / sizeof(LightData); + uint32_t light_buffer_size = scene_state.max_lights * sizeof(LightData); + print_line("ID: " + itos(sizeof(InstanceData))); + scene_state.lights = memnew_arr(LightData, scene_state.max_lights); + scene_state.light_buffer = RD::get_singleton()->uniform_buffer_create(light_buffer_size); + defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n"; + + scene_state.max_directional_lights = 4; + uint32_t directional_light_buffer_size = scene_state.max_directional_lights * sizeof(DirectionalLightData); + scene_state.directional_lights = memnew_arr(DirectionalLightData, scene_state.max_directional_lights); + scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); + defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(scene_state.max_directional_lights) + "\n"; + } + Vector shader_versions; shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); 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(""); @@ -2198,7 +2502,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions.usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; + actions.usage_defines["TRANSMISSION"] = "#define LIGHT_TRANSMISSION_USED\n"; actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; @@ -2249,11 +2553,17 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag } //render list - render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)256000); + render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)128000); render_list.init(); - scene_pass = 0; render_pass = 0; + { + + scene_state.max_instances = render_list.max_elements; + scene_state.instances = memnew_arr(InstanceData, scene_state.max_instances); + scene_state.instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(InstanceData) * scene_state.max_instances); + } + scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); { @@ -2266,6 +2576,16 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); } + + { + + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.enable_compare = true; + sampler.compare_op = RD::COMPARE_OP_LESS; + shadow_sampler = RD::get_singleton()->sampler_create(sampler); + } } RasterizerSceneForwardRD::~RasterizerSceneForwardRD() { @@ -2273,4 +2593,9 @@ RasterizerSceneForwardRD::~RasterizerSceneForwardRD() { if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } + + { + RD::get_singleton()->free(scene_state.reflection_buffer); + memdelete_arr(scene_state.reflections); + } } diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h index ca28678fccf7..f7d0e419ad49 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h @@ -42,6 +42,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { enum ShaderVersion { SHADER_VERSION_DEPTH_PASS, + SHADER_VERSION_DEPTH_PASS_DP, SHADER_VERSION_DEPTH_PASS_WITH_NORMAL, SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, SHADER_VERSION_COLOR_PASS, @@ -174,37 +175,11 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { return static_cast(singleton)->_create_material_func(static_cast(p_shader)); } - /* Instance Custom Data */ - - struct InstanceGeometryData : public InstanceCustomData { - - struct UBO { - float transform[16]; - float normal_transform[12]; - uint32_t flags; - uint32_t pad[3]; - }; - - RID ubo; - RID uniform_set_base; - RID uniform_set_gi; - - bool ubo_dirty = true; - bool using_lightmap_gi = false; - bool using_vct_gi = false; - }; - /* Push Constant */ struct PushConstant { - uint32_t reflection_probe_count; - uint32_t omni_light_count; - uint32_t spot_light_count; - uint32_t decal_count; - float reflection_probe_indices[4]; - float omni_light_indices[4]; - float spot_light_indices[4]; - float decal_indices[4]; + uint32_t index; + uint32_t pad[3]; }; /* Framebuffer */ @@ -227,11 +202,65 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { virtual RenderBufferData *_create_render_buffer_data(); + RID shadow_sampler; RID render_base_uniform_set; - void _setup_render_base_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap); + void _setup_render_base_uniform_set(RID p_depth_buffer, RID p_color_buffer, RID p_normal_buffer, RID p_roughness_limit_buffer, RID p_radiance_cubemap, RID p_shadow_atlas, RID p_reflection_atlas); /* Scene State UBO */ + struct ReflectionData { //should always be 128 bytes + float box_extents[4]; + float box_offset[4]; + float params[4]; // intensity, 0, interior , boxproject + float ambient[4]; // ambient color, energy + float local_matrix[16]; // up to here for spot and omni, rest is for directional + }; + + struct LightData { + float position[3]; + float inv_radius; + float direction[3]; + uint16_t attenuation_energy[2]; //16 bits attenuation, then energy + uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm) + uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float) + uint32_t mask; + uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm) + float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv + float shadow_matrix[16]; + }; + + struct DirectionalLightData { + + float direction[3]; + float energy; + float color[3]; + float specular; + uint32_t mask; + uint32_t pad[3]; + float shadow_color[3]; + uint32_t shadow_enabled; + float shadow_atlas_rect[4]; + float shadow_split_offsets[4]; + float shadow_matrix1[16]; + float shadow_matrix2[16]; + float shadow_matrix3[16]; + float shadow_matrix4[16]; + }; + + struct InstanceData { + float transform[16]; + float normal_transform[16]; + uint32_t flags; + uint32_t instance_ofs; //instance_offset in instancing/skeleton buffer + uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap) + uint32_t mask; + + uint16_t reflection_probe_indices[8]; + uint16_t omni_light_indices[8]; + uint16_t spot_light_indices[8]; + uint16_t decal_indices[8]; + }; + struct SceneState { struct UBO { float projection_matrix[16]; @@ -257,12 +286,37 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { uint32_t use_reflection_cubemap; float radiance_inverse_xform[12]; + + float shadow_atlas_pixel_size[2]; + float directional_shadow_pixel_size[2]; + + uint32_t directional_light_count; + float dual_paraboloid_side; + float z_far; + uint32_t pad[1]; }; UBO ubo; RID uniform_buffer; + ReflectionData *reflections; + uint32_t max_reflections; + RID reflection_buffer; + uint32_t max_reflection_probes_per_instance; + + LightData *lights; + uint32_t max_lights; + RID light_buffer; + + DirectionalLightData *directional_lights; + uint32_t max_directional_lights; + RID directional_light_buffer; + + RID instance_buffer; + InstanceData *instances; + uint32_t max_instances; + bool used_screen_texture = false; bool used_normal_texture = false; bool used_depth_texture = false; @@ -283,10 +337,14 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { union { struct { //from least significant to most significant in sort, TODO: should be endian swapped on big endian - uint64_t material_index : 20; - uint64_t shader_index : 20; - uint64_t priority : 16; - uint64_t depth_layer : 8; + uint64_t geometry_index : 20; + uint64_t material_index : 15; + uint64_t shader_index : 12; + uint64_t uses_instancing : 1; + uint64_t uses_vct : 1; + uint64_t uses_lightmap : 1; + uint64_t depth_layer : 4; + uint64_t priority : 8; }; uint64_t sort_key; @@ -407,7 +465,6 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { RenderList render_list; static RasterizerSceneForwardRD *singleton; - uint64_t scene_pass; uint64_t render_pass; double time; RID default_shader; @@ -419,39 +476,33 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { PASS_MODE_COLOR_SPECULAR, PASS_MODE_COLOR_TRANSPARENT, PASS_MODE_SHADOW, + PASS_MODE_SHADOW_DP, PASS_MODE_DEPTH, PASS_MODE_DEPTH_NORMAL, PASS_MODE_DEPTH_NORMAL_ROUGHNESS, }; - void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog); + void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas); + void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas); + 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 _fill_instances(RenderList::Element **p_elements, int p_element_count); void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi); - _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode); - _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, PassMode p_pass_mode); + _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, PassMode p_pass_mode, uint32_t p_geometry_index); void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi); void _draw_sky(RD::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, float p_alpha); protected: - virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip); public: - virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {} - - virtual void set_scene_pass(uint64_t p_pass); virtual void set_time(double p_time); virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {} - virtual void instance_create_custom_data(InstanceBase *p_instance); - virtual void instance_free_custom_data(InstanceBase *p_instance); - virtual void instance_custom_data_update_lights(InstanceBase *p_instance); - virtual void instance_custom_data_update_reflection_probes(InstanceBase *p_instance); - virtual void instance_custom_data_update_gi_probes(InstanceBase *p_instance); - virtual void instance_custom_data_update_lightmap(InstanceBase *p_instance); - virtual void instance_custom_data_update_transform(InstanceBase *p_instance); - virtual bool free(RID p_rid); RasterizerSceneForwardRD(RasterizerStorageRD *p_storage); diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index 97e3f9cdb629..72000e824a54 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -1,6 +1,204 @@ #include "rasterizer_scene_rd.h" +#include "core/os/os.h" #include "core/project_settings.h" +void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { + + if (rd.radiance.is_valid()) { + //if size changes, everything must be cleared + RD::get_singleton()->free(rd.radiance); + //everything else gets dependency, erase, so just clean it up + rd.radiance = RID(); + rd.layers.clear(); + rd.radiance_base_cubemap = RID(); + } +} + +void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, bool p_quality) { + //recreate radiance and all data + int mipmaps = Image::get_image_required_mipmaps(p_size, p_size, Image::FORMAT_RGBAH) + 1; + if (!p_quality) { + //use less mipmaps + mipmaps = MIN(8, mipmaps); + } + + uint32_t w = p_size, h = p_size; + + if (sky_use_cubemap_array) { + //array (higher quality, 6 times more memory) + RD::TextureFormat tf; + tf.array_layers = roughness_layers * 6; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.mipmaps = mipmaps; + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + rd.radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + for (int i = 0; i < roughness_layers; i++) { + ReflectionData::Layer layer; + uint32_t mmw = w; + uint32_t mmh = h; + layer.mipmaps.resize(mipmaps); + for (int j = 0; j < mipmaps; j++) { + ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; + mm.size.width = mmw; + mm.size.height = mmh; + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, i * 6 + k, j); + Vector fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + + mmw = MAX(1, mmw >> 1); + mmh = MAX(1, mmh >> 1); + } + + rd.layers.push_back(layer); + } + + } else { + //regular cubemap, lower quality (aliasing, less memory) + RD::TextureFormat tf; + tf.array_layers = 6; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.type = RD::TEXTURE_TYPE_CUBE; + tf.mipmaps = roughness_layers; + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + rd.radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + ReflectionData::Layer layer; + uint32_t mmw = w; + uint32_t mmh = h; + layer.mipmaps.resize(roughness_layers); + for (int j = 0; j < roughness_layers; j++) { + ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; + mm.size.width = mmw; + mm.size.height = mmh; + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, k, j); + Vector fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + + mmw = MAX(1, mmw >> 1); + mmh = MAX(1, mmh >> 1); + } + + rd.layers.push_back(layer); + } + + rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, 0, 0, RD::TEXTURE_SLICE_CUBEMAP); +} + +void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality) { + + if (sky_use_cubemap_array) { + + if (p_quality) { + //render directly to the layers + for (int i = 0; i < rd.layers.size(); i++) { + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].mipmaps[0].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0)); + } + } + } else { + //render to first mipmap + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].mipmaps[0].framebuffers[j], j, sky_ggx_samples_realtime, 0.0); + } + //do the rest in other mipmaps and use cubemap itself as source + for (int i = 1; i < roughness_layers; i++) { + //render using a smaller mipmap, then copy to main layer + for (int j = 0; j < 6; j++) { + //storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[0], j, sky_ggx_samples_realtime, float(i) / (rd.layers.size() - 1.0)); + storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].mipmaps[i].framebuffers[0], j, sky_ggx_samples_realtime, float(i) / (rd.layers.size() - 1.0)); + storage->get_effects()->region_copy(rd.layers[0].mipmaps[i].views[0], rd.layers[i].mipmaps[0].framebuffers[j], Rect2()); + } + } + } + } else { + + if (p_quality) { + //render directly to the layers + for (int i = 0; i < rd.layers[0].mipmaps.size(); i++) { + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0)); + } + } + } else { + + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].mipmaps[0].framebuffers[j], j, sky_ggx_samples_realtime, 0); + } + + for (int i = 1; i < rd.layers[0].mipmaps.size(); i++) { + for (int j = 0; j < 6; j++) { + storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_realtime, float(i) / (rd.layers[0].mipmaps.size() - 1.0)); + } + } + } + } +} + +void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_quality, int p_cube_side) { + + if (sky_use_cubemap_array) { + + if (p_quality) { + //render directly to the layers + for (int i = 1; i < rd.layers.size(); i++) { + storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[i].mipmaps[0].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0)); + } + } else { + //do the rest in other mipmaps and use cubemap itself as source + for (int i = 1; i < roughness_layers; i++) { + //render using a smaller mipmap, then copy to main layer + storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[0], p_cube_side, sky_ggx_samples_realtime, float(i) / (rd.layers.size() - 1.0)); + storage->get_effects()->region_copy(rd.layers[0].mipmaps[i].views[0], rd.layers[i].mipmaps[0].framebuffers[p_cube_side], Rect2()); + } + } + } else { + + if (p_quality) { + //render directly to the layers + for (int i = 1; i < rd.layers[0].mipmaps.size(); i++) { + storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0)); + } + } else { + + for (int i = 1; i < rd.layers[0].mipmaps.size(); i++) { + storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_realtime, float(i) / (rd.layers[0].mipmaps.size() - 1.0)); + } + } + } +} + +void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd, bool p_quality) { + + if (sky_use_cubemap_array) { + + for (int i = 0; i < rd.layers.size(); i++) { + for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) { + for (int k = 0; k < 6; k++) { + RID view = rd.layers[i].mipmaps[j].views[k]; + RID fb = rd.layers[i].mipmaps[j + 1].framebuffers[k]; + Vector2 size = rd.layers[i].mipmaps[j].size; + size = Vector2(1.0 / size.x, 1.0 / size.y); + storage->get_effects()->make_mipmap(view, fb, size); + } + } + } + } +} + RID RasterizerSceneRD::sky_create() { return sky_owner.make_rid(Sky()); } @@ -22,14 +220,7 @@ void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { } sky->radiance_size = p_radiance_size; _sky_invalidate(sky); - if (sky->radiance.is_valid()) { - //if size changes, everything must be cleared - RD::get_singleton()->free(sky->radiance); - //everything else gets dependency, erase, so just clean it up - sky->radiance = RID(); - sky->layers.clear(); - sky->radiance_base_cubemap = RID(); - } + _clear_reflection_data(sky->reflection); } void RasterizerSceneRD::sky_set_mode(RID p_sky, VS::SkyMode p_mode) { @@ -51,8 +242,7 @@ void RasterizerSceneRD::sky_set_texture(RID p_sky, RID p_panorama) { if (sky->panorama.is_valid()) { sky->panorama = RID(); - RD::get_singleton()->free(sky->radiance); - sky->radiance = RID(); + _clear_reflection_data(sky->reflection); } sky->panorama = p_panorama; @@ -70,155 +260,16 @@ void RasterizerSceneRD::_update_dirty_skys() { //update sky configuration if texture is missing - if (sky->radiance.is_null()) { - //recreate radiance and all data - int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; - if (sky->mode == VS::SKY_MODE_REALTIME) { - //use less mipmaps - mipmaps = MIN(8, mipmaps); - } - - uint32_t w = sky->radiance_size, h = sky->radiance_size; - - if (sky_use_cubemap_array) { - //array (higher quality, 6 times more memory) - RD::TextureFormat tf; - tf.array_layers = roughness_layers * 6; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; - tf.mipmaps = mipmaps; - tf.width = w; - tf.height = h; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - for (int i = 0; i < roughness_layers; i++) { - Sky::Layer layer; - uint32_t mmw = w; - uint32_t mmh = h; - layer.mipmaps.resize(mipmaps); - for (int j = 0; j < mipmaps; j++) { - Sky::Layer::Mipmap &mm = layer.mipmaps.write[j]; - mm.size.width = mmw; - mm.size.height = mmh; - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sky->radiance, i * 6 + k, j); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } - - mmw = MAX(1, mmw >> 1); - mmh = MAX(1, mmh >> 1); - } - - sky->layers.push_back(layer); - } - - } else { - //regular cubemap, lower quality (aliasing, less memory) - RD::TextureFormat tf; - tf.array_layers = 6; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE; - tf.mipmaps = roughness_layers; - tf.width = w; - tf.height = h; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - Sky::Layer layer; - uint32_t mmw = w; - uint32_t mmh = h; - layer.mipmaps.resize(roughness_layers); - for (int j = 0; j < roughness_layers; j++) { - Sky::Layer::Mipmap &mm = layer.mipmaps.write[j]; - mm.size.width = mmw; - mm.size.height = mmh; - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sky->radiance, k, j); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } - - mmw = MAX(1, mmw >> 1); - mmh = MAX(1, mmh >> 1); - } - - sky->layers.push_back(layer); - } - - sky->radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sky->radiance, 0, 0, RD::TEXTURE_SLICE_CUBEMAP); + if (sky->reflection.radiance.is_null()) { + _update_reflection_data(sky->reflection, sky->radiance_size, sky->mode == VS::SKY_MODE_QUALITY); } RID panorama_texture = storage->texture_get_rd_texture(sky->panorama); if (panorama_texture.is_valid()) { //is there a panorama texture? - - if (sky_use_cubemap_array) { - - if (sky->mode == VS::SKY_MODE_QUALITY) { - //render directly to the layers - for (int i = 0; i < sky->layers.size(); i++) { - for (int j = 0; j < 6; j++) { - storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[i].mipmaps[0].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (sky->layers.size() - 1.0)); - } - } - } else if (sky->mode == VS::SKY_MODE_REALTIME) { - //render to first mipmap - for (int j = 0; j < 6; j++) { - storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[0].framebuffers[j], j, sky_ggx_samples_realtime, 0.0); - } - //do the rest in other mipmaps and use cubemap itself as source - for (int i = 1; i < roughness_layers; i++) { - //render using a smaller mipmap, then copy to main layer - for (int j = 0; j < 6; j++) { - //storage->get_effects()->cubemap_roughness(sky->radiance_base_cubemap, false, sky->layers[0].mipmaps[i].framebuffers[0], j, sky_ggx_samples_realtime, float(i) / (sky->layers.size() - 1.0)); - storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[i].framebuffers[0], j, sky_ggx_samples_realtime, float(i) / (sky->layers.size() - 1.0)); - storage->get_effects()->copy(sky->layers[0].mipmaps[i].views[0], sky->layers[i].mipmaps[0].framebuffers[j], Rect2()); - } - } - } - - //generate mipmaps - - for (int i = 0; i < sky->layers.size(); i++) { - for (int j = 0; j < sky->layers[i].mipmaps.size() - 1; j++) { - for (int k = 0; k < 6; k++) { - RID view = sky->layers[i].mipmaps[j].views[k]; - RID fb = sky->layers[i].mipmaps[j + 1].framebuffers[k]; - Vector2 size = sky->layers[i].mipmaps[j].size; - size = Vector2(1.0 / size.x, 1.0 / size.y); - storage->get_effects()->make_mipmap(view, fb, size); - } - } - } - } else { - - if (sky->mode == VS::SKY_MODE_QUALITY) { - //render directly to the layers - for (int i = 0; i < sky->layers[0].mipmaps.size(); i++) { - for (int j = 0; j < 6; j++) { - storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (sky->layers[0].mipmaps.size() - 1.0)); - } - } - } else { - - for (int j = 0; j < 6; j++) { - storage->get_effects()->cubemap_roughness(panorama_texture, true, sky->layers[0].mipmaps[0].framebuffers[j], j, sky_ggx_samples_realtime, 0); - } - - for (int i = 1; i < sky->layers[0].mipmaps.size(); i++) { - for (int j = 0; j < 6; j++) { - storage->get_effects()->cubemap_roughness(sky->radiance_base_cubemap, false, sky->layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_realtime, float(i) / (sky->layers[0].mipmaps.size() - 1.0)); - } - } - } - } + _create_reflection_from_panorama(sky->reflection, panorama_texture, sky->mode == VS::SKY_MODE_QUALITY); + _update_reflection_mipmaps(sky->reflection, sky->mode == VS::SKY_MODE_QUALITY); } Sky *next = sky->dirty_list; @@ -244,7 +295,7 @@ RID RasterizerSceneRD::sky_get_radiance_texture_rd(RID p_sky) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); - return sky->radiance; + return sky->reflection.radiance; } RID RasterizerSceneRD::environment_create() { @@ -416,6 +467,593 @@ bool RasterizerSceneRD::is_environment(RID p_env) const { return environment_owner.owns(p_env); } +//////////////////////////////////////////////////////////// + +RID RasterizerSceneRD::reflection_probe_instance_create(RID p_probe) { + ReflectionProbeInstance rpi; + rpi.probe = p_probe; + return reflection_probe_instance_owner.make_rid(rpi); +} + +void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + + rpi->transform = p_transform; + rpi->dirty = true; +} + +bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + if (rpi->rendering) { + return false; + } + + if (rpi->dirty) { + return true; + } + + if (rpi->current_resolution != storage->reflection_probe_get_resolution(rpi->probe)) { + return true; + } + + if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) { + return true; + } + + return false; +} + +void RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + rpi->rendering = true; + rpi->processing_side = 0; + + int probe_resolution = storage->reflection_probe_get_resolution(rpi->probe); + if (rpi->current_resolution != probe_resolution) { + //need to re-create everything + _clear_reflection_data(rpi->reflection); + _update_reflection_data(rpi->reflection, probe_resolution, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE); + + rpi->current_resolution = probe_resolution; + + if (rpi->depth_buffer.is_valid()) { + RD::get_singleton()->free(rpi->depth_buffer); + } + { + RD::TextureFormat tf; + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.width = probe_resolution; + tf.height = probe_resolution; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + rpi->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + for (int i = 0; i < 6; i++) { + Vector fb; + fb.push_back(rpi->reflection.layers[0].mipmaps[0].views[i]); + fb.push_back(rpi->depth_buffer); + rpi->render_fb[i] = RD::get_singleton()->framebuffer_create(fb); + } + } +} + +bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + ERR_FAIL_COND_V(!rpi->rendering, false); + + _create_reflection_from_base_mipmap(rpi->reflection, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side); + + rpi->processing_side++; + + if (rpi->processing_side == 6) { + rpi->rendering = false; + rpi->processing_side = 0; + + return true; + } else { + return false; + } +} + +uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, 0); + + return rpi->current_resolution; +} + +RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, RID()); + ERR_FAIL_INDEX_V(p_index, 6, RID()); + + return rpi->render_fb[p_index]; +} + +/////////////////////////////////////////////////////////// + +RID RasterizerSceneRD::shadow_atlas_create() { + + return shadow_atlas_owner.make_rid(ShadowAtlas()); +} + +void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_COND(p_size < 0); + + p_size = next_power_of_2(p_size); + + if (p_size == shadow_atlas->size) + return; + + // erasing atlas + if (shadow_atlas->depth.is_valid()) { + RD::get_singleton()->free(shadow_atlas->depth); + shadow_atlas->depth = RID(); + shadow_atlas->fb = RID(); + } + for (int i = 0; i < 4; i++) { + //clear subdivisions + shadow_atlas->quadrants[i].shadows.resize(0); + shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision); + } + + //erase shadow atlas reference from lights + for (Map::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) { + LightInstance *li = light_instance_owner.getornull(E->key()); + ERR_CONTINUE(!li); + li->shadow_atlases.erase(p_atlas); + } + + //clear owners + shadow_atlas->shadow_owners.clear(); + + shadow_atlas->size = p_size; + + if (shadow_atlas->size) { + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R32_SFLOAT; + tf.width = shadow_atlas->size; + tf.height = shadow_atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector fb; + fb.push_back(shadow_atlas->depth); + shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb); + } +} + +void RasterizerSceneRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_INDEX(p_quadrant, 4); + ERR_FAIL_INDEX(p_subdivision, 16384); + + uint32_t subdiv = next_power_of_2(p_subdivision); + if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer + subdiv <<= 1; + } + + subdiv = int(Math::sqrt((float)subdiv)); + + //obtain the number that will be x*x + + if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv) + return; + + //erase all data from quadrant + for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) { + + if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) { + shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); + LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); + ERR_CONTINUE(!li); + li->shadow_atlases.erase(p_atlas); + } + } + + shadow_atlas->quadrants[p_quadrant].shadows.resize(0); + shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv); + shadow_atlas->quadrants[p_quadrant].subdivision = subdiv; + + //cache the smallest subdiv (for faster allocation in light update) + + shadow_atlas->smallest_subdiv = 1 << 30; + + for (int i = 0; i < 4; i++) { + if (shadow_atlas->quadrants[i].subdivision) { + shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision); + } + } + + if (shadow_atlas->smallest_subdiv == 1 << 30) { + shadow_atlas->smallest_subdiv = 0; + } + + //resort the size orders, simple bublesort for 4 elements.. + + int swaps = 0; + do { + swaps = 0; + + for (int i = 0; i < 3; i++) { + if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) { + SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]); + swaps++; + } + } + } while (swaps > 0); +} + +bool RasterizerSceneRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { + + for (int i = p_quadrant_count - 1; i >= 0; i--) { + + int qidx = p_in_quadrants[i]; + + if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { + return false; + } + + //look for an empty space + int sc = shadow_atlas->quadrants[qidx].shadows.size(); + ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw(); + + int found_free_idx = -1; //found a free one + int found_used_idx = -1; //found existing one, must steal it + uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion) + + for (int j = 0; j < sc; j++) { + if (!sarr[j].owner.is_valid()) { + found_free_idx = j; + break; + } + + LightInstance *sli = light_instance_owner.getornull(sarr[j].owner); + ERR_CONTINUE(!sli); + + if (sli->last_scene_pass != scene_pass) { + + //was just allocated, don't kill it so soon, wait a bit.. + if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) + continue; + + if (found_used_idx == -1 || sli->last_scene_pass < min_pass) { + found_used_idx = j; + min_pass = sli->last_scene_pass; + } + } + } + + if (found_free_idx == -1 && found_used_idx == -1) + continue; //nothing found + + if (found_free_idx == -1 && found_used_idx != -1) { + found_free_idx = found_used_idx; + } + + r_quadrant = qidx; + r_shadow = found_free_idx; + + return true; + } + + return false; +} + +bool RasterizerSceneRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND_V(!shadow_atlas, false); + + LightInstance *li = light_instance_owner.getornull(p_light_intance); + ERR_FAIL_COND_V(!li, false); + + if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { + return false; + } + + uint32_t quad_size = shadow_atlas->size >> 1; + int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage)); + + int valid_quadrants[4]; + int valid_quadrant_count = 0; + int best_size = -1; //best size found + int best_subdiv = -1; //subdiv for the best size + + //find the quadrants this fits into, and the best possible size it can fit into + for (int i = 0; i < 4; i++) { + int q = shadow_atlas->size_order[i]; + int sd = shadow_atlas->quadrants[q].subdivision; + if (sd == 0) + continue; //unused + + int max_fit = quad_size / sd; + + if (best_size != -1 && max_fit > best_size) + break; //too large + + valid_quadrants[valid_quadrant_count++] = q; + best_subdiv = sd; + + if (max_fit >= desired_fit) { + best_size = max_fit; + } + } + + ERR_FAIL_COND_V(valid_quadrant_count == 0, false); + + uint64_t tick = OS::get_singleton()->get_ticks_msec(); + + //see if it already exists + + if (shadow_atlas->shadow_owners.has(p_light_intance)) { + //it does! + uint32_t key = shadow_atlas->shadow_owners[p_light_intance]; + uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; + + bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); + bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version; + + if (!should_realloc) { + shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; + //already existing, see if it should redraw or it's just OK + return should_redraw; + } + + int new_quadrant, new_shadow; + + //find a better place + if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) { + //found a better place! + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; + if (sh->owner.is_valid()) { + //is taken, but is invalid, erasing it + shadow_atlas->shadow_owners.erase(sh->owner); + LightInstance *sli = light_instance_owner.getornull(sh->owner); + sli->shadow_atlases.erase(p_atlas); + } + + //erase previous + shadow_atlas->quadrants[q].shadows.write[s].version = 0; + shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); + + sh->owner = p_light_intance; + sh->alloc_tick = tick; + sh->version = p_light_version; + li->shadow_atlases.insert(p_atlas); + + //make new key + key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; + key |= new_shadow; + //update it in map + shadow_atlas->shadow_owners[p_light_intance] = key; + //make it dirty, as it should redraw anyway + return true; + } + + //no better place for this shadow found, keep current + + //already existing, see if it should redraw or it's just OK + + shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; + + return should_redraw; + } + + int new_quadrant, new_shadow; + + //find a better place + if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) { + //found a better place! + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; + if (sh->owner.is_valid()) { + //is taken, but is invalid, erasing it + shadow_atlas->shadow_owners.erase(sh->owner); + LightInstance *sli = light_instance_owner.getornull(sh->owner); + sli->shadow_atlases.erase(p_atlas); + } + + sh->owner = p_light_intance; + sh->alloc_tick = tick; + sh->version = p_light_version; + li->shadow_atlases.insert(p_atlas); + + //make new key + uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; + key |= new_shadow; + //update it in map + shadow_atlas->shadow_owners[p_light_intance] = key; + //make it dirty, as it should redraw anyway + + return true; + } + + //no place to allocate this light, apologies + + return false; +} + +void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { + + p_size = nearest_power_of_2_templated(p_size); + + if (directional_shadow.size == p_size) { + return; + } + + if (directional_shadow.depth.is_valid()) { + RD::get_singleton()->free(directional_shadow.depth); + directional_shadow.depth = RID(); + directional_shadow.fb = RID(); + } + + if (p_size > 0) { + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R32_SFLOAT; + tf.width = p_size; + tf.height = p_size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector fb; + fb.push_back(directional_shadow.depth); + directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb); + } +} + +void RasterizerSceneRD::set_directional_shadow_count(int p_count) { + + directional_shadow.light_count = p_count; + directional_shadow.current_light = 0; +} + +int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) { + + ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0); + + int shadow_size; + + if (directional_shadow.light_count == 1) { + shadow_size = directional_shadow.size; + } else { + shadow_size = directional_shadow.size / 2; //more than 4 not supported anyway + } + + LightInstance *light_instance = light_instance_owner.getornull(p_light_intance); + ERR_FAIL_COND_V(!light_instance, 0); + + switch (storage->light_directional_get_shadow_mode(light_instance->light)) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: + break; //none + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: shadow_size /= 2; break; + } + + return shadow_size; +} + +////////////////////////////////////////////////// + +RID RasterizerSceneRD::light_instance_create(RID p_light) { + + RID li = light_instance_owner.make_rid(LightInstance()); + + LightInstance *light_instance = light_instance_owner.getornull(li); + + light_instance->self = li; + light_instance->light = p_light; + light_instance->light_type = storage->light_get_type(p_light); + + return li; +} + +void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) { + + LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->transform = p_transform; +} + +void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale) { + + LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND(!light_instance); + + if (storage->light_get_type(light_instance->light) != VS::LIGHT_DIRECTIONAL) { + p_pass = 0; + } + + ERR_FAIL_INDEX(p_pass, 4); + + light_instance->shadow_transform[p_pass].camera = p_projection; + light_instance->shadow_transform[p_pass].transform = p_transform; + light_instance->shadow_transform[p_pass].farplane = p_far; + light_instance->shadow_transform[p_pass].split = p_split; + light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; +} + +void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) { + + LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->last_scene_pass = scene_pass; +} + +RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_size) { + + if (!shadow_cubemaps.has(p_size)) { + + ShadowCubemap sc; + { + RD::TextureFormat tf; + tf.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; + tf.width = p_size; + tf.height = p_size; + tf.type = RD::TEXTURE_TYPE_CUBE; + tf.array_layers = 6; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + for (int i = 0; i < 6; i++) { + RID side_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sc.cubemap, i, 0); + Vector fbtex; + fbtex.push_back(side_texture); + sc.side_fb[i] = RD::get_singleton()->framebuffer_create(fbtex); + } + + shadow_cubemaps[p_size] = sc; + } + + return &shadow_cubemaps[p_size]; +} + +RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p_size) { + + if (!shadow_maps.has(p_size)) { + + ShadowMap sm; + { + RD::TextureFormat tf; + tf.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; + tf.width = p_size.width; + tf.height = p_size.height; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + sm.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + Vector fbtex; + fbtex.push_back(sm.depth); + sm.fb = RD::get_singleton()->framebuffer_create(fbtex); + + shadow_maps[p_size] = sm; + } + + return &shadow_maps[p_size]; +} + +//////////////////////////////// RID RasterizerSceneRD::render_buffers_create() { RenderBuffers rb; rb.data = _create_render_buffer_data(); @@ -440,12 +1078,200 @@ bool RasterizerSceneRD::is_using_radiance_cubemap_array() const { return sky_use_cubemap_array; } -void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { +void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb && p_render_buffers.is_valid()); - _render_scene(rb->data, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass); + _render_scene(rb->data, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_probe, p_reflection_probe_pass); +} + +void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { + + LightInstance *light_instance = light_instance_owner.getornull(p_light); + ERR_FAIL_COND(!light_instance); + + Rect2i atlas_rect; + RID atlas_fb; + int atlas_fb_size; + + bool using_dual_paraboloid = false; + bool using_dual_paraboloid_flip = false; + float zfar = 0; + RID render_fb; + RID render_texture; + float bias = 0; + float normal_bias = 0; + + bool render_cubemap = false; + bool finalize_cubemap = false; + + CameraMatrix light_projection; + Transform light_transform; + + if (storage->light_get_type(light_instance->light) == VS::LIGHT_DIRECTIONAL) { + //set pssm stuff + if (light_instance->last_scene_shadow_pass != scene_pass) { + //assign rect if unassigned + light_instance->light_directional_index = directional_shadow.current_light; + light_instance->last_scene_shadow_pass = scene_pass; + directional_shadow.current_light++; + + if (directional_shadow.light_count == 1) { + light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size); + } else if (directional_shadow.light_count == 2) { + light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size / 2); + if (light_instance->light_directional_index == 1) { + light_instance->directional_rect.position.x += light_instance->directional_rect.size.x; + } + } else { //3 and 4 + light_instance->directional_rect = Rect2(0, 0, directional_shadow.size / 2, directional_shadow.size / 2); + if (light_instance->light_directional_index & 1) { + light_instance->directional_rect.position.x += light_instance->directional_rect.size.x; + } + if (light_instance->light_directional_index / 2) { + light_instance->directional_rect.position.y += light_instance->directional_rect.size.y; + } + } + } + + light_projection = light_instance->shadow_transform[p_pass].camera; + light_transform = light_instance->shadow_transform[p_pass].transform; + + atlas_rect.position.x = light_instance->directional_rect.position.x; + atlas_rect.position.y = light_instance->directional_rect.position.y; + atlas_rect.size.width = light_instance->directional_rect.size.x; + atlas_rect.size.height = light_instance->directional_rect.size.y; + + if (storage->light_directional_get_shadow_mode(light_instance->light) == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + + atlas_rect.size.width /= 2; + atlas_rect.size.height /= 2; + + if (p_pass == 1) { + atlas_rect.position.x += atlas_rect.size.width; + } else if (p_pass == 2) { + atlas_rect.position.y += atlas_rect.size.height; + } else if (p_pass == 3) { + atlas_rect.position.x += atlas_rect.size.width; + atlas_rect.position.y += atlas_rect.size.height; + } + + } else if (storage->light_directional_get_shadow_mode(light_instance->light) == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + + atlas_rect.size.height /= 2; + + if (p_pass == 0) { + + } else { + atlas_rect.position.y += atlas_rect.size.height; + } + } + + float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE)); + zfar = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_RANGE); + bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult; + normal_bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * bias_mult; + + ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); + render_fb = shadow_map->fb; + render_texture = shadow_map->depth; + atlas_fb = directional_shadow.fb; + atlas_fb_size = directional_shadow.size; + + } else { + //set from shadow atlas + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); + + uint32_t key = shadow_atlas->shadow_owners[p_light]; + + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size()); + + uint32_t quadrant_size = shadow_atlas->size >> 1; + + atlas_rect.position.x = (quadrant & 1) * quadrant_size; + atlas_rect.position.y = (quadrant >> 1) * quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + atlas_rect.size.width = shadow_size; + atlas_rect.size.height = shadow_size; + atlas_fb = shadow_atlas->fb; + atlas_fb_size = shadow_atlas->size; + + zfar = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_RANGE); + bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS); + normal_bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS); + + if (storage->light_get_type(light_instance->light) == VS::LIGHT_OMNI) { + + if (storage->light_omni_get_shadow_mode(light_instance->light) == VS::LIGHT_OMNI_SHADOW_CUBE) { + + ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2); + + render_fb = cubemap->side_fb[p_pass]; + render_texture = cubemap->cubemap; + + light_projection = light_instance->shadow_transform[0].camera; + light_transform = light_instance->shadow_transform[0].transform; + render_cubemap = true; + finalize_cubemap = p_pass == 5; + + } else { + + light_projection = light_instance->shadow_transform[0].camera; + light_transform = light_instance->shadow_transform[0].transform; + + atlas_rect.size.height /= 2; + atlas_rect.position.y += p_pass * atlas_rect.size.height; + + using_dual_paraboloid = true; + using_dual_paraboloid_flip = p_pass == 1; + + ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); + render_fb = shadow_map->fb; + render_texture = shadow_map->depth; + } + + } else if (storage->light_get_type(light_instance->light) == VS::LIGHT_SPOT) { + + light_projection = light_instance->shadow_transform[0].camera; + light_transform = light_instance->shadow_transform[0].transform; + + ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); + render_fb = shadow_map->fb; + render_texture = shadow_map->depth; + } + } + + if (render_cubemap) { + //rendering to cubemap + _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false); + if (finalize_cubemap) { + //reblit + atlas_rect.size.height /= 2; + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), bias, false); + atlas_rect.position.y += atlas_rect.size.height; + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), bias, true); + } + } else { + //render shadow + _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip); + + //copy to atlas + storage->get_effects()->copy_to_rect(render_texture, atlas_fb, atlas_rect, true); + + //does not work from depth to color + //RD::get_singleton()->texture_copy(render_texture, atlas_texture, Vector3(0, 0, 0), Vector3(atlas_rect.position.x, atlas_rect.position.y, 0), Vector3(atlas_rect.size.x, atlas_rect.size.y, 1), 0, 0, 0, 0, true); + } } bool RasterizerSceneRD::free(RID p_rid) { @@ -457,11 +1283,39 @@ bool RasterizerSceneRD::free(RID p_rid) { } else if (environment_owner.owns(p_rid)) { //not much to delete, just free it environment_owner.free(p_rid); + } else if (reflection_probe_instance_owner.owns(p_rid)) { + //not much to delete, just free it + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid); + _clear_reflection_data(rpi->reflection); + reflection_probe_instance_owner.free(p_rid); } else if (sky_owner.owns(p_rid)) { _update_dirty_skys(); Sky *sky = sky_owner.getornull(p_rid); - RD::get_singleton()->free(sky->radiance); //free radiance, everything else gets dependency-erased + _clear_reflection_data(sky->reflection); sky_owner.free(p_rid); + } else if (light_instance_owner.owns(p_rid)) { + + LightInstance *light_instance = light_instance_owner.getornull(p_rid); + + //remove from shadow atlases.. + for (Set::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(E->get()); + ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); + uint32_t key = shadow_atlas->shadow_owners[p_rid]; + uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; + + shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); + shadow_atlas->shadow_owners.erase(p_rid); + } + + light_instance_owner.free(p_rid); + + } else if (shadow_atlas_owner.owns(p_rid)) { + + shadow_atlas_set_size(p_rid, 0); + shadow_atlas_owner.free(p_rid); + } else { return false; } @@ -482,3 +1336,14 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); sky_use_cubemap_array = false; } + +RasterizerSceneRD::~RasterizerSceneRD() { + directional_shadow_atlas_set_size(0); + + for (Map::Element *E = shadow_maps.front(); E; E = E->next()) { + RD::get_singleton()->free(E->get().depth); + } + for (Map::Element *E = shadow_cubemaps.front(); E; E = E->next()) { + RD::get_singleton()->free(E->get().cubemap); + } +} diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h index c333c4b10c3f..83316079d1be 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h @@ -15,20 +15,17 @@ protected: }; virtual RenderBufferData *_create_render_buffer_data() = 0; - virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; + virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_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; private: int roughness_layers; RasterizerStorageRD *storage; - struct Sky { - int radiance_size = 256; - VS::SkyMode mode = VS::SKY_MODE_QUALITY; - RID panorama; + struct ReflectionData { RID radiance; - bool dirty = false; - Sky *dirty_list = nullptr; + struct Layer { struct Mipmap { RID framebuffers[6]; @@ -38,9 +35,26 @@ private: Vector mipmaps; }; RID radiance_base_cubemap; //cubemap for first layer, first cubemap + Vector layers; }; + void _clear_reflection_data(ReflectionData &rd); + void _update_reflection_data(ReflectionData &rd, int p_size, bool p_quality); + void _create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality); + void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_quality, int p_cube_side); + void _update_reflection_mipmaps(ReflectionData &rd, bool p_quality); + + /* SKY */ + struct Sky { + int radiance_size = 256; + VS::SkyMode mode = VS::SKY_MODE_QUALITY; + RID panorama; + ReflectionData reflection; + bool dirty = false; + Sky *dirty_list = nullptr; + }; + Sky *dirty_sky_list = nullptr; void _sky_invalidate(Sky *p_sky); @@ -52,6 +66,156 @@ private: mutable RID_Owner sky_owner; + /* REFLECTION PROBE INSTANCE */ + + struct ReflectionProbeInstance { + + RID probe; + + ReflectionData reflection; + RID depth_buffer; + RID render_fb[6]; + + int current_resolution = 0; + + bool dirty = true; + bool rendering = false; + int processing_side = 0; + + uint32_t render_index = 0; + + Transform transform; + }; + + mutable RID_Owner reflection_probe_instance_owner; + + /* SHADOW ATLAS */ + + struct ShadowAtlas { + + enum { + QUADRANT_SHIFT = 27, + SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1, + SHADOW_INVALID = 0xFFFFFFFF + }; + + struct Quadrant { + + uint32_t subdivision; + + struct Shadow { + RID owner; + uint64_t version; + uint64_t alloc_tick; + + Shadow() { + version = 0; + alloc_tick = 0; + } + }; + + Vector shadows; + + Quadrant() { + subdivision = 0; //not in use + } + + } quadrants[4]; + + int size_order[4] = { 0, 1, 2, 3 }; + uint32_t smallest_subdiv = 0; + + int size = 0; + + RID depth; + RID fb; //for copying + + Map shadow_owners; + }; + + RID_Owner shadow_atlas_owner; + + bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); + + /* DIRECTIONAL SHADOW */ + + struct DirectionalShadow { + RID depth; + RID fb; //for copying + + int light_count = 0; + int size = 0; + int current_light = 0; + } directional_shadow; + + /* SHADOW CUBEMAPS */ + + struct ShadowCubemap { + + RID cubemap; + RID side_fb[6]; + }; + + Map shadow_cubemaps; + ShadowCubemap *_get_shadow_cubemap(int p_size); + + struct ShadowMap { + RID depth; + RID fb; + }; + + Map shadow_maps; + ShadowMap *_get_shadow_map(const Size2i &p_size); + + void _create_shadow_cubemaps(); + + /* LIGHT INSTANCE */ + + struct LightInstance { + + struct ShadowTransform { + + CameraMatrix camera; + Transform transform; + float farplane; + float split; + float bias_scale; + }; + + VS::LightType light_type; + + ShadowTransform shadow_transform[4]; + + RID self; + RID light; + Transform transform; + + Vector3 light_vector; + Vector3 spot_vector; + float linear_att; + + uint64_t shadow_pass = 0; + uint64_t last_scene_pass = 0; + uint64_t last_scene_shadow_pass = 0; + uint64_t last_pass = 0; + uint32_t light_index = 0; + uint32_t light_directional_index = 0; + + uint32_t current_shadow_atlas_key; + + Vector2 dp; + + Rect2 directional_rect; + + Set shadow_atlases; //shadow atlases where this light is registered + + LightInstance() {} + }; + + mutable RID_Owner light_instance_owner; + + /* ENVIRONMENT */ + struct Environent { // BG @@ -82,6 +246,8 @@ private: mutable RID_Owner environment_owner; + /* RENDER BUFFERS */ + struct RenderBuffers { RenderBufferData *data = nullptr; @@ -92,16 +258,45 @@ private: mutable RID_Owner render_buffers_owner; + uint64_t scene_pass = 0; + uint64_t shadow_atlas_realloc_tolerance_msec = 500; + public: /* SHADOW ATLAS API */ - RID shadow_atlas_create() { return RID(); } - void shadow_atlas_set_size(RID p_atlas, int p_size) {} - void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {} - bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { return false; } + RID shadow_atlas_create(); + void shadow_atlas_set_size(RID p_atlas, int p_size); + void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); + bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version); + _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { + ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND_V(!atlas, false); + return atlas->shadow_owners.has(p_light_intance); + } - int get_directional_light_shadow_size(RID p_light_intance) { return 0; } - void set_directional_shadow_count(int p_count) {} + _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) { + ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->depth; + } + + _FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) { + ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND_V(!atlas, Size2i()); + return Size2(atlas->size, atlas->size); + } + + void directional_shadow_atlas_set_size(int p_size); + int get_directional_light_shadow_size(RID p_light_intance); + void set_directional_shadow_count(int p_count); + + _FORCE_INLINE_ RID directional_shadow_get_texture() { + return directional_shadow.depth; + } + + _FORCE_INLINE_ Size2i directional_shadow_get_size() { + return Size2i(directional_shadow.size, directional_shadow.size); + } /* SKY API */ @@ -166,22 +361,121 @@ public: void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {} - RID light_instance_create(RID p_light) { return RID(); } - void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {} - void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0) {} - void light_instance_mark_visible(RID p_light_instance) {} + RID light_instance_create(RID p_light); + void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); + void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0); + void light_instance_mark_visible(RID p_light_instance); - RID reflection_atlas_create() { return RID(); } - void reflection_atlas_set_size(RID p_ref_atlas, int p_size) {} - void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv) {} + _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->light; + } - RID reflection_probe_instance_create(RID p_probe) { return RID(); } - void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {} - void reflection_probe_release_atlas_index(RID p_instance) {} - bool reflection_probe_instance_needs_redraw(RID p_instance) { return false; } - bool reflection_probe_instance_has_reflection(RID p_instance) { return false; } - bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { return false; } - bool reflection_probe_instance_postprocess_step(RID p_instance) { return true; } + _FORCE_INLINE_ Transform light_instance_get_base_transform(RID p_light_instance) { + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->transform; + } + + _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas) { + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + LightInstance *li = light_instance_owner.getornull(p_light_instance); + uint32_t key = shadow_atlas->shadow_owners[li->self]; + + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2()); + + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size >> 1; + + uint32_t x = (quadrant & 1) * quadrant_size; + uint32_t y = (quadrant >> 1) * quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + uint32_t width = shadow_size; + uint32_t height = shadow_size; + + return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size)); + } + + _FORCE_INLINE_ CameraMatrix light_instance_get_shadow_camera(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].camera; + } + + _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) { + LightInstance *li = light_instance_owner.getornull(p_light_instance); + li->last_pass = p_pass; + } + + _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) { + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->last_pass; + } + + _FORCE_INLINE_ void light_instance_set_index(RID p_light_instance, uint32_t p_index) { + LightInstance *li = light_instance_owner.getornull(p_light_instance); + li->light_index = p_index; + } + + _FORCE_INLINE_ uint32_t light_instance_get_index(RID p_light_instance) { + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->light_index; + } + + _FORCE_INLINE_ VS::LightType light_instance_get_type(RID p_light_instance) { + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->light_type; + } + + virtual RID reflection_probe_instance_create(RID p_probe); + virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform); + virtual bool reflection_probe_instance_needs_redraw(RID p_instance); + virtual void reflection_probe_instance_begin_render(RID p_instance); + virtual bool reflection_probe_instance_postprocess_step(RID p_instance); + + uint32_t reflection_probe_instance_get_resolution(RID p_instance); + RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index); + + _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, RID()); + + return rpi->probe; + } + + _FORCE_INLINE_ void reflection_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + rpi->render_index = p_render_index; + } + + _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_index(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, 0); + + return rpi->render_index; + } + + _FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, Transform()); + + return rpi->transform; + } + + _FORCE_INLINE_ RID reflection_probe_instance_get_texture(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, RID()); + + return rpi->reflection.radiance; + } RID gi_probe_instance_create() { return RID(); } void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) {} @@ -191,7 +485,12 @@ public: RID render_buffers_create(); void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa); - void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + + void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); + + virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; } + _FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; } int get_roughness_layers() const; bool is_using_radiance_cubemap_array() const; @@ -201,6 +500,7 @@ public: virtual void update(); RasterizerSceneRD(RasterizerStorageRD *p_storage); + ~RasterizerSceneRD(); }; #endif // RASTERIZER_SCENE_RD_H diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp index 5ed90490dc46..b5dffc7762b1 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -2087,6 +2087,462 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers); } +/* LIGHT */ + +RID RasterizerStorageRD::light_create(VS::LightType p_type) { + + Light light; + light.type = p_type; + + light.param[VS::LIGHT_PARAM_ENERGY] = 1.0; + light.param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0; + light.param[VS::LIGHT_PARAM_SPECULAR] = 0.5; + light.param[VS::LIGHT_PARAM_RANGE] = 1.0; + light.param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45; + light.param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45; + light.param[VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0; + light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1; + light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; + light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; + light.param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1; + light.param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1; + + return light_owner.make_rid(light); +} + +void RasterizerStorageRD::light_set_color(RID p_light, const Color &p_color) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->color = p_color; +} +void RasterizerStorageRD::light_set_param(RID p_light, VS::LightParam p_param, float p_value) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX(p_param, VS::LIGHT_PARAM_MAX); + + switch (p_param) { + case VS::LIGHT_PARAM_RANGE: + case VS::LIGHT_PARAM_SPOT_ANGLE: + case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE: + case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET: + case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: + case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: + case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: + case VS::LIGHT_PARAM_SHADOW_BIAS: { + + light->version++; + light->instance_dependency.instance_notify_changed(true, false); + } break; + default: { + } + } + + light->param[p_param] = p_value; +} +void RasterizerStorageRD::light_set_shadow(RID p_light, bool p_enabled) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + light->shadow = p_enabled; + + light->version++; + light->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + light->shadow_color = p_color; +} + +void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->projector = p_texture; +} + +void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->negative = p_enable; +} +void RasterizerStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->cull_mask = p_mask; + + light->version++; + light->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->reverse_cull = p_enabled; + + light->version++; + light->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::light_set_use_gi(RID p_light, bool p_enabled) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->use_gi = p_enabled; + + light->version++; + light->instance_dependency.instance_notify_changed(true, false); +} +void RasterizerStorageRD::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->omni_shadow_mode = p_mode; + + light->version++; + light->instance_dependency.instance_notify_changed(true, false); +} + +VS::LightOmniShadowMode RasterizerStorageRD::light_omni_get_shadow_mode(RID p_light) { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, VS::LIGHT_OMNI_SHADOW_CUBE); + + return light->omni_shadow_mode; +} + +void RasterizerStorageRD::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->directional_shadow_mode = p_mode; + light->version++; + light->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->directional_blend_splits = p_enable; + light->version++; + light->instance_dependency.instance_notify_changed(true, false); +} + +bool RasterizerStorageRD::light_directional_get_blend_splits(RID p_light) const { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, false); + + return light->directional_blend_splits; +} + +VS::LightDirectionalShadowMode RasterizerStorageRD::light_directional_get_shadow_mode(RID p_light) { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); + + return light->directional_shadow_mode; +} + +void RasterizerStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->directional_range_mode = p_range_mode; +} + +VS::LightDirectionalShadowDepthRangeMode RasterizerStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE); + + return light->directional_range_mode; +} + +bool RasterizerStorageRD::light_get_use_gi(RID p_light) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, false); + + return light->use_gi; +} + +uint64_t RasterizerStorageRD::light_get_version(RID p_light) const { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, 0); + + return light->version; +} + +AABB RasterizerStorageRD::light_get_aabb(RID p_light) const { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, AABB()); + + switch (light->type) { + + case VS::LIGHT_SPOT: { + + float len = light->param[VS::LIGHT_PARAM_RANGE]; + float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len; + return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); + }; + case VS::LIGHT_OMNI: { + + float r = light->param[VS::LIGHT_PARAM_RANGE]; + return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2); + }; + case VS::LIGHT_DIRECTIONAL: { + + return AABB(); + }; + } + + ERR_FAIL_V(AABB()); +} + +/* REFLECTION PROBE */ + +RID RasterizerStorageRD::reflection_probe_create() { + + return reflection_probe_owner.make_rid(ReflectionProbe()); +} + +void RasterizerStorageRD::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->update_mode = p_mode; + reflection_probe->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->intensity = p_intensity; +} + +void RasterizerStorageRD::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient = p_ambient; +} + +void RasterizerStorageRD::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_energy = p_energy; +} + +void RasterizerStorageRD::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_probe_contrib = p_contrib; +} + +void RasterizerStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->max_distance = p_distance; + + reflection_probe->instance_dependency.instance_notify_changed(true, false); +} +void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->extents = p_extents; + reflection_probe->instance_dependency.instance_notify_changed(true, false); +} +void RasterizerStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->origin_offset = p_offset; + reflection_probe->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior = p_enable; + reflection_probe->instance_dependency.instance_notify_changed(true, false); +} +void RasterizerStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->box_projection = p_enable; +} + +void RasterizerStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->enable_shadows = p_enable; + reflection_probe->instance_dependency.instance_notify_changed(true, false); +} +void RasterizerStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->cull_mask = p_layers; + reflection_probe->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + ERR_FAIL_COND(p_resolution < 32); + + reflection_probe->resolution = p_resolution; +} + +AABB RasterizerStorageRD::reflection_probe_get_aabb(RID p_probe) const { + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, AABB()); + + AABB aabb; + aabb.position = -reflection_probe->extents; + aabb.size = reflection_probe->extents * 2.0; + + return aabb; +} +VS::ReflectionProbeUpdateMode RasterizerStorageRD::reflection_probe_get_update_mode(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, VS::REFLECTION_PROBE_UPDATE_ALWAYS); + + return reflection_probe->update_mode; +} + +uint32_t RasterizerStorageRD::reflection_probe_get_cull_mask(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->cull_mask; +} + +Vector3 RasterizerStorageRD::reflection_probe_get_extents(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, Vector3()); + + return reflection_probe->extents; +} +Vector3 RasterizerStorageRD::reflection_probe_get_origin_offset(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, Vector3()); + + return reflection_probe->origin_offset; +} + +bool RasterizerStorageRD::reflection_probe_renders_shadows(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, false); + + return reflection_probe->enable_shadows; +} + +float RasterizerStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->max_distance; +} + +int RasterizerStorageRD::reflection_probe_get_resolution(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->resolution; +} + +float RasterizerStorageRD::reflection_probe_get_intensity(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->intensity; +} +bool RasterizerStorageRD::reflection_probe_is_interior(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, false); + + return reflection_probe->interior; +} +bool RasterizerStorageRD::reflection_probe_is_box_projection(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, false); + + return reflection_probe->box_projection; +} + +Color RasterizerStorageRD::reflection_probe_get_interior_ambient(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, Color()); + + return reflection_probe->interior_ambient; +} +float RasterizerStorageRD::reflection_probe_get_interior_ambient_energy(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->interior_ambient_energy; +} +float RasterizerStorageRD::reflection_probe_get_interior_ambient_probe_contribution(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->interior_ambient_probe_contrib; +} + /* RENDER TARGET API */ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { @@ -2432,6 +2888,12 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In if (mesh_owner.owns(p_base)) { Mesh *mesh = mesh_owner.getornull(p_base); p_instance->update_dependency(&mesh->instance_dependency); + } else if (reflection_probe_owner.owns(p_base)) { + ReflectionProbe *rp = reflection_probe_owner.getornull(p_base); + p_instance->update_dependency(&rp->instance_dependency); + } else if (light_owner.owns(p_base)) { + Light *l = light_owner.getornull(p_base); + p_instance->update_dependency(&l->instance_dependency); } } @@ -2440,6 +2902,13 @@ VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return VS::INSTANCE_MESH; } + if (reflection_probe_owner.owns(p_rid)) { + return VS::INSTANCE_REFLECTION_PROBE; + } + if (light_owner.owns(p_rid)) { + return VS::INSTANCE_LIGHT; + } + return VS::INSTANCE_NONE; } void RasterizerStorageRD::update_dirty_resources() { @@ -2461,6 +2930,13 @@ bool RasterizerStorageRD::free(RID p_rid) { RD::get_singleton()->free(t->rd_texture); } + if (t->is_proxy && t->proxy_to.is_valid()) { + Texture *proxy_to = texture_owner.getornull(t->proxy_to); + if (proxy_to) { + proxy_to->proxies.erase(p_rid); + } + } + for (int i = 0; i < t->proxies.size(); i++) { Texture *p = texture_owner.getornull(t->proxies[i]); ERR_CONTINUE(!p); @@ -2495,6 +2971,18 @@ bool RasterizerStorageRD::free(RID p_rid) { Mesh *mesh = mesh_owner.getornull(p_rid); mesh->instance_dependency.instance_notify_deleted(p_rid); mesh_owner.free(p_rid); + } else if (reflection_probe_owner.owns(p_rid)) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); + reflection_probe->instance_dependency.instance_notify_deleted(p_rid); + reflection_probe_owner.free(p_rid); + + } else if (light_owner.owns(p_rid)) { + + // delete the texture + Light *light = light_owner.getornull(p_rid); + light->instance_dependency.instance_notify_deleted(p_rid); + light_owner.free(p_rid); + } else if (render_target_owner.owns(p_rid)) { RenderTarget *rt = render_target_owner.getornull(p_rid); @@ -2606,7 +3094,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE; + tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY; PoolVector pv; pv.resize(16 * 4); @@ -2634,7 +3122,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tformat.type = RD::TEXTURE_TYPE_CUBE; PoolVector pv; pv.resize(16 * 4); @@ -2680,34 +3168,6 @@ RasterizerStorageRD::RasterizerStorageRD() { } } - { //create default cubemap array - - RD::TextureFormat tformat; - tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; - tformat.width = 4; - tformat.height = 4; - tformat.array_layers = 6; - tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY; - - PoolVector pv; - pv.resize(16 * 4); - for (int i = 0; i < 16; i++) { - pv.set(i * 4 + 0, 0); - pv.set(i * 4 + 1, 0); - pv.set(i * 4 + 2, 0); - pv.set(i * 4 + 3, 0); - } - - { - Vector > vpv; - for (int i = 0; i < 6; i++) { - vpv.push_back(pv); - } - default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); - } - } - //default samplers for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h index 4059331790a0..3cfd5601e8c2 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -251,6 +251,12 @@ private: RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed RID material; + + uint32_t render_index = 0; + uint64_t render_pass = 0; + + uint32_t multimesh_render_index = 0; + uint64_t multimesh_render_pass = 0; }; uint32_t blend_shape_count = 0; @@ -275,6 +281,54 @@ private: RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX]; + /* LIGHT */ + + struct Light { + + VS::LightType type; + float param[VS::LIGHT_PARAM_MAX]; + Color color = Color(1, 1, 1, 1); + Color shadow_color; + RID projector; + bool shadow = false; + bool negative = false; + bool reverse_cull = false; + bool use_gi = true; + uint32_t cull_mask = 0xFFFFFFFF; + VS::LightOmniShadowMode omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; + VS::LightDirectionalShadowMode directional_shadow_mode = VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; + VS::LightDirectionalShadowDepthRangeMode directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; + bool directional_blend_splits = false; + uint64_t version = 0; + + RasterizerScene::InstanceDependency instance_dependency; + }; + + mutable RID_Owner light_owner; + + /* REFLECTION PROBE */ + + struct ReflectionProbe { + + VS::ReflectionProbeUpdateMode update_mode = VS::REFLECTION_PROBE_UPDATE_ONCE; + int resolution = 256; + float intensity = 1.0; + Color interior_ambient; + float interior_ambient_energy = 1.0; + float interior_ambient_probe_contrib = 0.0; + float max_distance = 0; + Vector3 extents = Vector3(1, 1, 1); + Vector3 origin_offset; + bool interior = false; + bool box_projection = false; + bool enable_shadows = false; + uint32_t cull_mask = (1 << 20) - 1; + + RasterizerScene::InstanceDependency instance_dependency; + }; + + mutable RID_Owner reflection_probe_owner; + /* RENDER TARGET */ struct RenderTarget { @@ -530,6 +584,32 @@ public: return mesh_default_rd_buffers[p_buffer]; } + _FORCE_INLINE_ uint32_t mesh_surface_get_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh::Surface *s = mesh->surfaces[p_surface_index]; + + if (s->render_pass != p_render_pass) { + (*r_index)++; + s->render_pass = p_render_pass; + s->render_index = *r_index; + } + + return s->render_index; + } + + _FORCE_INLINE_ uint32_t mesh_surface_get_multimesh_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh::Surface *s = mesh->surfaces[p_surface_index]; + + if (s->multimesh_render_pass != p_render_pass) { + (*r_index)++; + s->multimesh_render_pass = p_render_pass; + s->multimesh_render_index = *r_index; + } + + return s->multimesh_render_index; + } + /* MULTIMESH API */ virtual RID multimesh_create() { return RID(); } @@ -587,68 +667,125 @@ public: /* Light API */ - RID light_create(VS::LightType p_type) { return RID(); } + RID light_create(VS::LightType p_type); RID directional_light_create() { return light_create(VS::LIGHT_DIRECTIONAL); } RID omni_light_create() { return light_create(VS::LIGHT_OMNI); } RID spot_light_create() { return light_create(VS::LIGHT_SPOT); } - void light_set_color(RID p_light, const Color &p_color) {} - void light_set_param(RID p_light, VS::LightParam p_param, float p_value) {} - void light_set_shadow(RID p_light, bool p_enabled) {} - void light_set_shadow_color(RID p_light, const Color &p_color) {} - void light_set_projector(RID p_light, RID p_texture) {} - void light_set_negative(RID p_light, bool p_enable) {} - void light_set_cull_mask(RID p_light, uint32_t p_mask) {} - void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {} - void light_set_use_gi(RID p_light, bool p_enabled) {} + void light_set_color(RID p_light, const Color &p_color); + void light_set_param(RID p_light, VS::LightParam p_param, float p_value); + void light_set_shadow(RID p_light, bool p_enabled); + void light_set_shadow_color(RID p_light, const Color &p_color); + void light_set_projector(RID p_light, RID p_texture); + void light_set_negative(RID p_light, bool p_enable); + void light_set_cull_mask(RID p_light, uint32_t p_mask); + void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled); + void light_set_use_gi(RID p_light, bool p_enabled); - void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) {} - void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail) {} + void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode); - void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) {} - void light_directional_set_blend_splits(RID p_light, bool p_enable) {} - bool light_directional_get_blend_splits(RID p_light) const { return false; } - void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) {} - VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const { return VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; } + void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode); + void light_directional_set_blend_splits(RID p_light, bool p_enable); + bool light_directional_get_blend_splits(RID p_light) const; + void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode); + VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const; - VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) { return VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; } - VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) { return VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; } + VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); + VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); - bool light_has_shadow(RID p_light) const { return false; } + _FORCE_INLINE_ VS::LightType light_get_type(RID p_light) const { + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL); - VS::LightType light_get_type(RID p_light) const { return VS::LIGHT_OMNI; } - AABB light_get_aabb(RID p_light) const { return AABB(); } - float light_get_param(RID p_light, VS::LightParam p_param) { return 0.0; } - Color light_get_color(RID p_light) { return Color(); } - bool light_get_use_gi(RID p_light) { return false; } - uint64_t light_get_version(RID p_light) const { return 0; } + return light->type; + } + AABB light_get_aabb(RID p_light) const; + + _FORCE_INLINE_ float light_get_param(RID p_light, VS::LightParam p_param) { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, 0); + + return light->param[p_param]; + } + + _FORCE_INLINE_ Color light_get_color(RID p_light) { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, Color()); + + return light->color; + } + + _FORCE_INLINE_ Color light_get_shadow_color(RID p_light) { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, Color()); + + return light->shadow_color; + } + + _FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, 0); + + return light->cull_mask; + } + + _FORCE_INLINE_ bool light_has_shadow(RID p_light) const { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL); + + return light->shadow; + } + + _FORCE_INLINE_ bool light_is_negative(RID p_light) const { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL); + + return light->negative; + } + + bool light_get_use_gi(RID p_light); + uint64_t light_get_version(RID p_light) const; /* PROBE API */ - RID reflection_probe_create() { return RID(); } + RID reflection_probe_create(); - void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) {} - void reflection_probe_set_intensity(RID p_probe, float p_intensity) {} - void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) {} - void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) {} - void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) {} - void reflection_probe_set_max_distance(RID p_probe, float p_distance) {} - void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {} - void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {} - void reflection_probe_set_as_interior(RID p_probe, bool p_enable) {} - void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {} - void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {} - void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {} - void reflection_probe_set_resolution(RID p_probe, int p_resolution) {} + void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode); + void reflection_probe_set_intensity(RID p_probe, float p_intensity); + void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient); + void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy); + void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib); + void reflection_probe_set_max_distance(RID p_probe, float p_distance); + void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents); + void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset); + void reflection_probe_set_as_interior(RID p_probe, bool p_enable); + void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); + void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); + void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + void reflection_probe_set_resolution(RID p_probe, int p_resolution); - AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); } - VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return VisualServer::REFLECTION_PROBE_UPDATE_ONCE; } - uint32_t reflection_probe_get_cull_mask(RID p_probe) const { return 0; } - Vector3 reflection_probe_get_extents(RID p_probe) const { return Vector3(); } - Vector3 reflection_probe_get_origin_offset(RID p_probe) const { return Vector3(); } - float reflection_probe_get_origin_max_distance(RID p_probe) const { return 0.0; } - bool reflection_probe_renders_shadows(RID p_probe) const { return false; } + AABB reflection_probe_get_aabb(RID p_probe) const; + VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; + uint32_t reflection_probe_get_cull_mask(RID p_probe) const; + Vector3 reflection_probe_get_extents(RID p_probe) const; + Vector3 reflection_probe_get_origin_offset(RID p_probe) const; + float reflection_probe_get_origin_max_distance(RID p_probe) const; + int reflection_probe_get_resolution(RID p_probe) const; + bool reflection_probe_renders_shadows(RID p_probe) const; + + float reflection_probe_get_intensity(RID p_probe) const; + bool reflection_probe_is_interior(RID p_probe) const; + bool reflection_probe_is_box_projection(RID p_probe) const; + Color reflection_probe_get_interior_ambient(RID p_probe) const; + float reflection_probe_get_interior_ambient_energy(RID p_probe) const; + float reflection_probe_get_interior_ambient_probe_contribution(RID p_probe) const; void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {} diff --git a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h index 2c3de2dbed55..70404f2cfdcc 100644 --- a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h +++ b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h @@ -31,10 +31,13 @@ #ifndef RENDER_PIPELINE_CACHE_RD_H #define RENDER_PIPELINE_CACHE_RD_H +#include "core/spin_lock.h" #include "servers/visual/rendering_device.h" class RenderPipelineVertexFormatCacheRD { + SpinLock spin_lock; + RID shader; uint32_t input_mask; @@ -68,12 +71,19 @@ public: ERR_FAIL_COND_V_MSG(shader.is_null(), RID(), "Attempted to use an unused shader variant (shader is null),"); #endif + + spin_lock.lock(); + RID result; for (uint32_t i = 0; i < version_count; i++) { if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id) { - return versions[i].pipeline; + result = versions[i].pipeline; + spin_lock.unlock(); + return result; } } - return _generate_version(p_vertex_format_id, p_framebuffer_format_id); + result = _generate_version(p_vertex_format_id, p_framebuffer_format_id); + spin_lock.unlock(); + return result; } _FORCE_INLINE_ uint32_t get_vertex_input_mask() const { diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub index 0a4bebcfbc18..b1fa9cd3f464 100644 --- a/servers/visual/rasterizer_rd/shaders/SCsub +++ b/servers/visual/rasterizer_rd/shaders/SCsub @@ -10,4 +10,5 @@ if 'RD_GLSL' in env['BUILDERS']: env.RD_GLSL('scene_forward.glsl'); env.RD_GLSL('sky.glsl'); env.RD_GLSL('tonemap.glsl'); + env.RD_GLSL('copy.glsl'); diff --git a/servers/visual/rasterizer_rd/shaders/blur.glsl b/servers/visual/rasterizer_rd/shaders/blur.glsl index 4f47595d2c30..5907e911a350 100644 --- a/servers/visual/rasterizer_rd/shaders/blur.glsl +++ b/servers/visual/rasterizer_rd/shaders/blur.glsl @@ -23,6 +23,10 @@ void main() { gl_Position = vec4( uv_interp *2.0 - 1.0, 0.0, 1.0); + if (bool(blur.flags&FLAG_FLIP_Y)) { + uv_interp.y = 1.0 - uv_interp.y; + } + } /* clang-format off */ diff --git a/servers/visual/rasterizer_rd/shaders/blur_inc.glsl b/servers/visual/rasterizer_rd/shaders/blur_inc.glsl index ea932130aa0b..275b547fc4c1 100644 --- a/servers/visual/rasterizer_rd/shaders/blur_inc.glsl +++ b/servers/visual/rasterizer_rd/shaders/blur_inc.glsl @@ -3,6 +3,7 @@ #define FLAG_USE_ORTHOGONAL_PROJECTION (1<<2) #define FLAG_DOF_NEAR_FIRST_TAP (1<<3) #define FLAG_GLOW_FIRST_PASS (1<<4) +#define FLAG_FLIP_Y (1<<5) layout(push_constant, binding = 1, std430) uniform Blur { vec4 section; diff --git a/servers/visual/rasterizer_rd/shaders/copy.glsl b/servers/visual/rasterizer_rd/shaders/copy.glsl new file mode 100644 index 000000000000..e54b3972c0a5 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/copy.glsl @@ -0,0 +1,93 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +layout(location =0) out vec2 uv_interp; + +void main() { + + vec2 base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0)); + uv_interp = base_arr[gl_VertexIndex]; + + gl_Position = vec4( uv_interp *2.0 - 1.0, 0.0, 1.0); + +} + +/* clang-format off */ +[fragment] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +layout(location =0) in vec2 uv_interp; + +#ifdef MODE_CUBE_TO_DP + +layout( set=0, binding=0 ) uniform samplerCube source_cube; + +layout(push_constant, binding = 0, std430) uniform Params { + float bias; + float z_far; + float z_near; + bool z_flip; + +} params; + +layout(location=0) out float depth_buffer; + +#endif + + +void main() { + +#ifdef MODE_CUBE_TO_DP + + vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0); + + normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + + + normal.y = -normal.y; //needs to be flipped to match projection matrix + if (!params.z_flip) { + normal.z = -normal.z; + } + + float depth = texture(source_cube, normal).r; + + // absolute values for direction cosines, bigger value equals closer to basis axis + vec3 unorm = abs(normal); + + if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { + // x code + unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); + } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { + // y code + unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); + } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { + // z code + unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); + } else { + // oh-no we messed up code + // has to be + unorm = vec3(1.0, 0.0, 0.0); + } + + float depth_fix = 1.0 / dot(normal, unorm); + + depth = 2.0 * depth - 1.0; + float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth_buffer = (linear_depth * depth_fix + params.bias) / params.z_far; + +#endif +} diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl index df31d8c26fcd..3479929774ed 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl @@ -75,12 +75,26 @@ VERTEX_SHADER_GLOBALS // See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316 //invariant gl_Position; +layout(location =7) flat out uint instance_index; + +#ifdef MODE_DUAL_PARABOLOID + +layout(location =8) out float dp_clip; + +#endif + void main() { + instance_index = draw_call.instance_index; + + /*if (draw_call.instance_increment) { + instance_index += gl_InstanceIndex; + }*/ + vec3 vertex = vertex_attrib; - mat4 world_matrix = instance_data.transform; - mat3 world_normal_matrix= instance_data.normal_transform; + mat4 world_matrix = instances.data[instance_index].transform; + mat3 world_normal_matrix= mat3(instances.data[instance_index].normal_transform); vec3 normal = normal_attrib; @@ -131,8 +145,8 @@ void main() { float roughness = 1.0; - mat4 modelview = scene_data.inv_camera_matrix * instance_data.transform; - mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * instance_data.normal_transform; + mat4 modelview = scene_data.inv_camera_matrix * world_matrix; + mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix; { /* clang-format off */ @@ -179,14 +193,35 @@ VERTEX_SHADER_CODE #ifdef MODE_RENDER_DEPTH +#ifdef MODE_DUAL_PARABOLOID + + vertex_interp.z *= scene_data.dual_paraboloid_side; + normal_interp.z *= scene_data.dual_paraboloid_side; + + dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + vec3 vtx = vertex_interp + normalize(vertex_interp) * scene_data.z_offset; + float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy /= 1.0 - vtx.z; + vtx.z = (distance / scene_data.z_far); + vtx.z = vtx.z * 2.0 - 1.0; + + vertex_interp = vtx; +#else + float z_ofs = scene_data.z_offset; z_ofs += (1.0 - abs(normal_interp.z)) * scene_data.z_slope_scale; vertex_interp.z -= z_ofs; +#endif + #endif //MODE_RENDER_DEPTH #ifdef USE_OVERRIDE_POSITION - gl_Position = position; + gl_Position = position;; #else gl_Position = projection_matrix * vec4(vertex_interp, 1.0); #endif @@ -227,10 +262,19 @@ layout(location = 5) in vec3 tangent_interp; layout(location = 6) in vec3 binormal_interp; #endif +layout(location =7) flat in uint instance_index; + +#ifdef MODE_DUAL_PARABOLOID + +layout(location =8) in float dp_clip; + +#endif + + //defines to keep compatibility with vertex -#define world_matrix instance_data.transform; -#define world_normal_matrix instance_data.normal_transform; +#define world_matrix instances.data[instance_index].transform; +#define world_normal_matrix instances.data[instance_index].normal_transform; #define projection_matrix scene_data.projection_matrix; #ifdef USE_MATERIAL_UNIFORMS @@ -253,10 +297,14 @@ 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 + + // This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. // We're dividing this factor off because the overall term we'll end up looks like // (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): @@ -329,7 +377,24 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { +void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, vec3 attenuation, vec3 diffuse_color,float roughness, float metallic, float specular,float specular_blob_intensity, +#ifdef LIGHT_TRANSMISSION_USED + vec3 transmission, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 B, vec3 T,float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light + ) { #if defined(USE_LIGHT_SHADER_CODE) // light is written by the light shader @@ -419,11 +484,11 @@ LIGHT_SHADER_CODE diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; -#if defined(TRANSMISSION_USED) +#if defined(LIGHT_TRANSMISSION_USED) diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; #endif -#if defined(RIM_LIGHT_USED) +#if defined(LIGHT_RIM_USED) float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; #endif @@ -517,9 +582,209 @@ LIGHT_SHADER_CODE #endif //defined(USE_LIGHT_SHADER_CODE) } +#ifndef USE_NO_SHADOWS + +float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec2 pos, float depth) { + +#ifdef SHADOW_MODE_PCF_13 + + float avg = textureProj(shadow, vec4(pos, depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); + return avg * (1.0 / 13.0); +#endif + +#ifdef SHADOW_MODE_PCF_5 + + float avg = textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos, depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); + return avg * (1.0 / 5.0); + +#endif + +#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) + + return textureProj(sampler2DShadow(shadow,shadow_sampler), vec4(pos, depth, 1.0)); + +#endif +} + +#endif //USE_NO_SHADOWS + + +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo,float roughness, float metallic, float specular,float p_blob_intensity, +#ifdef LIGHT_TRANSMISSION_USED + vec3 transmission, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + + vec3 light_rel_vec = lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float normalized_distance = light_length * lights.data[idx].inv_radius; + vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); + float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x); + vec3 light_attenuation = vec3(omni_attenuation); + vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); + color_specular.rgb*=attenuation_energy.y; + +#ifndef USE_NO_SHADOWS + vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); + if (shadow_color_enabled.w > 0.5) { + // there is a shadowmap + + vec3 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; + float shadow_len = length(splane); + splane = normalize(splane); + vec4 clamp_rect = lights.data[idx].atlas_rect; + + if (splane.z >= 0.0) { + + splane.z += 1.0; + + clamp_rect.y += clamp_rect.w; + + } else { + + splane.z = 1.0 - splane.z; + + } + + splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len * lights.data[idx].inv_radius; + + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane.xy, splane.z); + + light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + } +#endif //USE_NO_SHADOWS + + light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, albedo, roughness, metallic, specular,color_specular.a * p_blob_intensity, +#ifdef LIGHT_TRANSMISSION_USED + transmission, +#endif +#ifdef LIGHT_RIM_USED + rim * omni_attenuation, rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha +#endif + diffuse_light, specular_light); +} + + + +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo,float roughness, float metallic, float specular,float p_blob_intensity, +#ifdef LIGHT_TRANSMISSION_USED + vec3 transmission, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + + vec3 light_rel_vec = lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float normalized_distance = light_length * lights.data[idx].inv_radius; + vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); + float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), attenuation_energy.x); + vec3 spot_dir = lights.data[idx].direction; + vec2 spot_att_angle = unpackHalf2x16(lights.data[idx].cone_attenuation_angle); + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y)); + spot_attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x); + vec3 light_attenuation = vec3(spot_attenuation); + vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); + color_specular.rgb*=attenuation_energy.y; + + + +/* + if (lights.data[idx].atlas_rect!=vec4(0.0)) { + //use projector texture + } + */ +#ifndef USE_NO_SHADOWS + vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); + if (shadow_color_enabled.w > 0.5) { + //there is a shadowmap + vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); + splane.xyz /= splane.w; + + float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane.xy, splane.z); + + light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + } + +#endif //USE_NO_SHADOWS + + light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, albedo, roughness, metallic, specular,color_specular.a * p_blob_intensity, +#ifdef LIGHT_TRANSMISSION_USED + transmission, +#endif +#ifdef LIGHT_RIM_USED + rim * omni_attenuation, rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); +} void main() { +#ifdef MODE_DUAL_PARABOLOID + + if (dp_clip > 0.0) + discard; +#endif //lay out everything, whathever is unused is optimized away anyway vec3 vertex = vertex_interp; @@ -701,14 +966,149 @@ FRAGMENT_SHADER_CODE specular_blob_intensity *= specular * 2.0; #endif +#ifndef MODE_RENDER_DEPTH //gi probes //lightmap //lightmap capture - //process reflections +#if 0 + { // process reflections + + vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); + vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); + + for (uint i = 0; i < MAX_REFLECTION_PROBES; i++) { + if (i >= draw_data.reflection_probe_count) { + break; + } + + uint ref_index; + if (i<4) { + if (i<2) { + ref_index=draw_data.reflection_probe_indices[0]; + } else { + ref_index=draw_data.reflection_probe_indices[1]; + } + } else { + if (i<6) { + ref_index=draw_data.reflection_probe_indices[2]; + } else { + ref_index=draw_data.reflection_probe_indices[3]; + } + } + ref_index>>=(i&1)*16; + ref_index&=0xFFFF; + + vec3 box_extents = reflections.data[ref_index].box_extents.xyz; + vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz; + + if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box + continue; + } + + vec3 ref_vec = normalize(reflect(vertex, normal)); + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + //make blend more rounded + blend = mix(length(inner_pos), blend, blend); + blend *= blend; + blend = max(0.0, 1.0 - blend); + + if (reflections.data[ref_index].params.x > 0.0) { // compute reflection + + vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; + + if (reflections.data[ref_index].params.w > 0.5) { //box project + + vec3 nrdir = normalize(local_ref_vec); + vec3 rbmax = (box_extents - local_pos) / nrdir; + vec3 rbmin = (-box_extents - local_pos) / nrdir; + + vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + local_ref_vec = posonbox - reflections.data[ref_index].box_offset.xyz; + } + + vec4 reflection; + +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + + float lod,layer_blend; + layer_blend = modf(roughness * MAX_ROUGHNESS_LOD, lod); + reflection.rgb = texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, lod)).rgb; + reflection.rgb = mix(reflection.rgb,texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, lod+1)).rgb,layer_blend); + +#else + reflection.rgb = textureLod(samplerCube(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), local_ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; + +#endif + + if (reflections.data[ref_index].params.z < 0.5) { + reflection.rgb = mix(specular_light, reflection.rgb, blend); + } + + reflection.rgb *= reflections.data[ref_index].params.x; + reflection.a = blend; + reflection.rgb *= reflection.a; + + reflection_accum += reflection; + } + +#ifndef USE_LIGHTMAP + if (reflections.data[ref_index].ambient.a > 0.0) { //compute ambient using skybox + + vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz; + + vec4 ambient_out; + +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + ambient_out.rgb = texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, MAX_ROUGHNESS_LOD)).rgb; +#else + ambient_out.rgb = textureLod(samplerCube(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), local_amb_vec, MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + + ambient_out.a = blend; + ambient_out.rgb = mix(reflections.data[ref_index].ambient.rgb, ambient_out.rgb, reflections.data[ref_index].ambient.a); + if (reflections.data[ref_index].params.z < 0.5) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } else { + + vec4 ambient_out; + ambient_out.a = blend; + ambient_out.rgb = reflections.data[ref_index].ambient.rgb; + if (reflections.data[ref_index].params.z < 0.5) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } +#endif //USE_LIGHTMAP + + } + + if (reflection_accum.a > 0.0) { + specular_light = reflection_accum.rgb / reflection_accum.a; + } + +#if !defined(USE_LIGHTMAP) + if (ambient_accum.a > 0.0) { + ambient_light = ambient_accum.rgb / ambient_accum.a; + } +#endif + + + } +#endif //0 { #if defined(DIFFUSE_TOON) @@ -734,8 +1134,86 @@ FRAGMENT_SHADER_CODE //directional light + { //omni lights + uint omni_light_count = (instances.data[instance_index].flags >> INSTANCE_FLAGS_FORWARD_OMNI_LIGHT_SHIFT) & INSTANCE_FLAGS_FORWARD_MASK; + for (uint i = 0; i < omni_light_count; i++) { - //process omni and spots + uint light_index = instances.data[instance_index].omni_light_indices[i>>1]; + + if (bool(i&1)) { + light_index>>=16; + } else { + light_index&=0xFFFF; + } + + //this is done on CPU, so no need to do it here + //if (!bool(lights.data[light_index].mask&instances.data[instance_index].layer_mask)) { + // continue; //not masked + //} + + light_process_omni(light_index, vertex, view, normal, albedo, roughness, metallic, specular,specular_blob_intensity, +#ifdef LIGHT_TRANSMISSION_USED + transmission, +#endif +#ifdef LIGHT_RIM_USED + rim, + rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + tangent, binormal, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); + } + + } + + { //spot lights + uint spot_light_count = (instances.data[instance_index].flags >> INSTANCE_FLAGS_FORWARD_SPOT_LIGHT_SHIFT) & INSTANCE_FLAGS_FORWARD_MASK; + for (uint i = 0; i < spot_light_count; i++) { + + uint light_index = instances.data[instance_index].spot_light_indices[i>>1]; + + if (bool(i&1)) { + light_index>>=16; + } else { + light_index&=0xFFFF; + } + + //this is done on CPU, so no need to do it here + //if (!bool(lights.data[light_index].mask&instances.data[instance_index].layer_mask)) { + // continue; //not masked + //} + + light_process_spot(light_index, vertex, view, normal, albedo, roughness, metallic, specular,specular_blob_intensity, +#ifdef LIGHT_TRANSMISSION_USED + transmission, +#endif +#ifdef LIGHT_RIM_USED + rim, + rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + tangent, binormal, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); + } + + } + + +#endif //!MODE_RENDER_DEPTH #ifdef USE_SHADOW_TO_OPACITY alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); @@ -757,6 +1235,7 @@ FRAGMENT_SHADER_CODE #endif // USE_SHADOW_TO_OPACITY + #ifdef MODE_RENDER_DEPTH //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl index 3547cad46c01..8951f89c13bd 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl @@ -2,6 +2,13 @@ #define M_PI 3.14159265359 #define ROUGHNESS_MAX_LOD 5 +layout(push_constant, binding = 0, std430) uniform DrawCall { + uint instance_index; + uint pad[3]; //16 bits minimum size +} draw_call; + + + /* Set 0 Scene data, screen and sources (changes the least) */ layout(set=0,binding=1) uniform texture2D depth_buffer; @@ -35,7 +42,9 @@ layout(set = 0, binding = 5) uniform textureCube radiance_cubemap; layout(set = 0, binding = 6) uniform sampler material_samplers[12]; -layout(set=0,binding=7,std140) uniform SceneData { +layout(set = 0, binding = 7) uniform sampler shadow_sampler; + +layout(set=0,binding=8,std140) uniform SceneData { mat4 projection_matrix; mat4 inv_projection_matrix; @@ -63,6 +72,14 @@ layout(set=0,binding=7,std140) uniform SceneData { mat3 radiance_inverse_xform; + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + + uint directional_light_count; + float dual_paraboloid_side; + float z_far; + uint pad0; + #if 0 vec4 ambient_light_color; vec4 bg_color; @@ -101,80 +118,125 @@ layout(set=0,binding=7,std140) uniform SceneData { #endif } scene_data; +#define INSTANCE_FLAGS_FORWARD_MASK 3 +#define INSTANCE_FLAGS_FORWARD_OMNI_LIGHT_SHIFT 3 +#define INSTANCE_FLAGS_FORWARD_SPOT_LIGHT_SHIFT 6 +#define INSTANCE_FLAGS_FORWARD_DECAL_SHIFT 9 + + +struct InstanceData { + mat4 transform; + mat4 normal_transform; + uint flags; + uint instance_ofs; //instance_offset in instancing/skeleton buffer + uint gi_offset; //GI information when using lightmapping (VCT or lightmap) + uint layer_mask; + + uint reflection_probe_indices[4]; + uint omni_light_indices[4]; + uint spot_light_indices[4]; + uint decal_indices[4]; +}; + + +layout(set=0,binding=9,std430) buffer Instances { + InstanceData data[]; +} instances; + +struct ReflectionData { + + vec4 box_extents; + vec4 box_offset; + vec4 params; // intensity, 0, interior , boxproject + vec4 ambient; // ambient color, energy + mat4 local_matrix; // up to here for spot and omni, rest is for directional + // notes: for ambientblend, use distance to edge to blend between already existing global environment +}; + +layout(set=0,binding=10,std140) uniform ReflectionProbeData { + ReflectionData data[MAX_REFLECTION_DATA_STRUCTS]; +} reflections; + + +struct LightData { //this structure needs to be 128 bits + + vec3 position; + float inv_radius; + vec3 direction; + uint attenuation_energy; //attenuation + uint color_specular; //rgb color, a specular (8 bit unorm) + uint cone_attenuation_angle; // attenuation and angle, (16bit float) + uint mask; + uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) + vec4 atlas_rect; //used for shadow atlas uv on omni, and for projection atlas on spot + mat4 shadow_matrix; +}; + +layout(set=0,binding=11,std140) uniform Lights { + LightData data[MAX_LIGHT_DATA_STRUCTS]; +} lights; + +layout(set=0,binding=12) uniform texture2D shadow_atlas; -#if 0 struct DirectionalLightData { - vec4 light_pos_inv_radius; - vec4 light_direction_attenuation; - vec4 light_color_energy; - vec4 light_params; // cone attenuation, angle, specular, shadow enabled, - vec4 light_clamp; - vec4 shadow_color_contact; + vec3 direction; + float energy; + vec3 color; + float specular; + uint mask; + uint pad0,pad1,pad2; + vec3 shadow_color; + bool shadow_enabled; + vec4 shadow_atlas_rect; + vec4 shadow_split_offsets; mat4 shadow_matrix1; mat4 shadow_matrix2; mat4 shadow_matrix3; mat4 shadow_matrix4; - vec4 shadow_split_offsets; -}; -#endif -/* Set 1 Skeleton Data (most objects lack it, so it changes little */ +}; + +layout(set=0,binding=13,std140) uniform DirectionalLights { + DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} directional_lights; + +layout(set=0,binding=14) uniform texture2D directional_shadow_atlas; + +/* +layout(set=0,binding=15,std430) buffer Skeletons { + vec4 data[]; +} skeletons; +*/ + +/* Set 1 Instancing (Multimesh) */ + +//layout(set = 1, binding = 0) uniform textureBuffer multimesh_transforms; + +/* Set 2 Instancing (Multimesh) data */ #if 0 -layout(set = 1 binding = 0, std140) uniform SkeletonData { - mat4 transform; - bool use_skeleton; - bool use_world_coords; - bool pad1; - bool pad2; -} skeleton; -layout(set = 1, binding = 1) uniform textureBuffer skeleton_bones; -#endif +#ifdef USE_RADIANCE_CUBEMAP_ARRAY -/* Set 2 Custom Material Data (changess less than instance) */ +layout(set = 3, binding = 2) uniform textureCubeArray reflection_probes[MAX_REFLECTION_PROBES]; +#else -/* Set 3 Instance Data (Set on every draw call) */ - -layout(push_constant, binding = 0, std430) uniform DrawData { - //used in forward rendering, 16 bits indices, max 8 - uint reflection_probe_count; - uint omni_light_count; - uint spot_light_count; - uint decal_count; - uvec4 reflection_probe_indices; - uvec4 omni_light_indices; - uvec4 spot_light_indices; - uvec4 decal_indices; -} draw_data; - -layout(set = 3, binding = 0, std140) uniform InstanceData { - mat4 transform; - mat3 normal_transform; - uint flags; - uint pad0; - uint pad1; - uint pad2; -} instance_data; - -layout(set = 3, binding = 1) uniform textureBuffer multimesh_transforms; - -#ifdef USE_LIGHTMAP - -layout(set = 3, binding = 2) uniform texture2D lightmap; +layout(set = 3, binding = 2) uniform textureCube reflection_probes[MAX_REFLECTION_PROBES]; #endif + #ifdef USE_VOXEL_CONE_TRACING -layout(set = 3, binding = 3) uniform texture3D gi_probe[2]; +layout(set = 3, binding = 4) uniform texture3D gi_probe[2]; #ifdef USE_ANISOTROPIC_VOXEL_CONE_TRACING -layout(set = 3, binding = 4) uniform texture3D gi_probe_aniso_pos[2]; -layout(set = 3, binding = 5) uniform texture3D gi_probe_aniso_neg[2]; +layout(set = 3, binding = 5) uniform texture3D gi_probe_aniso_pos[2]; +layout(set = 3, binding = 6) uniform texture3D gi_probe_aniso_neg[2]; #endif #endif +#endif diff --git a/servers/visual/rasterizer_rd/shaders/tonemap.glsl b/servers/visual/rasterizer_rd/shaders/tonemap.glsl index 284c934cf688..6797ff9f773c 100644 --- a/servers/visual/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/visual/rasterizer_rd/shaders/tonemap.glsl @@ -166,7 +166,9 @@ vec3 tonemap_reinhard(vec3 color, float white) { return (white * color + color) / (color * white + white); } -vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped input in range [0;1] +vec3 linear_to_srgb(vec3 color) { + //if going to srgb, clamp from 0 to 1. + color = clamp(color,vec3(0.0),vec3(1.0)); const vec3 a = vec3(0.055f); return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); } @@ -233,15 +235,9 @@ vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blendi return color + glow; } else if (params.glow_mode==GLOW_MODE_SCREEN) { //need color clamping - color = clamp(color,0.0,1.0); - glow = clamp(glow,0.0,1.0); - return max((color + glow) - (color * glow), vec3(0.0)); } else if ( params.glow_mode==GLOW_MODE_SOFTLIGHT) { //need color clamping - color = clamp(color,0.0,1.0); - glow = clamp(glow,0.0,1.0); - glow = glow * vec3(0.5f) + vec3(0.5f); color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r))); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 0910bf3a9f61..2f25b8b015a7 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -103,9 +103,9 @@ void VisualServerRaster::draw(bool p_swap_buffers, double frame_step) { VSG::rasterizer->begin_frame(frame_step); - VSG::scene->update_dirty_instances(); //update scene stuff + VSG::scene_render->update(); //update scenes stuff before updating instances - VSG::scene_render->update(); + VSG::scene->update_dirty_instances(); //update scene stuff VSG::viewport->draw_viewports(); VSG::scene->render_probes(); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index bef82a7da43e..be19a935e98b 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -313,7 +313,6 @@ public: BIND2(light_set_use_gi, RID, bool) BIND2(light_omni_set_shadow_mode, RID, LightOmniShadowMode) - BIND2(light_omni_set_shadow_detail, RID, LightOmniShadowDetail) BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) BIND2(light_directional_set_blend_splits, RID, bool) @@ -489,6 +488,8 @@ public: //from now on, calls forwarded to this singleton #define BINDBASE VSG::scene_render + BIND1(directional_shadow_atlas_set_size, int) + /* SKY API */ BIND0R(RID, sky_create) @@ -535,7 +536,6 @@ public: BIND2(scenario_set_debug, RID, ScenarioDebugMode) BIND2(scenario_set_environment, RID, RID) - BIND3(scenario_set_reflection_atlas_size, RID, int, int) BIND2(scenario_set_fallback_environment, RID, RID) /* INSTANCING API */ diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index ae95fe386d7f..d060043b404b 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -268,7 +268,6 @@ RID VisualServerScene::scenario_create() { VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4); VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4); VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8); - scenario->reflection_atlas = VSG::scene_render->reflection_atlas_create(); return scenario_rid; } @@ -294,14 +293,6 @@ void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_ scenario->fallback_environment = p_environment; } -void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_size, int p_subdiv) { - - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - VSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_size); - VSG::scene_render->reflection_atlas_set_subdivision(scenario->reflection_atlas, p_subdiv); -} - /* INSTANCING API */ void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) { @@ -360,11 +351,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { instance->octree_id = 0; } - if (instance->custom_data) { - VSG::scene_render->instance_free_custom_data(instance); - instance->custom_data = nullptr; - } - switch (instance->base_type) { case VS::INSTANCE_LIGHT: { @@ -494,8 +480,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it VSG::storage->base_update_dependency(p_base, instance); - - VSG::scene_render->instance_create_custom_data(instance); } _instance_queue_update(instance, true, true); @@ -527,8 +511,6 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) { } break; case VS::INSTANCE_REFLECTION_PROBE: { - InstanceReflectionProbeData *reflection_probe = static_cast(instance->base_data); - VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); } break; case VS::INSTANCE_GI_PROBE: { @@ -710,10 +692,6 @@ void VisualServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap lightmap_capture->users.insert(instance); instance->lightmap = p_lightmap; } - - if (instance->custom_data) { - VSG::scene_render->instance_custom_data_update_lightmap(instance); - } } void VisualServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { @@ -943,10 +921,6 @@ void VisualServerScene::_update_instance(Instance *p_instance) { p_instance->transformed_aabb = new_aabb; - if (p_instance->custom_data) { - VSG::scene_render->instance_custom_data_update_transform(p_instance); - } - if (!p_instance->scenario) { return; @@ -1614,12 +1588,12 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons //using this one ensures that raster deferred will have it static const Vector3 view_normals[6] = { - Vector3(-1, 0, 0), Vector3(+1, 0, 0), + Vector3(-1, 0, 0), Vector3(0, -1, 0), Vector3(0, +1, 0), - Vector3(0, 0, -1), - Vector3(0, 0, +1) + Vector3(0, 0, +1), + Vector3(0, 0, -1) }; static const Vector3 view_up[6] = { Vector3(0, -1, 0), @@ -1920,10 +1894,8 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca reflection_probe->reflection_dirty = false; } - if (VSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { - reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance; - reflection_probe_cull_count++; - } + reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance; + reflection_probe_cull_count++; } } } @@ -1970,10 +1942,6 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } geom->lighting_dirty = false; - - if (ins->custom_data) { - VSG::scene_render->instance_custom_data_update_lights(ins); - } } if (geom->reflection_dirty) { @@ -1989,10 +1957,6 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } geom->reflection_dirty = false; - - if (ins->custom_data) { - VSG::scene_render->instance_custom_data_update_reflection_probes(ins); - } } if (geom->gi_probes_dirty) { @@ -2008,10 +1972,6 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } geom->gi_probes_dirty = false; - - if (ins->custom_data) { - VSG::scene_render->instance_custom_data_update_gi_probes(ins); - } } ins->depth = near_plane.distance_to(ins->transform.origin); @@ -2188,7 +2148,7 @@ void VisualServerScene::_render_scene(RID p_render_buffers, const Transform p_ca /* PROCESS GEOMETRY AND DRAW SCENE */ - VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass); + VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe, p_reflection_probe_pass); } void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { @@ -2202,7 +2162,7 @@ void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, environment = scenario->environment; else environment = scenario->fallback_environment; - VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0); + VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, RID(), 0); #endif } @@ -2216,9 +2176,7 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int if (p_step == 0) { - if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { - return true; //sorry, all full :( - } + VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance); } if (p_step >= 0 && p_step < 6) { @@ -3507,7 +3465,6 @@ bool VisualServerScene::free(RID p_rid) { instance_set_scenario(scenario->instances.first()->self()->self, RID()); } VSG::scene_render->free(scenario->reflection_probe_shadow_atlas); - VSG::scene_render->free(scenario->reflection_atlas); scenario_owner.free(p_rid); memdelete(scenario); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index ad0c1caff383..0f73f42153ba 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -115,7 +115,6 @@ public: RID environment; RID fallback_environment; RID reflection_probe_shadow_atlas; - RID reflection_atlas; SelfList::List instances; @@ -132,7 +131,6 @@ public: virtual void scenario_set_debug(RID p_scenario, VS::ScenarioDebugMode p_debug_mode); virtual void scenario_set_environment(RID p_scenario, RID p_environment); virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); - virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_size, int p_subdiv); /* INSTANCING API */ diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index ac4b5c3ecbb5..d8cd6771c1e1 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -240,7 +240,6 @@ public: FUNC2(light_set_use_gi, RID, bool) FUNC2(light_omni_set_shadow_mode, RID, LightOmniShadowMode) - FUNC2(light_omni_set_shadow_detail, RID, LightOmniShadowDetail) FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) FUNC2(light_directional_set_blend_splits, RID, bool) @@ -404,6 +403,8 @@ public: FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw) + FUNC1(directional_shadow_atlas_set_size, int) + /* SKY API */ FUNCRID(sky) @@ -447,7 +448,6 @@ public: FUNC2(scenario_set_debug, RID, ScenarioDebugMode) FUNC2(scenario_set_environment, RID, RID) - FUNC3(scenario_set_reflection_atlas_size, RID, int, int) FUNC2(scenario_set_fallback_environment, RID, RID) /* INSTANCING API */ diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index e83498389ed5..4b3ac207f18f 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1694,7 +1694,6 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("light_set_use_gi", "light", "enabled"), &VisualServer::light_set_use_gi); ClassDB::bind_method(D_METHOD("light_omni_set_shadow_mode", "light", "mode"), &VisualServer::light_omni_set_shadow_mode); - ClassDB::bind_method(D_METHOD("light_omni_set_shadow_detail", "light", "detail"), &VisualServer::light_omni_set_shadow_detail); ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &VisualServer::light_directional_set_shadow_mode); ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &VisualServer::light_directional_set_blend_splits); @@ -1836,7 +1835,6 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("scenario_create"), &VisualServer::scenario_create); ClassDB::bind_method(D_METHOD("scenario_set_debug", "scenario", "debug_mode"), &VisualServer::scenario_set_debug); ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &VisualServer::scenario_set_environment); - ClassDB::bind_method(D_METHOD("scenario_set_reflection_atlas_size", "scenario", "size", "subdiv"), &VisualServer::scenario_set_reflection_atlas_size); ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &VisualServer::scenario_set_fallback_environment); #ifndef _3D_DISABLED @@ -2056,8 +2054,6 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DUAL_PARABOLOID); BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_CUBE); - BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DETAIL_VERTICAL); - BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL); BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS); diff --git a/servers/visual_server.h b/servers/visual_server.h index fe64f1a04cad..7aae7acf322c 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -432,14 +432,6 @@ public: virtual void light_omni_set_shadow_mode(RID p_light, LightOmniShadowMode p_mode) = 0; - // omni light - enum LightOmniShadowDetail { - LIGHT_OMNI_SHADOW_DETAIL_VERTICAL, - LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL - }; - - virtual void light_omni_set_shadow_detail(RID p_light, LightOmniShadowDetail p_detail) = 0; - // directional light enum LightDirectionalShadowMode { LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL, @@ -667,12 +659,17 @@ public: enum ViewportDebugDraw { VIEWPORT_DEBUG_DRAW_DISABLED, VIEWPORT_DEBUG_DRAW_UNSHADED, + VIEWPORT_DEBUG_DRAW_LIGHTING, VIEWPORT_DEBUG_DRAW_OVERDRAW, VIEWPORT_DEBUG_DRAW_WIREFRAME, + VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS + }; virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0; + virtual void directional_shadow_atlas_set_size(int p_size) = 0; + /* SKY API */ enum SkyMode { @@ -792,7 +789,6 @@ public: virtual void scenario_set_debug(RID p_scenario, ScenarioDebugMode p_debug_mode) = 0; virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0; - virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_size, int p_subdiv) = 0; virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0; /* INSTANCING API */ @@ -1106,7 +1102,6 @@ VARIANT_ENUM_CAST(VisualServer::MultimeshTransformFormat); VARIANT_ENUM_CAST(VisualServer::MultimeshColorFormat); VARIANT_ENUM_CAST(VisualServer::MultimeshCustomDataFormat); VARIANT_ENUM_CAST(VisualServer::LightOmniShadowMode); -VARIANT_ENUM_CAST(VisualServer::LightOmniShadowDetail); VARIANT_ENUM_CAST(VisualServer::LightDirectionalShadowMode); VARIANT_ENUM_CAST(VisualServer::LightDirectionalShadowDepthRangeMode); VARIANT_ENUM_CAST(VisualServer::ReflectionProbeUpdateMode);