diff --git a/core/image.cpp b/core/image.cpp index 7e7c8d16073..f2d78168f6c 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -87,6 +87,8 @@ const char *Image::format_names[Image::FORMAT_MAX] = { SavePNGFunc Image::save_png_func = NULL; SaveEXRFunc Image::save_exr_func = NULL; +SavePNGBufferFunc Image::save_png_buffer_func = NULL; + void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel) { uint32_t ofs = (p_y * width + p_x) * p_pixelsize; @@ -901,6 +903,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0."); ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); + ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); if (p_width == width && p_height == height) return; @@ -1593,6 +1596,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma ERR_FAIL_INDEX(p_width - 1, MAX_WIDTH); ERR_FAIL_INDEX(p_height - 1, MAX_HEIGHT); + ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); int mm = 0; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -1612,6 +1616,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma ERR_FAIL_INDEX(p_width - 1, MAX_WIDTH); ERR_FAIL_INDEX(p_height - 1, MAX_HEIGHT); + ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); int mm; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -1910,6 +1915,14 @@ Error Image::save_png(const String &p_path) const { return save_png_func(p_path, Ref((Image *)this)); } +PoolVector Image::save_png_to_buffer() const { + if (save_png_buffer_func == NULL) { + return PoolVector(); + } + + return save_png_buffer_func(Ref((Image *)this)); +} + Error Image::save_exr(const String &p_path, bool p_grayscale) const { if (save_exr_func == NULL) diff --git a/core/image.h b/core/image.h index cf1ebfad9f5..2f8b7fbe9cc 100644 --- a/core/image.h +++ b/core/image.h @@ -47,6 +47,7 @@ class Image; typedef Error (*SavePNGFunc)(const String &p_path, const Ref &p_img); +typedef PoolVector (*SavePNGBufferFunc)(const Ref &p_img); typedef Ref (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size); typedef Error (*SaveEXRFunc)(const String &p_path, const Ref &p_img, bool p_grayscale); @@ -57,10 +58,12 @@ class Image : public Resource { public: static SavePNGFunc save_png_func; static SaveEXRFunc save_exr_func; + static SavePNGBufferFunc save_png_buffer_func; enum { - MAX_WIDTH = 16384, // force a limit somehow - MAX_HEIGHT = 16384 // force a limit somehow + MAX_WIDTH = (1 << 24), // force a limit somehow + MAX_HEIGHT = (1 << 24), // force a limit somehow + MAX_PIXELS = 268435456 }; enum Format { @@ -265,6 +268,7 @@ public: Error load(const String &p_path); Error save_png(const String &p_path) const; + PoolVector save_png_to_buffer() const; Error save_exr(const String &p_path, bool p_grayscale) const; /** diff --git a/core/math/vector3i.h b/core/math/vector3i.h index cb2e2bdd2d1..dac713502d6 100644 --- a/core/math/vector3i.h +++ b/core/math/vector3i.h @@ -183,7 +183,7 @@ bool Vector3i::operator==(const Vector3i &p_v) const { bool Vector3i::operator!=(const Vector3i &p_v) const { - return (x != p_v.x || y == p_v.y || z == p_v.z); + return (x != p_v.x || y != p_v.y || z != p_v.z); } bool Vector3i::operator<(const Vector3i &p_v) const { diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp index f4dbf135bb6..750d00eb59a 100644 --- a/drivers/png/png_driver_common.cpp +++ b/drivers/png/png_driver_common.cpp @@ -114,6 +114,7 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref p_image) { ERR_FAIL_COND_V_MSG(check_error(png_img), ERR_FILE_CORRUPT, png_img.message); ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT); + //print_line("png width: "+itos(png_img.width)+" height: "+itos(png_img.height)); p_image->create(png_img.width, png_img.height, 0, dest_format, buffer); return OK; diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index b15a84d3b93..566bfbcc1d4 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -71,6 +71,14 @@ Error ResourceSaverPNG::save_image(const String &p_path, const Ref &p_img return OK; } +PoolVector ResourceSaverPNG::save_image_to_buffer(const Ref &p_img) { + + PoolVector buffer; + Error err = PNGDriverCommon::image_to_png(p_img, buffer); + ERR_FAIL_COND_V_MSG(err, PoolVector(), "Can't convert image to PNG."); + return buffer; +} + bool ResourceSaverPNG::recognize(const RES &p_resource) const { return (p_resource.is_valid() && p_resource->is_class("ImageTexture")); @@ -86,4 +94,5 @@ void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List &p_img); + static PoolVector save_image_to_buffer(const Ref &p_img); virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); virtual bool recognize(const RES &p_resource) const; diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index cc538593b5f..98b1bc1115e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -36,6 +36,8 @@ #include "drivers/vulkan/vulkan_context.h" #include "thirdparty/spirv-reflect/spirv_reflect.h" +//#define FORCE_FULL_BARRIER + void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { if (!dependency_map.has(p_depends_on)) { @@ -1499,6 +1501,42 @@ 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::_full_barrier(bool p_sync_with_draw) { + //used for debug + _memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + 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, + 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, + p_sync_with_draw); +} + 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; @@ -4643,7 +4681,11 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint } _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); - +#ifdef FORCE_FULL_BARRIER + _full_barrier(p_sync_with_draw); +#else + _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); +#endif return err; } @@ -6038,7 +6080,12 @@ void RenderingDeviceVulkan::draw_list_end() { // 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 + +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, true); +#endif } /***********************/ @@ -6298,7 +6345,11 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t } void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, true); +#endif } void RenderingDeviceVulkan::compute_list_end() { @@ -6330,8 +6381,11 @@ void RenderingDeviceVulkan::compute_list_end() { memdelete(compute_list); compute_list = NULL; - +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); +#endif } #if 0 diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 0dc3cc702b9..3c387a7d524 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_free(Buffer *p_buffer); 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 _full_barrier(bool p_sync_with_draw); 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); diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp index 8914e0ed011..429d13990e5 100644 --- a/editor/plugins/gi_probe_editor_plugin.cpp +++ b/editor/plugins/gi_probe_editor_plugin.cpp @@ -33,6 +33,18 @@ void GIProbeEditorPlugin::_bake() { if (gi_probe) { + if (gi_probe->get_probe_data().is_null()) { + String path = get_tree()->get_edited_scene_root()->get_filename(); + if (path==String()) { + path="res://"+gi_probe->get_name()+"_data.res"; + } else { + String ext = path.get_extension(); + path = path.get_basename()+"."+gi_probe->get_name()+"_data.res"; + } + probe_file->set_current_path(path); + probe_file->popup_centered_ratio(); + return; + } gi_probe->bake(); } } @@ -51,13 +63,42 @@ bool GIProbeEditorPlugin::handles(Object *p_object) const { return p_object->is_class("GIProbe"); } +void GIProbeEditorPlugin::_notification(int p_what) { + + if (p_what==NOTIFICATION_PROCESS) { + if (!gi_probe) { + return; + } + + String text; + + Vector3i size = gi_probe->get_estimated_cell_size(); + text = itos(size.x)+", "+itos(size.y)+", "+itos(size.z); + int data_size = 4; + if (GLOBAL_GET("rendering/quality/gi_probes/anisotropic")) { + data_size+=4; + } + text += " - VRAM Size: " + String::num(size.x*size.y*size.z*data_size/(1024.0*1024.0),2)+" Mb."; + + if (bake_info->get_text()==text) { + return; + } + + bake_info->add_color_override("font_color", bake_info->get_color("success_color", "Editor")); + + bake_info->set_text(text); + } +} + void GIProbeEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - bake->show(); + bake_hb->show(); + set_process(true); } else { - bake->hide(); + bake_hb->hide(); + set_process(false); } } @@ -82,21 +123,46 @@ void GIProbeEditorPlugin::bake_func_end() { tmp_progress = NULL; } +void GIProbeEditorPlugin::_giprobe_save_path_and_bake(const String& p_path) { + probe_file->hide(); + if (gi_probe) { + gi_probe->bake(); + ERR_FAIL_COND( gi_probe->get_probe_data().is_null() ); + ResourceSaver::save(p_path,gi_probe->get_probe_data(),ResourceSaver::FLAG_CHANGE_PATH); + } +} + void GIProbeEditorPlugin::_bind_methods() { ClassDB::bind_method("_bake", &GIProbeEditorPlugin::_bake); + ClassDB::bind_method("_giprobe_save_path_and_bake", &GIProbeEditorPlugin::_giprobe_save_path_and_bake); + } GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { editor = p_node; + bake_hb = memnew( HBoxContainer ); + bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + bake_hb->hide(); bake = memnew(ToolButton); bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons")); bake->set_text(TTR("Bake GI Probe")); - bake->hide(); bake->connect("pressed", this, "_bake"); - add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake); + bake_hb->add_child(bake); + bake_info = memnew( Label ); + bake_info->set_h_size_flags(Control::SIZE_EXPAND_FILL); + bake_info->set_clip_text(true); + bake_hb->add_child(bake_info); + + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb); gi_probe = NULL; + probe_file = memnew( EditorFileDialog ); + probe_file->set_mode(EditorFileDialog::MODE_SAVE_FILE); + probe_file->add_filter("*.res"); + probe_file->connect("file_selected",this,"_giprobe_save_path_and_bake"); + get_editor_interface()->get_base_control()->add_child(probe_file); + probe_file->set_title(TTR("Select path for GIProbe Data File")); GIProbe::bake_begin_function = bake_func_begin; GIProbe::bake_step_function = bake_func_step; diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/gi_probe_editor_plugin.h index 5db682835d4..63b14ca15a1 100644 --- a/editor/plugins/gi_probe_editor_plugin.h +++ b/editor/plugins/gi_probe_editor_plugin.h @@ -42,18 +42,25 @@ class GIProbeEditorPlugin : public EditorPlugin { GIProbe *gi_probe; + HBoxContainer *bake_hb; + Label *bake_info; ToolButton *bake; EditorNode *editor; + EditorFileDialog *probe_file; + static EditorProgress *tmp_progress; static void bake_func_begin(int p_steps); static void bake_func_step(int p_step, const String &p_description); static void bake_func_end(); void _bake(); + void _giprobe_save_path_and_bake(const String& p_path); + protected: static void _bind_methods(); + void _notification(int p_what); public: virtual String get_name() const { return "GIProbe"; } diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 404185f3e7d..8d343f03b67 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -41,7 +41,7 @@ void GIProbeData::_set_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("octree_size")); ERR_FAIL_COND(!p_data.has("octree_cells")); ERR_FAIL_COND(!p_data.has("octree_data")); - ERR_FAIL_COND(!p_data.has("octree_df")); + ERR_FAIL_COND(!p_data.has("octree_df") && !p_data.has("octree_df_png")); ERR_FAIL_COND(!p_data.has("level_counts")); ERR_FAIL_COND(!p_data.has("to_cell_xform")); @@ -49,7 +49,19 @@ void GIProbeData::_set_data(const Dictionary &p_data) { Vector3 octree_size = p_data["octree_size"]; PoolVector octree_cells = p_data["octree_cells"]; PoolVector octree_data = p_data["octree_data"]; - PoolVector octree_df = p_data["octree_df"]; + + PoolVector octree_df; + if (p_data.has("octree_df")) { + octree_df = p_data["octree_df"]; + } else if (p_data.has("octree_df_png")) { + PoolVector octree_df_png = p_data["octree_df_png"]; + Ref img; + img.instance(); + Error err = img->load_png_from_buffer(octree_df_png); + ERR_FAIL_COND(err != OK); + ERR_FAIL_COND(img->get_format() != Image::FORMAT_L8); + octree_df = img->get_data(); + } PoolVector octree_levels = p_data["level_counts"]; Transform to_cell_xform = p_data["to_cell_xform"]; @@ -59,10 +71,21 @@ void GIProbeData::_set_data(const Dictionary &p_data) { Dictionary GIProbeData::_get_data() const { Dictionary d; d["bounds"] = get_bounds(); - d["octree_size"] = get_octree_size(); + Vector3i otsize = get_octree_size(); + d["octree_size"] = Vector3(otsize); d["octree_cells"] = get_octree_cells(); d["octree_data"] = get_data_cells(); - d["octree_df"] = get_distance_field(); + if (otsize != Vector3i()) { + Ref img; + img.instance(); + img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field()); + PoolVector df_png = img->save_png_to_buffer(); + ERR_FAIL_COND_V(df_png.size() == 0, Dictionary()); + d["octree_df_png"] = df_png; + } else { + d["octree_df"] = PoolVector(); + } + d["level_counts"] = get_level_counts(); d["to_cell_xform"] = get_to_cell_xform(); return d; @@ -384,6 +407,32 @@ GIProbe::BakeBeginFunc GIProbe::bake_begin_function = NULL; GIProbe::BakeStepFunc GIProbe::bake_step_function = NULL; GIProbe::BakeEndFunc GIProbe::bake_end_function = NULL; +Vector3i GIProbe::get_estimated_cell_size() const { + static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; + int cell_subdiv = subdiv_value[subdiv]; + int axis_cell_size[3]; + AABB bounds = AABB(-extents, extents * 2.0); + int longest_axis = bounds.get_longest_axis_index(); + axis_cell_size[longest_axis] = 1 << cell_subdiv; + + + for (int i = 0; i < 3; i++) { + + if (i == longest_axis) + continue; + + axis_cell_size[i] = axis_cell_size[longest_axis]; + float axis_size = bounds.size[longest_axis]; + + //shrink until fit subdiv + while (axis_size / 2.0 >= bounds.size[i]) { + axis_size /= 2.0; + axis_cell_size[i] >>= 1; + } + } + + return Vector3i(axis_cell_size[0],axis_cell_size[1],axis_cell_size[2]); +} void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; @@ -458,6 +507,8 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { if (bake_end_function) { bake_end_function(); } + + _change_notify(); //bake property may have changed } void GIProbe::_debug_bake() { diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index ac309e82c70..efb526b435f 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -159,6 +159,7 @@ public: void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; + Vector3i get_estimated_cell_size() const; void bake(Node *p_from_node = NULL, bool p_create_visual_debug = false); diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 47312107687..08290fe6c3b 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -409,6 +409,7 @@ void MeshInstance::_bind_methods() { ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); + ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); } diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp index 279cb886606..d57c62b629b 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp @@ -2363,11 +2363,14 @@ void RasterizerSceneForwardRD::_setup_render_pass_uniform_set(RID p_depth_buffer RD::Uniform u; u.binding = 6; u.type = RD::UNIFORM_TYPE_TEXTURE; + RID 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)); + texture = shadow_atlas_get_texture(p_shadow_atlas); } + if (!texture.is_valid()) { + texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); + } + u.ids.push_back(texture); uniforms.push_back(u); } diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index b2e90c7f595..05624e5279e 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -2334,6 +2334,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas } } 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 diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl index 8c122e6fcbf..f567970e4a4 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl @@ -266,7 +266,7 @@ VERTEX_SHADER_CODE #else float z_ofs = scene_data.z_offset; - z_ofs += (1.0 - abs(normal_interp.z)) * scene_data.z_slope_scale; + z_ofs += max(0.0,1.0 - abs(normalize(normal_interp).z)) * scene_data.z_slope_scale; vertex_interp.z -= z_ofs; #endif diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 1ce4f47d75e..61e6755ee27 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -851,7 +851,7 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF Instance *instance = instance_owner.getornull(p_instance); ERR_FAIL_COND(!instance); - ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK)); + //ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK)); switch (p_flags) { @@ -2526,6 +2526,9 @@ void VisualServerScene::render_probes() { for (List::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { if (instance_cull_count < MAX_INSTANCE_CULL) { Instance *ins = E->get().geometry; + if (!ins->visible) { + continue; + } InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; if (geom->gi_probes_dirty) {