diff options
Diffstat (limited to 'servers/rendering/renderer_rd')
16 files changed, 883 insertions, 187 deletions
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index c96c541461..5a26b5abbb 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -30,6 +30,7 @@ #include "scene_shader_forward_clustered.h" #include "core/config/project_settings.h" +#include "core/math/math_defs.h" #include "render_forward_clustered.h" using namespace RendererSceneRenderImplementation; @@ -608,6 +609,9 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin //builtins actions.renames["TIME"] = "scene_data.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; actions.renames["FRAGCOORD"] = "gl_FragCoord"; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index b9220cc514..883273c8a5 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -30,6 +30,7 @@ #include "scene_shader_forward_mobile.h" #include "core/config/project_settings.h" +#include "core/math/math_defs.h" #include "render_forward_mobile.h" using namespace RendererSceneRenderImplementation; @@ -625,6 +626,9 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p //builtins actions.renames["TIME"] = "scene_data.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; actions.renames["FRAGCOORD"] = "gl_FragCoord"; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index f448698976..70c1705bff 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -31,8 +31,10 @@ #include "renderer_canvas_render_rd.h" #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" +#include "core/math/math_defs.h" #include "core/math/math_funcs.h" #include "renderer_compositor_rd.h" +#include "servers/rendering/rendering_server_default.h" void RendererCanvasRenderRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { p_mat4[0] = p_transform.elements[0][0]; @@ -390,7 +392,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI r_last_texture = p_texture; } -void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) { +void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) { //create an empty push constant RS::CanvasItemTextureFilter current_filter = default_filter; @@ -747,9 +749,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item } else if (c->type == Item::Command::TYPE_PARTICLES) { const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c); ERR_BREAK(storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D); + storage->particles_request_process(pt->particles); + if (storage->particles_is_inactive(pt->particles)) { break; } + + RenderingServerDefault::redraw_request(); // active particles means redraw request + + bool local_coords = true; int dpc = storage->particles_get_draw_passes(pt->particles); if (dpc == 0) { break; //nothing to draw @@ -768,6 +776,30 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item mesh = storage->particles_get_draw_pass_mesh(pt->particles, 0); //higher ones are ignored texture = pt->texture; + + if (storage->particles_has_collision(pt->particles) && storage->render_target_is_sdf_enabled(p_render_target)) { + //pass collision information + Transform2D xform; + if (local_coords) { + xform = p_item->final_transform; + } else { + xform = p_canvas_transform_inverse; + } + + RID sdf_texture = storage->render_target_get_sdf_texture(p_render_target); + + Rect2 to_screen; + { + Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_render_target); + + to_screen.size = Vector2(1.0 / sdf_rect.size.width, 1.0 / sdf_rect.size.height); + to_screen.position = -sdf_rect.position * to_screen.size; + } + + storage->particles_set_canvas_sdf_collision(pt->particles, true, xform, to_screen, sdf_texture); + } else { + storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), RID()); + } } if (mesh.is_null()) { @@ -1052,7 +1084,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co } } - _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants); + _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants); prev_material = material; } @@ -1280,6 +1312,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p Item *canvas_group_owner = nullptr; bool update_skeletons = false; + bool time_used = false; while (ci) { if (ci->copy_back_buffer && canvas_group_owner == nullptr) { @@ -1305,6 +1338,9 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p if (md->shader_data->uses_sdf) { r_sdf_used = true; } + if (md->shader_data->uses_time) { + time_used = true; + } if (md->last_frame != RendererCompositorRD::singleton->get_frame_number()) { md->last_frame = RendererCompositorRD::singleton->get_frame_number(); if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) { @@ -1401,6 +1437,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p ci = ci->next; } + + if (time_used) { + RenderingServerDefault::redraw_request(); + } } RID RendererCanvasRenderRD::light_create() { @@ -1877,6 +1917,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { uniforms.clear(); uses_screen_texture = false; uses_sdf = false; + uses_time = false; if (code == String()) { return; //just invalid, but no error @@ -1901,6 +1942,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; actions.usage_flag_pointers["texture_sdf"] = &uses_sdf; + actions.usage_flag_pointers["TIME"] = &uses_time; actions.uniforms = &uniforms; @@ -2367,6 +2409,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) { actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform"; actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform"; actions.renames["TIME"] = "canvas_data.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); actions.renames["AT_LIGHT_PASS"] = "false"; actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 8129cc6c9b..890a4e3649 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -176,6 +176,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { bool uses_screen_texture = false; bool uses_sdf = false; + bool uses_time = false; virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); @@ -425,7 +426,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer); inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead. - void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants); + void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants); void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false); _FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 0012ba9c27..1337d36762 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -31,6 +31,7 @@ #include "renderer_compositor_rd.h" #include "core/config/project_settings.h" +#include "core/os/dir_access.h" void RendererCompositorRD::prepare_for_blitting_render_targets() { RD::get_singleton()->prepare_screen_for_drawing(); @@ -155,6 +156,43 @@ void RendererCompositorRD::finalize() { RendererCompositorRD *RendererCompositorRD::singleton = nullptr; RendererCompositorRD::RendererCompositorRD() { + { + String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path(); + if (shader_cache_dir == String()) { + shader_cache_dir = "user://"; + } + DirAccessRef da = DirAccess::open(shader_cache_dir); + if (!da) { + ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir); + } else { + Error err = da->change_dir("shader_cache"); + if (err != OK) { + err = da->make_dir("shader_cache"); + } + if (err != OK) { + ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir); + } else { + shader_cache_dir = shader_cache_dir.plus_file("shader_cache"); + + bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled"); + if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) { + shader_cache_dir = String(); //disable only if not editor + } + + if (shader_cache_dir != String()) { + bool compress = GLOBAL_GET("rendering/shader_compiler/shader_cache/compress"); + bool use_zstd = GLOBAL_GET("rendering/shader_compiler/shader_cache/use_zstd_compression"); + bool strip_debug = GLOBAL_GET("rendering/shader_compiler/shader_cache/strip_debug"); + + ShaderRD::set_shader_cache_dir(shader_cache_dir); + ShaderRD::set_shader_cache_save_compressed(compress); + ShaderRD::set_shader_cache_save_compressed_zstd(use_zstd); + ShaderRD::set_shader_cache_save_debug(!strip_debug); + } + } + } + } + singleton = this; time = 0; @@ -171,3 +209,7 @@ RendererCompositorRD::RendererCompositorRD() { scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage)); } } + +RendererCompositorRD::~RendererCompositorRD() { + ShaderRD::set_shader_cache_dir(String()); +} diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 52552f7ee3..7a78322051 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -118,6 +118,6 @@ public: static RendererCompositorRD *singleton; RendererCompositorRD(); - ~RendererCompositorRD() {} + ~RendererCompositorRD(); }; #endif // RASTERIZER_RD_H diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 54c6e81110..966a1c6815 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -30,6 +30,7 @@ #include "renderer_scene_sky_rd.h" #include "core/config/project_settings.h" +#include "core/math/math_defs.h" #include "renderer_scene_render_rd.h" #include "servers/rendering/rendering_server_default.h" @@ -710,6 +711,9 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) { actions.renames["SKY_COORDS"] = "panorama_coords"; actions.renames["SCREEN_UV"] = "uv"; actions.renames["TIME"] = "params.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); actions.renames["HALF_RES_COLOR"] = "half_res_color"; actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color"; actions.renames["RADIANCE"] = "radiance"; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index f419875d58..7a26e40c0a 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -33,6 +33,7 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/io/resource_loader.h" +#include "core/math/math_defs.h" #include "renderer_compositor_rd.h" #include "servers/rendering/shader_language.h" @@ -4305,6 +4306,15 @@ void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_partic particles->collisions.erase(p_particles_collision_instance); } +void RendererStorageRD::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->has_sdf_collision = p_enable; + particles->sdf_collision_transform = p_xform; + particles->sdf_collision_to_screen = p_to_screen; + particles->sdf_collision_texture = p_texture; +} + void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) { if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) { Vector<RD::Uniform> uniforms; @@ -4410,6 +4420,50 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta if (p_particles->use_local_coords) { to_particles = p_particles->emission_transform.affine_inverse(); } + + if (p_particles->has_sdf_collision && RD::get_singleton()->texture_is_valid(p_particles->sdf_collision_texture)) { + //2D collision + + Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand + Transform2D revert = xform.affine_inverse(); + frame_params.collider_count = 1; + frame_params.colliders[0].transform[0] = xform.elements[0][0]; + frame_params.colliders[0].transform[1] = xform.elements[0][1]; + frame_params.colliders[0].transform[2] = 0; + frame_params.colliders[0].transform[3] = xform.elements[2][0]; + + frame_params.colliders[0].transform[4] = xform.elements[1][0]; + frame_params.colliders[0].transform[5] = xform.elements[1][1]; + frame_params.colliders[0].transform[6] = 0; + frame_params.colliders[0].transform[7] = xform.elements[2][1]; + + frame_params.colliders[0].transform[8] = revert.elements[0][0]; + frame_params.colliders[0].transform[9] = revert.elements[0][1]; + frame_params.colliders[0].transform[10] = 0; + frame_params.colliders[0].transform[11] = revert.elements[2][0]; + + frame_params.colliders[0].transform[12] = revert.elements[1][0]; + frame_params.colliders[0].transform[13] = revert.elements[1][1]; + frame_params.colliders[0].transform[14] = 0; + frame_params.colliders[0].transform[15] = revert.elements[2][1]; + + frame_params.colliders[0].extents[0] = p_particles->sdf_collision_to_screen.size.x; + frame_params.colliders[0].extents[1] = p_particles->sdf_collision_to_screen.size.y; + frame_params.colliders[0].extents[2] = p_particles->sdf_collision_to_screen.position.x; + frame_params.colliders[0].scale = p_particles->sdf_collision_to_screen.position.y; + frame_params.colliders[0].texture_index = 0; + frame_params.colliders[0].type = ParticlesFrameParams::COLLISION_TYPE_2D_SDF; + + collision_heightmap_texture = p_particles->sdf_collision_texture; + + //replace in all other history frames where used because parameters are no longer valid if screen moves + for (uint32_t i = 1; i < p_particles->frame_history.size(); i++) { + if (p_particles->frame_history[i].collider_count > 0 && p_particles->frame_history[i].colliders[0].type == ParticlesFrameParams::COLLISION_TYPE_2D_SDF) { + p_particles->frame_history[i].colliders[0] = frame_params.colliders[0]; + } + } + } + uint32_t collision_3d_textures_used = 0; for (const Set<RID>::Element *E = p_particles->collisions.front(); E; E = E->next()) { ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get()); @@ -4657,6 +4711,8 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta ERR_FAIL_COND(!m); + p_particles->has_collision_cache = m->shader_data->uses_collision; + //todo should maybe compute all particle systems together? RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline); @@ -4740,6 +4796,11 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & copy_push_constant.trail_total = 1; copy_push_constant.frame_delta = 0.0; } + + copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME); + copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1); + copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME; + copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0; copy_push_constant.total_particles = particles->amount; @@ -5019,6 +5080,10 @@ void RendererStorageRD::update_particles() { copy_push_constant.frame_delta = 0.0; } + copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME); + copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1); + copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME; + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); @@ -5049,6 +5114,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { valid = false; ubo_size = 0; uniforms.clear(); + uses_collision = false; if (code == String()) { return; //just invalid, but no error @@ -5068,6 +5134,8 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["TIME"] = &uses_time; */ + actions.usage_flag_pointers["COLLIDED"] = &uses_collision; + actions.uniforms = &uniforms; Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code); @@ -7133,6 +7201,20 @@ Rect2i RendererStorageRD::render_target_get_sdf_rect(RID p_render_target) const return _render_target_get_sdf_rect(rt); } +void RendererStorageRD::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + rt->sdf_enabled = p_enabled; +} + +bool RendererStorageRD::render_target_is_sdf_enabled(RID p_render_target) const { + const RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, false); + + return rt->sdf_enabled; +} + RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); @@ -7200,7 +7282,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { rt->process_size.x = MAX(rt->process_size.x, 1); rt->process_size.y = MAX(rt->process_size.y, 1); - tformat.format = RD::DATA_FORMAT_R16G16_UINT; + tformat.format = RD::DATA_FORMAT_R16G16_SINT; tformat.width = rt->process_size.width; tformat.height = rt->process_size.height; tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; @@ -7208,7 +7290,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); - tformat.format = RD::DATA_FORMAT_R16_UNORM; + tformat.format = RD::DATA_FORMAT_R16_SNORM; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView()); @@ -9144,6 +9226,9 @@ RendererStorageRD::RendererStorageRD() { actions.renames["CUSTOM"] = "PARTICLE.custom"; actions.renames["TRANSFORM"] = "PARTICLE.xform"; actions.renames["TIME"] = "FRAME.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); actions.renames["LIFETIME"] = "params.lifetime"; actions.renames["DELTA"] = "local_delta"; actions.renames["NUMBER"] = "particle_number"; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 49f7f3dba6..67fbeb3008 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -638,7 +638,9 @@ private: COLLISION_TYPE_SPHERE, COLLISION_TYPE_BOX, COLLISION_TYPE_SDF, - COLLISION_TYPE_HEIGHT_FIELD + COLLISION_TYPE_HEIGHT_FIELD, + COLLISION_TYPE_2D_SDF, + }; struct Collider { @@ -710,6 +712,13 @@ private: bool restart_request = false; AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)); bool use_local_coords = true; + bool has_collision_cache = false; + + bool has_sdf_collision = false; + Transform2D sdf_collision_transform; + Rect2 sdf_collision_to_screen; + RID sdf_collision_texture; + RID process_material; uint32_t frame_counter = 0; RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED; @@ -820,6 +829,11 @@ private: float align_up[3]; uint32_t align_mode; + + uint32_t order_by_lifetime; + uint32_t lifetime_split; + uint32_t lifetime_reverse; + uint32_t pad; }; enum { @@ -843,6 +857,7 @@ private: struct ParticlesShaderData : public ShaderData { bool valid; RID version; + bool uses_collision = false; //PipelineCacheRD pipelines[SKY_VERSION_MAX]; Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; @@ -1120,6 +1135,8 @@ private: bool flags[RENDER_TARGET_FLAG_MAX]; + bool sdf_enabled = false; + RID backbuffer; //used for effects RID backbuffer_fb; RID backbuffer_mipmap0; @@ -2175,6 +2192,13 @@ public: return particles->amount * r_trail_divisor; } + _FORCE_INLINE_ bool particles_has_collision(RID p_particles) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND_V(!particles, 0); + + return particles->has_collision_cache; + } + _FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, false); @@ -2206,6 +2230,7 @@ public: virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance); virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance); + virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture); /* PARTICLES COLLISION */ @@ -2280,6 +2305,8 @@ public: RID render_target_get_sdf_framebuffer(RID p_render_target); void render_target_sdf_process(RID p_render_target); virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const; + void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled); + bool render_target_is_sdf_enabled(RID p_render_target) const; Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 3a000bd06e..7deedb80c3 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -369,17 +369,24 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S ERR_FAIL_COND(fidx == -1); + Vector<StringName> uses_functions; + for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) { - if (added.has(E->get())) { + uses_functions.push_back(E->get()); + } + uses_functions.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced + + for (int k = 0; k < uses_functions.size(); k++) { + if (added.has(uses_functions[k])) { continue; //was added already } - _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added); + _dump_function_deps(p_node, uses_functions[k], p_func_code, r_to_add, added); SL::FunctionNode *fnode = nullptr; for (int i = 0; i < p_node->functions.size(); i++) { - if (p_node->functions[i].name == E->get()) { + if (p_node->functions[i].name == uses_functions[k]) { fnode = p_node->functions[i].function; break; } @@ -391,10 +398,21 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S String header; if (fnode->return_type == SL::TYPE_STRUCT) { - header = _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "("; + header = _mkid(fnode->return_struct_name); } else { - header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "("; + header = _typestr(fnode->return_type); } + + if (fnode->return_array_size > 0) { + header += "["; + header += itos(fnode->return_array_size); + header += "]"; + } + + header += " "; + header += _mkid(fnode->name); + header += "("; + for (int i = 0; i < fnode->arguments.size(); i++) { if (i > 0) { header += ", "; @@ -407,13 +425,18 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S } else { header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); } + if (fnode->arguments[i].array_size > 0) { + header += "["; + header += itos(fnode->arguments[i].array_size); + header += "]"; + } } header += ")\n"; r_to_add += header; - r_to_add += p_func_code[E->get()]; + r_to_add += p_func_code[uses_functions[k]]; - added.insert(E->get()); + added.insert(uses_functions[k]); } } @@ -565,63 +588,74 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uniform_defines.resize(max_uniforms); bool uses_uniforms = false; + Vector<StringName> uniform_names; + for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { + uniform_names.push_back(E->key()); + } + + uniform_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced + + for (int k = 0; k < uniform_names.size(); k++) { + StringName uniform_name = uniform_names[k]; + const SL::ShaderNode::Uniform &uniform = pnode->uniforms[uniform_name]; + String ucode; - if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { + if (uniform.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { //insert, but don't generate any code. - p_actions.uniforms->insert(E->key(), E->get()); + p_actions.uniforms->insert(uniform_name, uniform); continue; //instances are indexed directly, dont need index uniforms } - if (SL::is_sampler_type(E->get().type)) { - ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform "; + if (SL::is_sampler_type(uniform.type)) { + ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform "; } - bool is_buffer_global = !SL::is_sampler_type(E->get().type) && E->get().scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL; + bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL; if (is_buffer_global) { //this is an integer to index the global table ucode += _typestr(ShaderLanguage::TYPE_UINT); } else { - ucode += _prestr(E->get().precision); - ucode += _typestr(E->get().type); + ucode += _prestr(uniform.precision); + ucode += _typestr(uniform.type); } - ucode += " " + _mkid(E->key()); + ucode += " " + _mkid(uniform_name); ucode += ";\n"; - if (SL::is_sampler_type(E->get().type)) { + if (SL::is_sampler_type(uniform.type)) { for (int j = 0; j < STAGE_MAX; j++) { r_gen_code.stage_globals[j] += ucode; } GeneratedCode::Texture texture; - texture.name = E->key(); - texture.hint = E->get().hint; - texture.type = E->get().type; - texture.filter = E->get().filter; - texture.repeat = E->get().repeat; - texture.global = E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL; + texture.name = uniform_name; + texture.hint = uniform.hint; + texture.type = uniform.type; + texture.filter = uniform.filter; + texture.repeat = uniform.repeat; + texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL; if (texture.global) { r_gen_code.uses_global_textures = true; } - r_gen_code.texture_uniforms.write[E->get().texture_order] = texture; + r_gen_code.texture_uniforms.write[uniform.texture_order] = texture; } else { if (!uses_uniforms) { uses_uniforms = true; } - uniform_defines.write[E->get().order] = ucode; + uniform_defines.write[uniform.order] = ucode; if (is_buffer_global) { //globals are indices into the global table - uniform_sizes.write[E->get().order] = _get_datatype_size(ShaderLanguage::TYPE_UINT); - uniform_alignments.write[E->get().order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT); + uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT); + uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT); } else { - uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type); - uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type); + uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type); + uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type); } } - p_actions.uniforms->insert(E->key(), E->get()); + p_actions.uniforms->insert(uniform_name, uniform); } for (int i = 0; i < max_uniforms; i++) { @@ -688,21 +722,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light; + Vector<StringName> varying_names; + for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { - if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) { - var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get())); - fragment_varyings.insert(E->key()); + varying_names.push_back(E->key()); + } + + varying_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced + + for (int k = 0; k < varying_names.size(); k++) { + StringName varying_name = varying_names[k]; + const SL::ShaderNode::Varying &varying = pnode->varyings[varying_name]; + + if (varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) { + var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(varying_name, varying)); + fragment_varyings.insert(varying_name); continue; } String vcode; - String interp_mode = _interpstr(E->get().interpolation); - vcode += _prestr(E->get().precision); - vcode += _typestr(E->get().type); - vcode += " " + _mkid(E->key()); - if (E->get().array_size > 0) { + String interp_mode = _interpstr(varying.interpolation); + vcode += _prestr(varying.precision); + vcode += _typestr(varying.type); + vcode += " " + _mkid(varying_name); + if (varying.array_size > 0) { vcode += "["; - vcode += itos(E->get().array_size); + vcode += itos(varying.array_size); vcode += "]"; } vcode += ";\n"; @@ -959,25 +1004,30 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge declaration += itos(adnode->declarations[i].size); } declaration += "]"; - int sz = adnode->declarations[i].initializer.size(); - if (sz > 0) { + if (adnode->declarations[i].single_expression) { declaration += "="; - if (adnode->datatype == SL::TYPE_STRUCT) { - declaration += _mkid(adnode->struct_name); - } else { - declaration += _typestr(adnode->datatype); - } - declaration += "["; - declaration += itos(sz); - declaration += "]"; - declaration += "("; - for (int j = 0; j < sz; j++) { - declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (j != sz - 1) { - declaration += ", "; + declaration += _dump_node_code(adnode->declarations[i].initializer[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } else { + int sz = adnode->declarations[i].initializer.size(); + if (sz > 0) { + declaration += "="; + if (adnode->datatype == SL::TYPE_STRUCT) { + declaration += _mkid(adnode->struct_name); + } else { + declaration += _typestr(adnode->datatype); + } + declaration += "["; + declaration += itos(sz); + declaration += "]"; + declaration += "("; + for (int j = 0; j < sz; j++) { + declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + if (j != sz - 1) { + declaration += ", "; + } } + declaration += ")"; } - declaration += ")"; } } @@ -988,7 +1038,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge bool use_fragment_varying = false; if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) { - if (anode->assign_expression != nullptr) { + if (anode->assign_expression != nullptr && shader->varyings.has(anode->name)) { use_fragment_varying = true; } else { if (p_assigning) { diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index f7242a2b17..6f29ff42bc 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -30,8 +30,12 @@ #include "shader_rd.h" +#include "core/io/compression.h" +#include "core/os/dir_access.h" +#include "core/os/file_access.h" #include "renderer_compositor_rd.h" #include "servers/rendering/rendering_device.h" +#include "thirdparty/misc/smolv.h" void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { Vector<String> lines = String(p_code).split("\n"); @@ -97,6 +101,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) { name = p_name; + if (p_compute_code) { _add_stage(p_compute_code, STAGE_TYPE_COMPUTE); is_compute = true; @@ -109,6 +114,18 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con _add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT); } } + + StringBuilder tohash; + tohash.append("[VersionKey]"); + tohash.append(RenderingDevice::get_singleton()->shader_get_cache_key()); + tohash.append("[Vertex]"); + tohash.append(p_vertex_code ? p_vertex_code : ""); + tohash.append("[Fragment]"); + tohash.append(p_fragment_code ? p_fragment_code : ""); + tohash.append("[Compute]"); + tohash.append(p_compute_code ? p_compute_code : ""); + + base_sha256 = tohash.as_string().sha256_text(); } RID ShaderRD::version_create() { @@ -131,6 +148,9 @@ void ShaderRD::_clear_version(Version *p_version) { } memdelete_arr(p_version->variants); + if (p_version->variant_stages) { + memdelete_arr(p_version->variant_stages); + } p_version->variants = nullptr; } } @@ -183,7 +203,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { return; //variant is disabled, return } - Vector<RD::ShaderStageData> stages; + Vector<RD::ShaderStageData> &stages = p_version->variant_stages[p_variant]; String error; String current_source; @@ -313,6 +333,197 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio return source_code; } +String ShaderRD::_version_get_sha1(Version *p_version) const { + StringBuilder hash_build; + + hash_build.append("[uniforms]"); + hash_build.append(p_version->uniforms.get_data()); + hash_build.append("[vertex_globals]"); + hash_build.append(p_version->vertex_globals.get_data()); + hash_build.append("[fragment_globals]"); + hash_build.append(p_version->fragment_globals.get_data()); + hash_build.append("[compute_globals]"); + hash_build.append(p_version->compute_globals.get_data()); + + Vector<StringName> code_sections; + for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) { + code_sections.push_back(E->key()); + } + code_sections.sort_custom<StringName::AlphCompare>(); + + for (int i = 0; i < code_sections.size(); i++) { + hash_build.append(String("[code:") + String(code_sections[i]) + "]"); + hash_build.append(p_version->code_sections[code_sections[i]].get_data()); + } + for (int i = 0; i < p_version->custom_defines.size(); i++) { + hash_build.append("[custom_defines:" + itos(i) + "]"); + hash_build.append(p_version->custom_defines[i].get_data()); + } + + return hash_build.as_string().sha1_text(); +} + +static const char *shader_file_header = "GDSC"; +static const uint32_t cache_file_version = 1; + +bool ShaderRD::_load_from_cache(Version *p_version) { + String sha1 = _version_get_sha1(p_version); + String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache"; + + uint64_t time_from = OS::get_singleton()->get_ticks_usec(); + + FileAccessRef f = FileAccess::open(path, FileAccess::READ); + if (!f) { + return false; + } + + char header[5] = { 0, 0, 0, 0, 0 }; + f->get_buffer((uint8_t *)header, 4); + ERR_FAIL_COND_V(header != String(shader_file_header), false); + + uint32_t file_version = f->get_32(); + if (file_version != cache_file_version) { + return false; // wrong version + } + + uint32_t variant_count = f->get_32(); + + ERR_FAIL_COND_V(variant_count != (uint32_t)variant_defines.size(), false); //should not happen but check + + bool success = true; + for (uint32_t i = 0; i < variant_count; i++) { + uint32_t stage_count = f->get_32(); + p_version->variant_stages[i].resize(stage_count); + for (uint32_t j = 0; j < stage_count; j++) { + p_version->variant_stages[i].write[j].shader_stage = RD::ShaderStage(f->get_32()); + + int compression = f->get_32(); + uint32_t length = f->get_32(); + + if (compression == 0) { + Vector<uint8_t> data; + data.resize(length); + + f->get_buffer(data.ptrw(), length); + + p_version->variant_stages[i].write[j].spir_v = data; + } else { + Vector<uint8_t> data; + + if (compression == 2) { + //zstd + int smol_length = f->get_32(); + Vector<uint8_t> zstd_data; + + zstd_data.resize(smol_length); + f->get_buffer(zstd_data.ptrw(), smol_length); + + data.resize(length); + Compression::decompress(data.ptrw(), data.size(), zstd_data.ptr(), zstd_data.size(), Compression::MODE_ZSTD); + + } else { + data.resize(length); + f->get_buffer(data.ptrw(), length); + } + + Vector<uint8_t> spirv; + uint32_t spirv_size = smolv::GetDecodedBufferSize(data.ptr(), data.size()); + spirv.resize(spirv_size); + if (!smolv::Decode(data.ptr(), data.size(), spirv.ptrw(), spirv_size)) { + ERR_PRINT("Malformed smolv input uncompressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(j)); + success = false; + break; + } + p_version->variant_stages[i].write[j].spir_v = spirv; + } + } + } + + if (!success) { + for (uint32_t i = 0; i < variant_count; i++) { + p_version->variant_stages[i].resize(0); + } + return false; + } + + float time_ms = double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0; + + print_verbose("Shader cache load success '" + path + "' " + rtos(time_ms) + "ms."); + + for (uint32_t i = 0; i < variant_count; i++) { + RID shader = RD::get_singleton()->shader_create(p_version->variant_stages[i]); + { + MutexLock lock(variant_set_mutex); + p_version->variants[i] = shader; + } + } + + memdelete_arr(p_version->variant_stages); //clear stages + p_version->variant_stages = nullptr; + p_version->valid = true; + return true; +} + +void ShaderRD::_save_to_cache(Version *p_version) { + String sha1 = _version_get_sha1(p_version); + String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache"; + + FileAccessRef f = FileAccess::open(path, FileAccess::WRITE); + ERR_FAIL_COND(!f); + f->store_buffer((const uint8_t *)shader_file_header, 4); + f->store_32(cache_file_version); //file version + uint32_t variant_count = variant_defines.size(); + f->store_32(variant_count); //variant count + + for (uint32_t i = 0; i < variant_count; i++) { + f->store_32(p_version->variant_stages[i].size()); //stage count + for (int j = 0; j < p_version->variant_stages[i].size(); j++) { + f->store_32(p_version->variant_stages[i][j].shader_stage); //stage count + Vector<uint8_t> spirv = p_version->variant_stages[i][j].spir_v; + + bool save_uncompressed = true; + if (shader_cache_save_compressed) { + smolv::ByteArray smolv; + bool strip_debug = !shader_cache_save_debug; + if (!smolv::Encode(spirv.ptr(), spirv.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) { + ERR_PRINT("Error compressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(i)); + } else { + bool compress_zstd = shader_cache_save_compressed_zstd; + + if (compress_zstd) { + Vector<uint8_t> zstd; + zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD)); + int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD); + if (dst_size >= 0 && (uint32_t)dst_size < smolv.size()) { + f->store_32(2); //compressed zstd + f->store_32(smolv.size()); //size of smolv buffer + f->store_32(dst_size); //size of smolv buffer + f->store_buffer(zstd.ptr(), dst_size); //smolv buffer + } else { + compress_zstd = false; + } + } + + if (!compress_zstd) { + f->store_32(1); //compressed + f->store_32(smolv.size()); //size of smolv buffer + f->store_buffer(&smolv[0], smolv.size()); //smolv buffer + } + save_uncompressed = false; + } + } + + if (save_uncompressed) { + f->store_32(0); //uncompressed + f->store_32(spirv.size()); //stage count + f->store_buffer(spirv.ptr(), spirv.size()); //stage count + } + } + } + + f->close(); +} + void ShaderRD::_compile_version(Version *p_version) { _clear_version(p_version); @@ -320,6 +531,15 @@ void ShaderRD::_compile_version(Version *p_version) { p_version->dirty = false; p_version->variants = memnew_arr(RID, variant_defines.size()); + typedef Vector<RD::ShaderStageData> ShaderStageArray; + p_version->variant_stages = memnew_arr(ShaderStageArray, variant_defines.size()); + + if (shader_cache_dir_valid) { + if (_load_from_cache(p_version)) { + return; + } + } + #if 1 RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version); @@ -351,10 +571,20 @@ void ShaderRD::_compile_version(Version *p_version) { } } memdelete_arr(p_version->variants); + if (p_version->variant_stages) { + memdelete_arr(p_version->variant_stages); + } p_version->variants = nullptr; + p_version->variant_stages = nullptr; return; + } else if (shader_cache_dir_valid) { + //save shader cache + _save_to_cache(p_version); } + memdelete_arr(p_version->variant_stages); //clear stages + p_version->variant_stages = nullptr; + p_version->valid = true; } @@ -443,6 +673,8 @@ bool ShaderRD::is_variant_enabled(int p_variant) const { return variants_enabled[p_variant]; } +bool ShaderRD::shader_cache_cleanup_on_start = false; + ShaderRD::ShaderRD() { // Do not feel forced to use this, in most cases it makes little to no difference. bool use_32_threads = false; @@ -469,8 +701,64 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String variant_defines.push_back(p_variant_defines[i].utf8()); variants_enabled.push_back(true); } + + if (shader_cache_dir != String()) { + StringBuilder hash_build; + + hash_build.append("[base_hash]"); + hash_build.append(base_sha256); + hash_build.append("[general_defines]"); + hash_build.append(general_defines.get_data()); + for (int i = 0; i < variant_defines.size(); i++) { + hash_build.append("[variant_defines:" + itos(i) + "]"); + hash_build.append(variant_defines[i].get_data()); + } + + base_sha256 = hash_build.as_string().sha256_text(); + + DirAccessRef d = DirAccess::open(shader_cache_dir); + ERR_FAIL_COND(!d); + if (d->change_dir(name) != OK) { + Error err = d->make_dir(name); + ERR_FAIL_COND(err != OK); + d->change_dir(name); + } + + //erase other versions? + if (shader_cache_cleanup_on_start) { + } + // + if (d->change_dir(base_sha256) != OK) { + Error err = d->make_dir(base_sha256); + ERR_FAIL_COND(err != OK); + } + shader_cache_dir_valid = true; + + print_verbose("Shader '" + name + "' SHA256: " + base_sha256); + } +} + +void ShaderRD::set_shader_cache_dir(const String &p_dir) { + shader_cache_dir = p_dir; +} + +void ShaderRD::set_shader_cache_save_compressed(bool p_enable) { + shader_cache_save_compressed = p_enable; } +void ShaderRD::set_shader_cache_save_compressed_zstd(bool p_enable) { + shader_cache_save_compressed_zstd = p_enable; +} + +void ShaderRD::set_shader_cache_save_debug(bool p_enable) { + shader_cache_save_debug = p_enable; +} + +String ShaderRD::shader_cache_dir; +bool ShaderRD::shader_cache_save_compressed = true; +bool ShaderRD::shader_cache_save_compressed_zstd = true; +bool ShaderRD::shader_cache_save_debug = true; + ShaderRD::~ShaderRD() { List<RID> remaining; version_owner.get_owned_list(&remaining); diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index f20d539621..9a68e02007 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -59,7 +59,8 @@ class ShaderRD { Map<StringName, CharString> code_sections; Vector<CharString> custom_defines; - RID *variants; //same size as version defines + Vector<RD::ShaderStageData> *variant_stages = nullptr; + RID *variants = nullptr; //same size as version defines bool valid; bool dirty; @@ -96,10 +97,19 @@ class ShaderRD { bool is_compute = false; - const char *name; + String name; CharString base_compute_defines; + String base_sha256; + + static String shader_cache_dir; + static bool shader_cache_cleanup_on_start; + static bool shader_cache_save_compressed; + static bool shader_cache_save_compressed_zstd; + static bool shader_cache_save_debug; + bool shader_cache_dir_valid = false; + enum StageType { STAGE_TYPE_VERTEX, STAGE_TYPE_FRAGMENT, @@ -113,6 +123,10 @@ class ShaderRD { void _add_stage(const char *p_code, StageType p_stage_type); + String _version_get_sha1(Version *p_version) const; + bool _load_from_cache(Version *p_version); + void _save_to_cache(Version *p_version); + protected: ShaderRD(); void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name); @@ -148,6 +162,11 @@ public: void set_variant_enabled(int p_variant, bool p_enabled); bool is_variant_enabled(int p_variant) const; + static void set_shader_cache_dir(const String &p_dir); + static void set_shader_cache_save_compressed(bool p_enable); + static void set_shader_cache_save_compressed_zstd(bool p_enable); + static void set_shader_cache_save_debug(bool p_enable); + RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version); void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = ""); diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index cf4c77db0d..2186bd174b 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -101,36 +101,34 @@ void main() { uint offset = trail_size * stride * gl_InstanceIndex; - mat4 matrix; vec4 pcolor; + vec2 new_vertex; { uint boffset = offset + bone_attrib.x * stride; - matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x; - pcolor = transforms.data[boffset + 3] * weight_attrib.x; + new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x; + pcolor = transforms.data[boffset + 2] * weight_attrib.x; } if (weight_attrib.y > 0.001) { uint boffset = offset + bone_attrib.y * stride; - matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y; - pcolor += transforms.data[boffset + 3] * weight_attrib.y; + new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y; + pcolor += transforms.data[boffset + 2] * weight_attrib.y; } if (weight_attrib.z > 0.001) { uint boffset = offset + bone_attrib.z * stride; - matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z; - pcolor += transforms.data[boffset + 3] * weight_attrib.z; + new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z; + pcolor += transforms.data[boffset + 2] * weight_attrib.z; } if (weight_attrib.w > 0.001) { uint boffset = offset + bone_attrib.w * stride; - matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w; - pcolor += transforms.data[boffset + 3] * weight_attrib.w; + new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w; + pcolor += transforms.data[boffset + 2] * weight_attrib.w; } - instance_custom = transforms.data[offset + 4]; + instance_custom = transforms.data[offset + 3]; + vertex = new_vertex; color *= pcolor; - matrix = transpose(matrix); - world_matrix = world_matrix * matrix; - } else #endif // USE_ATTRIBUTES @@ -283,7 +281,7 @@ vec2 screen_uv_to_sdf(vec2 p_uv) { float texture_sdf(vec2 p_sdf) { vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw; float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r; - d = d * SDF_MAX_LENGTH - 1.0; + d *= SDF_MAX_LENGTH; return d * canvas_data.tex_to_sdf; } diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl index 65a554e839..2bdfbabfcf 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl @@ -7,7 +7,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels; -layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf; +layout(r16_snorm, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf; layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process; layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process; @@ -32,7 +32,7 @@ void main() { #ifdef MODE_LOAD bool solid = imageLoad(src_pixels, pos).r > 0.5; - imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0)); + imageStore(dst_process, pos, solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0)); #endif #ifdef MODE_LOAD_SHRINK @@ -43,6 +43,8 @@ void main() { ivec2 rel = ivec2(32767); float d = 1e20; + int found = 0; + int solid_found = 0; for (int i = 0; i < s; i++) { for (int j = 0; j < s; j++) { ivec2 src_pos = base + ivec2(i, j); @@ -56,10 +58,17 @@ void main() { d = dist; rel = src_pos; } + solid_found++; } + found++; } } + if (solid_found == found) { + //mark solid only if all are solid + rel = ivec2(-32767); + } + imageStore(dst_process, pos, ivec4(rel, 0, 0)); #endif @@ -70,6 +79,12 @@ void main() { ivec2 rel = imageLoad(src_process, pos).xy; + bool solid = rel.x < 0; + + if (solid) { + rel = -rel - ivec2(1); + } + if (center != rel) { //only process if it does not point to itself const int ofs_table_size = 8; @@ -92,6 +107,15 @@ void main() { continue; } ivec2 src_rel = imageLoad(src_process, src_pos).xy; + bool src_solid = src_rel.x < 0; + if (src_solid) { + src_rel = -src_rel - ivec2(1); + } + + if (src_solid != solid) { + src_rel = ivec2(src_pos << params.shift); //point to itself if of different type + } + float src_dist = length(vec2(src_rel - center)); if (src_dist < dist) { dist = src_dist; @@ -100,18 +124,31 @@ void main() { } } + if (solid) { + rel = -rel - ivec2(1); + } + imageStore(dst_process, pos, ivec4(rel, 0, 0)); #endif #ifdef MODE_STORE ivec2 rel = imageLoad(src_process, pos).xy; + + bool solid = rel.x < 0; + + if (solid) { + rel = -rel - ivec2(1); + } + float d = length(vec2(rel - pos)); - if (d > 0.01) { - d += 1.0; //make it signed + + if (solid) { + d = -d; } + d /= SDF_MAX_LENGTH; - d = clamp(d, 0.0, 1.0); + d = clamp(d, -1.0, 1.0); imageStore(dst_sdf, pos, vec4(d)); #endif @@ -122,13 +159,20 @@ void main() { ivec2 center = base + ivec2(params.shift); ivec2 rel = imageLoad(src_process, pos).xy; + + bool solid = rel.x < 0; + + if (solid) { + rel = -rel - ivec2(1); + } + float d = length(vec2(rel - center)); - if (d > 0.01) { - d += 1.0; //make it signed + if (solid) { + d = -d; } d /= SDF_MAX_LENGTH; - d = clamp(d, 0.0, 1.0); + d = clamp(d, -1.0, 1.0); imageStore(dst_sdf, pos, vec4(d)); #endif diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index beaff10793..9f8410fd8a 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -19,6 +19,8 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 #define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 +#define SDF_MAX_LENGTH 16384.0 + /* SET 0: GLOBAL DATA */ layout(set = 0, binding = 1) uniform sampler material_samplers[12]; @@ -54,6 +56,7 @@ struct Attractor { #define COLLIDER_TYPE_BOX 1 #define COLLIDER_TYPE_SDF 2 #define COLLIDER_TYPE_HEIGHT_FIELD 3 +#define COLLIDER_TYPE_2D_SDF 4 struct Collider { mat4 transform; @@ -452,128 +455,167 @@ void main() { #endif - for (uint i = 0; i < FRAME.collider_count; i++) { - vec3 normal; - float depth; - bool col = false; + if (FRAME.collider_count == 1 && FRAME.colliders[0].type == COLLIDER_TYPE_2D_SDF) { + //2D collision - vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz; - vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform); + vec2 pos = PARTICLE.xform[3].xy; + vec4 to_sdf_x = FRAME.colliders[0].transform[0]; + vec4 to_sdf_y = FRAME.colliders[0].transform[1]; + vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y)); - switch (FRAME.colliders[i].type) { - case COLLIDER_TYPE_SPHERE: { - float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x); + vec4 sdf_to_screen = vec4(FRAME.colliders[0].extents, FRAME.colliders[0].scale); - if (d < 0.0) { - col = true; - depth = -d; - normal = normalize(rel_vec); - } + vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw; - } break; - case COLLIDER_TYPE_BOX: { - vec3 abs_pos = abs(local_pos); - vec3 sgn_pos = sign(local_pos); + if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) { + vec2 pos2 = pos + vec2(0, particle_size); + vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y)); + float sdf_particle_size = distance(sdf_pos, sdf_pos2); + + float d = texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos).r * SDF_MAX_LENGTH; + + d -= sdf_particle_size; + + if (d < 0.0) { + const float EPSILON = 0.001; + vec2 n = normalize(vec2( + texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(EPSILON, 0.0)).r, + texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(0.0, EPSILON)).r)); + + collided = true; + sdf_pos2 = sdf_pos + n * d; + pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[3])); + + n = pos - pos2; + + collision_normal = normalize(vec3(n, 0.0)); + collision_depth = length(n); + } + } + + } else { + for (uint i = 0; i < FRAME.collider_count; i++) { + vec3 normal; + float depth; + bool col = false; - if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) { - //point outside box + vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz; + vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform); - vec3 closest = min(abs_pos, FRAME.colliders[i].extents); - vec3 rel = abs_pos - closest; - depth = length(rel) - particle_size; - if (depth < 0.0) { + switch (FRAME.colliders[i].type) { + case COLLIDER_TYPE_SPHERE: { + float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x); + + if (d < 0.0) { col = true; - normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos); - depth = -depth; + depth = -d; + normal = normalize(rel_vec); } - } else { - //point inside box - vec3 axis_len = FRAME.colliders[i].extents - abs_pos; - // there has to be a faster way to do this? - if (all(lessThan(axis_len.xx, axis_len.yz))) { - normal = vec3(1, 0, 0); - } else if (all(lessThan(axis_len.yy, axis_len.xz))) { - normal = vec3(0, 1, 0); + + } break; + case COLLIDER_TYPE_BOX: { + vec3 abs_pos = abs(local_pos); + vec3 sgn_pos = sign(local_pos); + + if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) { + //point outside box + + vec3 closest = min(abs_pos, FRAME.colliders[i].extents); + vec3 rel = abs_pos - closest; + depth = length(rel) - particle_size; + if (depth < 0.0) { + col = true; + normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos); + depth = -depth; + } } else { - normal = vec3(0, 0, 1); + //point inside box + vec3 axis_len = FRAME.colliders[i].extents - abs_pos; + // there has to be a faster way to do this? + if (all(lessThan(axis_len.xx, axis_len.yz))) { + normal = vec3(1, 0, 0); + } else if (all(lessThan(axis_len.yy, axis_len.xz))) { + normal = vec3(0, 1, 0); + } else { + normal = vec3(0, 0, 1); + } + + col = true; + depth = dot(normal * axis_len, vec3(1)) + particle_size; + normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos); } - col = true; - depth = dot(normal * axis_len, vec3(1)) + particle_size; - normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos); - } + } break; + case COLLIDER_TYPE_SDF: { + vec3 apos = abs(local_pos); + float extra_dist = 0.0; + if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside + vec3 mpos = min(apos, FRAME.colliders[i].extents); + extra_dist = distance(mpos, apos); + } - } break; - case COLLIDER_TYPE_SDF: { - vec3 apos = abs(local_pos); - float extra_dist = 0.0; - if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside - vec3 mpos = min(apos, FRAME.colliders[i].extents); - extra_dist = distance(mpos, apos); - } + if (extra_dist > particle_size) { + continue; + } - if (extra_dist > particle_size) { - continue; - } + vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5; + float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r; + s *= FRAME.colliders[i].scale; + s += extra_dist; + if (s < particle_size) { + col = true; + depth = particle_size - s; + const float EPSILON = 0.001; + normal = mat3(FRAME.colliders[i].transform) * + normalize( + vec3( + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r, + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r, + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r)); + } - vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5; - float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r; - s *= FRAME.colliders[i].scale; - s += extra_dist; - if (s < particle_size) { - col = true; - depth = particle_size - s; - const float EPSILON = 0.001; - normal = mat3(FRAME.colliders[i].transform) * - normalize( - vec3( - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r, - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r, - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r)); - } + } break; + case COLLIDER_TYPE_HEIGHT_FIELD: { + vec3 local_pos_bottom = local_pos; + local_pos_bottom.y -= particle_size; - } break; - case COLLIDER_TYPE_HEIGHT_FIELD: { - vec3 local_pos_bottom = local_pos; - local_pos_bottom.y -= particle_size; + if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) { + continue; + } + const float DELTA = 1.0 / 8192.0; - if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) { - continue; - } + vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5; - const float DELTA = 1.0 / 8192.0; + float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r; - vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5; + if (y > uvw_pos.y) { + //inside heightfield - float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r; + vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; + vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; + vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents; - if (y > uvw_pos.y) { - //inside heightfield + normal = normalize(cross(pos1 - pos2, pos1 - pos3)); + float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y; - vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; - vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents; - vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents; + col = true; + depth = dot(normal, pos1) - dot(normal, local_pos_bottom); + } - normal = normalize(cross(pos1 - pos2, pos1 - pos3)); - float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y; + } break; + } - col = true; - depth = dot(normal, pos1) - dot(normal, local_pos_bottom); + if (col) { + if (!collided) { + collided = true; + collision_normal = normal; + collision_depth = depth; + } else { + vec3 c = collision_normal * collision_depth; + c += normal * max(0.0, depth - dot(normal, c)); + collision_normal = normalize(c); + collision_depth = length(c); } - - } break; - } - - if (col) { - if (!collided) { - collided = true; - collision_normal = normal; - collision_depth = depth; - } else { - vec3 c = collision_normal * collision_depth; - c += normal * max(0.0, depth - dot(normal, c)); - collision_normal = normalize(c); - collision_depth = length(c); } } } diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index e2bebadf1a..4dceeea995 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -53,6 +53,11 @@ layout(push_constant, binding = 0, std430) uniform Params { vec3 align_up; uint align_mode; + + bool order_by_lifetime; + uint lifetime_split; + bool lifetime_reverse; + uint pad; } params; @@ -80,7 +85,6 @@ void main() { #ifdef MODE_FILL_INSTANCES uint particle = gl_GlobalInvocationID.x; - uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom if (particle >= params.total_particles) { return; //discard @@ -93,7 +97,41 @@ void main() { } else { particle = uint(sort_buffer.data[particle].y); //use index from sort buffer } -#endif +#else + if (params.order_by_lifetime) { + if (params.trail_size > 1) { + uint limit = (params.total_particles / params.trail_size) - params.lifetime_split; + + uint base_index = particle / params.trail_size; + uint base_offset = particle % params.trail_size; + + if (params.lifetime_reverse) { + base_index = (params.total_particles / params.trail_size) - base_index - 1; + } + + if (base_index < limit) { + base_index = params.lifetime_split + base_index; + } else { + base_index -= limit; + } + + particle = base_index * params.trail_size + base_offset; + + } else { + uint limit = params.total_particles - params.lifetime_split; + + if (params.lifetime_reverse) { + particle = params.total_particles - particle - 1; + } + + if (particle < limit) { + particle = params.lifetime_split + particle; + } else { + particle -= limit; + } + } + } +#endif // USE_SORT_BUFFER mat4 txform; @@ -165,12 +203,17 @@ void main() { #ifdef MODE_2D + uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom + instances.data[write_offset + 0] = txform[0]; instances.data[write_offset + 1] = txform[1]; instances.data[write_offset + 2] = particles.data[particle].color; instances.data[write_offset + 3] = particles.data[particle].custom; #else + + uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom + instances.data[write_offset + 0] = txform[0]; instances.data[write_offset + 1] = txform[1]; instances.data[write_offset + 2] = txform[2]; |