diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd')
20 files changed, 1174 insertions, 348 deletions
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index 527ed09584..409cfdfecf 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -389,14 +389,14 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { zeromem(©.push_constant, sizeof(CopyPushConstant)); CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW; uint32_t base_flags = 0; - int32_t x_groups = (p_size.width - 1) / 8 + 1; - int32_t y_groups = (p_size.height - 1) / 8 + 1; + int32_t x_groups = (p_size.width + 7) / 8; + int32_t y_groups = (p_size.height + 7) / 8; copy.push_constant.section[2] = p_size.x; copy.push_constant.section[3] = p_size.y; @@ -411,29 +411,15 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, copy.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also - //HORIZONTAL RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3); if (p_auto_exposure.is_valid() && p_first_pass) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_auto_exposure), 1); } - copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0) | (p_high_quality ? COPY_FLAG_HIGH_QUALITY_GLOW : 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); - - copy_mode = COPY_MODE_GAUSSIAN_GLOW; - - //VERTICAL - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3); - - copy.push_constant.flags = base_flags; + copy.push_constant.flags = base_flags | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0) | (p_high_quality ? COPY_FLAG_HIGH_QUALITY_GLOW : 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); @@ -692,7 +678,13 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, tonemap.push_constant.use_glow = p_settings.use_glow; tonemap.push_constant.glow_intensity = p_settings.glow_intensity; - tonemap.push_constant.glow_level_flags = p_settings.glow_level_flags; + tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something + tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1]; + tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2]; + tonemap.push_constant.glow_levels[3] = p_settings.glow_levels[3]; + tonemap.push_constant.glow_levels[4] = p_settings.glow_levels[4]; + tonemap.push_constant.glow_levels[5] = p_settings.glow_levels[5]; + tonemap.push_constant.glow_levels[6] = p_settings.glow_levels[6]; tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x; tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y; tonemap.push_constant.glow_mode = p_settings.glow_mode; @@ -708,6 +700,7 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, tonemap.push_constant.use_color_correction = p_settings.use_color_correction; tonemap.push_constant.use_fxaa = p_settings.use_fxaa; + tonemap.push_constant.use_debanding = p_settings.use_debanding; tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; @@ -1758,6 +1751,7 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { resolve.shader.version_free(resolve.shader_version); roughness.shader.version_free(roughness.shader_version); roughness_limiter.shader.version_free(roughness_limiter.shader_version); + sort.shader.version_free(sort.shader_version); specular_merge.shader.version_free(specular_merge.shader_version); ssao.blur_shader.version_free(ssao.blur_shader_version); ssao.gather_shader.version_free(ssao.gather_shader_version); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h index e434bbc372..679263fbf6 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -175,18 +175,20 @@ class RasterizerEffectsRD { uint32_t tonemapper; uint32_t glow_texture_size[2]; - float glow_intensity; - uint32_t glow_level_flags; + uint32_t pad3; + uint32_t glow_mode; + float glow_levels[7]; float exposure; float white; float auto_exposure_grey; + uint32_t pad2; float pixel_size[2]; uint32_t use_fxaa; - uint32_t pad; + uint32_t use_debanding; }; /* tonemap actually writes to a framebuffer, which is @@ -607,7 +609,7 @@ public: void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far); void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false); void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); - void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); + void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); @@ -627,7 +629,7 @@ public: GlowMode glow_mode = GLOW_MODE_ADD; float glow_intensity = 1.0; - uint32_t glow_level_flags = 0; + float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 }; Vector2i glow_texture_size; bool glow_use_bicubic_upscale = false; RID glow_texture; @@ -649,6 +651,7 @@ public: RID color_correction_texture; bool use_fxaa = false; + bool use_debanding = false; Vector2i texture_size; }; diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index efa16628e4..35b0591289 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -1335,6 +1335,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende if (scene_state.ubo.fog_height_density >= 0.0001) { scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; } + scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); float fog_energy = environment_get_fog_light_energy(p_environment); @@ -2018,6 +2019,39 @@ void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase ** } } +void RasterizerSceneHighEndRD::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) { + RENDER_TIMESTAMP("Setup Render Collider Heightfield"); + + _update_render_base_uniform_set(); + + render_pass++; + + scene_state.ubo.dual_paraboloid_side = 0; + + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); + + render_list.clear(); + + PassMode pass_mode = PASS_MODE_SHADOW; + + _fill_render_list(p_cull_result, p_cull_count, pass_mode); + + _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + + RENDER_TIMESTAMP("Render Collider Heightield"); + + render_list.sort_by_key(false); + + _fill_instances(render_list.elements, render_list.element_count, true); + + { + //regular forward for now + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_fb), render_list.elements, render_list.element_count, false, pass_mode, true, RID(), RID()); + RD::get_singleton()->draw_list_end(); + } +} + void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering Material"); @@ -2728,12 +2762,16 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; actions.renames["DEPTH"] = "gl_FragDepth"; actions.renames["OUTPUT_IS_SRGB"] = "true"; + actions.renames["FOG"] = "custom_fog"; + actions.renames["RADIANCE"] = "custom_radiance"; + actions.renames["IRRADIANCE"] = "custom_irradiance"; //for light actions.renames["VIEW"] = "view"; actions.renames["LIGHT_COLOR"] = "light_color"; actions.renames["LIGHT"] = "light"; actions.renames["ATTENUATION"] = "attenuation"; + actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation"; actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; actions.renames["SPECULAR_LIGHT"] = "specular_light"; @@ -2764,6 +2802,10 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n"; + actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n"; + actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n"; + actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h index 1aad9039ff..566022ae5b 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h @@ -308,12 +308,6 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float viewport_size[2]; float screen_pixel_size[2]; - float time; - float reflection_multiplier; - - uint32_t pancake_shadows; - uint32_t pad; - float directional_penumbra_shadow_kernel[128]; //32 vec4s float directional_soft_shadow_kernel[128]; float penumbra_shadow_kernel[128]; @@ -366,7 +360,6 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { uint32_t volumetric_fog_pad; // Fog - uint32_t fog_enabled; float fog_density; float fog_height; @@ -374,6 +367,13 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float fog_light_color[3]; float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; + + uint32_t pancake_shadows; }; UBO ubo; @@ -581,6 +581,7 @@ protected: virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count); public: virtual void set_time(double p_time, double p_step); diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp index 958d8eac1f..f708b6ce00 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -1173,6 +1173,94 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm /* Update dynamic lights */ { + int32_t cascade_light_count[SDFGI::MAX_CASCADES]; + + for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { + SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; + + SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; + uint32_t idx = 0; + for (uint32_t j = 0; j < p_directional_light_count; j++) { + if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { + break; + } + + LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]); + ERR_CONTINUE(!li); + Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); + dir.y *= rb->sdfgi->y_mult; + dir.normalize(); + lights[idx].direction[0] = dir.x; + lights[idx].direction[1] = dir.y; + lights[idx].direction[2] = dir.z; + Color color = storage->light_get_color(li->light); + color = color.to_linear(); + lights[idx].color[0] = color.r; + lights[idx].color[1] = color.g; + lights[idx].color[2] = color.b; + lights[idx].type = RS::LIGHT_DIRECTIONAL; + lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); + lights[idx].has_shadow = storage->light_has_shadow(li->light); + + idx++; + } + + AABB cascade_aabb; + cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size; + cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size; + + for (uint32_t j = 0; j < p_positional_light_count; j++) { + if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { + break; + } + + LightInstance *li = light_instance_owner.getornull(p_positional_light_instances[j]); + ERR_CONTINUE(!li); + + uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); + if (i > max_sdfgi_cascade) { + continue; + } + + if (!cascade_aabb.intersects(li->aabb)) { + continue; + } + + Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); + //faster to not do this here + //dir.y *= rb->sdfgi->y_mult; + //dir.normalize(); + lights[idx].direction[0] = dir.x; + lights[idx].direction[1] = dir.y; + lights[idx].direction[2] = dir.z; + Vector3 pos = li->transform.origin; + pos.y *= rb->sdfgi->y_mult; + lights[idx].position[0] = pos.x; + lights[idx].position[1] = pos.y; + lights[idx].position[2] = pos.z; + Color color = storage->light_get_color(li->light); + color = color.to_linear(); + lights[idx].color[0] = color.r; + lights[idx].color[1] = color.g; + lights[idx].color[2] = color.b; + lights[idx].type = storage->light_get_type(li->light); + lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); + lights[idx].has_shadow = storage->light_has_shadow(li->light); + lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); + lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); + lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)); + lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + + idx++; + } + + if (idx > 0) { + RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); + } + + cascade_light_count[i] = idx; + } + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]); @@ -1191,91 +1279,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; - - { //fill light buffer - - SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; - uint32_t idx = 0; - for (uint32_t j = 0; j < p_directional_light_count; j++) { - if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { - break; - } - - LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]); - ERR_CONTINUE(!li); - Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); - dir.y *= rb->sdfgi->y_mult; - dir.normalize(); - lights[idx].direction[0] = dir.x; - lights[idx].direction[1] = dir.y; - lights[idx].direction[2] = dir.z; - Color color = storage->light_get_color(li->light); - color = color.to_linear(); - lights[idx].color[0] = color.r; - lights[idx].color[1] = color.g; - lights[idx].color[2] = color.b; - lights[idx].type = RS::LIGHT_DIRECTIONAL; - lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); - lights[idx].has_shadow = storage->light_has_shadow(li->light); - - idx++; - } - - AABB cascade_aabb; - cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size; - cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size; - - for (uint32_t j = 0; j < p_positional_light_count; j++) { - if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { - break; - } - - LightInstance *li = light_instance_owner.getornull(p_positional_light_instances[j]); - ERR_CONTINUE(!li); - - uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); - if (i > max_sdfgi_cascade) { - continue; - } - - if (!cascade_aabb.intersects(li->aabb)) { - continue; - } - - Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); - //faster to not do this here - //dir.y *= rb->sdfgi->y_mult; - //dir.normalize(); - lights[idx].direction[0] = dir.x; - lights[idx].direction[1] = dir.y; - lights[idx].direction[2] = dir.z; - Vector3 pos = li->transform.origin; - pos.y *= rb->sdfgi->y_mult; - lights[idx].position[0] = pos.x; - lights[idx].position[1] = pos.y; - lights[idx].position[2] = pos.z; - Color color = storage->light_get_color(li->light); - color = color.to_linear(); - lights[idx].color[0] = color.r; - lights[idx].color[1] = color.g; - lights[idx].color[2] = color.b; - lights[idx].type = storage->light_get_type(li->light); - lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); - lights[idx].has_shadow = storage->light_has_shadow(li->light); - lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); - lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); - lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)); - lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); - - idx++; - } - - if (idx > 0) { - RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); - } - push_constant.light_count = idx; - } - + push_constant.light_count = cascade_light_count[i]; push_constant.cascade = i; RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0); @@ -2322,6 +2326,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons sky_scene_state.ubo.z_far = p_projection.get_z_far(); sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment); sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment); + sky_scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); float fog_energy = environment_get_fog_light_energy(p_environment); sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; @@ -2932,11 +2937,12 @@ void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMa env->auto_exp_scale = p_auto_exp_scale; } -void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7"); env->glow_enabled = p_enable; - env->glow_levels = p_level_flags; + env->glow_levels = p_levels; env->glow_intensity = p_intensity; env->glow_strength = p_strength; env->glow_mix = p_mix; @@ -2971,7 +2977,7 @@ void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::Envi env->sdfgi_y_scale = p_y_scale; } -void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density) { +void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -2982,6 +2988,7 @@ void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Colo env->fog_density = p_density; env->fog_height = p_height; env->fog_height_density = p_height_density; + env->fog_aerial_perspective = p_fog_aerial_perspective; } bool RasterizerSceneRD::environment_is_fog_enabled(RID p_env) const { @@ -3022,6 +3029,12 @@ float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const { return env->fog_height_density; } +float RasterizerSceneRD::environment_get_fog_aerial_perspective(RID p_env) const { + const Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, 0); + return env->fog_aerial_perspective; +} + void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -5237,25 +5250,21 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu } int max_glow_level = -1; - int glow_mask = 0; if (can_use_effects && env && env->glow_enabled) { /* see that blur textures are allocated */ - if (rb->blur[0].texture.is_null()) { + if (rb->blur[1].texture.is_null()) { _allocate_blur_textures(rb); _render_buffers_uniform_set_changed(p_render_buffers); } for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { - if (env->glow_levels & (1 << i)) { + if (env->glow_levels[i] > 0.0) { if (i >= rb->blur[1].mipmaps.size()) { max_glow_level = rb->blur[1].mipmaps.size() - 1; - glow_mask |= 1 << max_glow_level; - } else { max_glow_level = i; - glow_mask |= (1 << i); } } } @@ -5269,9 +5278,9 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu if (env->auto_exposure && rb->luminance.current.is_valid()) { luminance_texture = rb->luminance.current; } - storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); } else { - storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality); + storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality); } } } @@ -5294,7 +5303,9 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.use_glow = true; tonemap.glow_mode = RasterizerEffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode); tonemap.glow_intensity = env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? env->glow_mix : env->glow_intensity; - tonemap.glow_level_flags = glow_mask; + for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { + tonemap.glow_levels[i] = env->glow_levels[i]; + } tonemap.glow_texture_size.x = rb->blur[1].mipmaps[0].width; tonemap.glow_texture_size.y = rb->blur[1].mipmaps[0].height; tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale; @@ -5307,6 +5318,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.use_fxaa = true; } + tonemap.use_debanding = rb->use_debanding; tonemap.texture_size = Vector2i(rb->width, rb->height); if (env) { @@ -5686,13 +5698,14 @@ float RasterizerSceneRD::render_buffers_get_volumetric_fog_detail_spread(RID p_r return rb->volumetric_fog->spread; } -void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) { +void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; rb->height = p_height; rb->render_target = p_render_target; rb->msaa = p_msaa; rb->screen_space_aa = p_screen_space_aa; + rb->use_debanding = p_use_debanding; _free_render_buffer_data(rb); { @@ -7227,8 +7240,9 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc push_constant.grid_size = rb->sdfgi->cascade_size; push_constant.cascade = cascade; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) { + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + //must pre scroll existing data because not all is dirty RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_uniform_set, 0); @@ -7302,13 +7316,15 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc } //ok finally barrier - RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->compute_list_end(); } //clear dispatch indirect data uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 }; RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data, true); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + bool half_size = true; //much faster, very little difference static const int optimized_jf_group_size = 8; @@ -7511,6 +7527,23 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc } } +void RasterizerSceneRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) { + ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider)); + Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale(); + CameraMatrix cm; + cm.set_orthogonal(-extents.x, extents.x, -extents.z, extents.z, 0, extents.y * 2.0); + + Vector3 cam_pos = p_transform.origin; + cam_pos.y += extents.y; + + Transform cam_xform; + cam_xform.set_look_at(cam_pos, cam_pos - p_transform.basis.get_axis(Vector3::AXIS_Y), -p_transform.basis.get_axis(Vector3::AXIS_Z).normalized()); + + RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider); + + _render_particle_collider_heightfield(fb, cam_xform, cm, p_cull_result, p_cull_count); +} + void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -7975,6 +8008,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { actions.renames["HALF_RES_COLOR"] = "half_res_color"; actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color"; actions.renames["RADIANCE"] = "radiance"; + actions.renames["FOG"] = "custom_fog"; actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled"; actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz"; actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w"; diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h index fe31d2f76b..2ad712a9d3 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h @@ -67,7 +67,8 @@ protected: uint32_t volumetric_fog_enabled; float volumetric_fog_inv_length; float volumetric_fog_detail_spread; - uint32_t volumetric_fog_pad; + + float fog_aerial_perspective; float fog_light_color[3]; float fog_sun_scatter; @@ -112,6 +113,7 @@ protected: virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) = 0; virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); @@ -705,6 +707,7 @@ private: float fog_density = 0.001; float fog_height = 0.0; float fog_height_density = 0.0; //can be negative to invert effect + float fog_aerial_perspective = 0.0; /// Volumetric Fog /// @@ -720,7 +723,7 @@ private: /// Glow bool glow_enabled = false; - int glow_levels = (1 << 2) | (1 << 4); + Vector<float> glow_levels; float glow_intensity = 0.8; float glow_strength = 1.0; float glow_bloom = 0.0; @@ -812,6 +815,7 @@ private: int width = 0, height = 0; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; + bool use_debanding = false; RID render_target; @@ -1529,11 +1533,11 @@ public: bool is_environment(RID p_env) const; - void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); + void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); void environment_glow_set_use_bicubic_upscale(bool p_enable); void environment_glow_set_use_high_quality(bool p_enable); - void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density); + void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective); bool environment_is_fog_enabled(RID p_env) const; Color environment_get_fog_light_color(RID p_env) const; float environment_get_fog_light_energy(RID p_env) const; @@ -1541,6 +1545,7 @@ public: float environment_get_fog_density(RID p_env) const; float environment_get_fog_height(RID p_env) const; float environment_get_fog_height_density(RID p_env) const; + float environment_get_fog_aerial_perspective(RID p_env) const; void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter); @@ -1841,7 +1846,7 @@ public: } */ RID render_buffers_create(); - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa); + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding); RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); @@ -1876,6 +1881,8 @@ public: void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count); void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count); + void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count); + virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; } diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index 9e3335b05b..e723028e56 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -1256,6 +1256,10 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { } material->shader_type = new_type; } + + for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) { + shader->data->set_default_texture_param(E->key(), E->get()); + } } if (shader->data) { @@ -1292,7 +1296,9 @@ void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const S } else { shader->default_texture_parameter.erase(p_name); } - + if (shader->data) { + shader->data->set_default_texture_param(p_name, p_texture); + } for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { Material *material = E->get(); _material_queue_update(material, false, true); @@ -3208,9 +3214,9 @@ Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const { Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); Vector<float> ret; - ret.resize(multimesh->instances); + ret.resize(multimesh->instances * multimesh->stride_cache); { - float *w = multimesh->data_cache.ptrw(); + float *w = ret.ptrw(); const uint8_t *r = buffer.ptr(); copymem(w, r, buffer.size()); } @@ -3333,6 +3339,10 @@ void RasterizerStorageRD::_particles_free_data(Particles *particles) { particles->particles_transforms_buffer_uniform_set = RID(); particles->particle_buffer = RID(); + if (RD::get_singleton()->uniform_set_is_valid(particles->collision_textures_uniform_set)) { + RD::get_singleton()->free(particles->collision_textures_uniform_set); + } + if (particles->particles_sort_buffer.is_valid()) { RD::get_singleton()->free(particles->particles_sort_buffer); particles->particles_sort_buffer = RID(); @@ -3454,6 +3464,13 @@ void RasterizerStorageRD::particles_set_fractional_delta(RID p_particles, bool p particles->fractional_delta = p_enable; } +void RasterizerStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->collision_base_size = p_size; +} + void RasterizerStorageRD::particles_set_process_material(RID p_particles, RID p_material) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -3646,6 +3663,22 @@ RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pas return particles->draw_passes[p_pass]; } +void RasterizerStorageRD::particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_PARTICLES_COLLISION); + + particles->collisions.insert(p_instance); +} + +void RasterizerStorageRD::particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->collisions.erase(p_instance); +} + void RasterizerStorageRD::_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; @@ -3729,6 +3762,195 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del frame_params.cycle = p_particles->cycle_number; + { //collision and attractors + + frame_params.collider_count = 0; + frame_params.attractor_count = 0; + frame_params.particle_size = p_particles->collision_base_size; + + RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES]; + RID collision_heightmap_texture; + + Transform to_particles; + if (p_particles->use_local_coords) { + to_particles = p_particles->emission_transform.affine_inverse(); + } + uint32_t collision_3d_textures_used = 0; + for (const Set<RasterizerScene::InstanceBase *>::Element *E = p_particles->collisions.front(); E; E = E->next()) { + ParticlesCollision *pc = particles_collision_owner.getornull(E->get()->base); + Transform to_collider = E->get()->transform; + if (p_particles->use_local_coords) { + to_collider = to_particles * to_collider; + } + Vector3 scale = to_collider.basis.get_scale(); + to_collider.basis.orthonormalize(); + + if (pc->type <= RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) { + //attractor + if (frame_params.attractor_count >= ParticlesFrameParams::MAX_ATTRACTORS) { + continue; + } + + ParticlesFrameParams::Attractor &attr = frame_params.attractors[frame_params.attractor_count]; + + store_transform(to_collider, attr.transform); + attr.strength = pc->attractor_strength; + attr.attenuation = pc->attractor_attenuation; + attr.directionality = pc->attractor_directionality; + + switch (pc->type) { + case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT: { + attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_SPHERE; + float radius = pc->radius; + radius *= (scale.x + scale.y + scale.z) / 3.0; + attr.extents[0] = radius; + attr.extents[1] = radius; + attr.extents[2] = radius; + } break; + case RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT: { + attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_BOX; + Vector3 extents = pc->extents * scale; + attr.extents[0] = extents.x; + attr.extents[1] = extents.y; + attr.extents[2] = extents.z; + } break; + case RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT: { + if (collision_3d_textures_used >= ParticlesFrameParams::MAX_3D_TEXTURES) { + continue; + } + attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_VECTOR_FIELD; + Vector3 extents = pc->extents * scale; + attr.extents[0] = extents.x; + attr.extents[1] = extents.y; + attr.extents[2] = extents.z; + attr.texture_index = collision_3d_textures_used; + + collision_3d_textures[collision_3d_textures_used] = pc->field_texture; + collision_3d_textures_used++; + } break; + default: { + } + } + + frame_params.attractor_count++; + } else { + //collider + if (frame_params.collider_count >= ParticlesFrameParams::MAX_COLLIDERS) { + continue; + } + + ParticlesFrameParams::Collider &col = frame_params.colliders[frame_params.collider_count]; + + store_transform(to_collider, col.transform); + switch (pc->type) { + case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: { + col.type = ParticlesFrameParams::COLLISION_TYPE_SPHERE; + float radius = pc->radius; + radius *= (scale.x + scale.y + scale.z) / 3.0; + col.extents[0] = radius; + col.extents[1] = radius; + col.extents[2] = radius; + } break; + case RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE: { + col.type = ParticlesFrameParams::COLLISION_TYPE_BOX; + Vector3 extents = pc->extents * scale; + col.extents[0] = extents.x; + col.extents[1] = extents.y; + col.extents[2] = extents.z; + } break; + case RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE: { + if (collision_3d_textures_used >= ParticlesFrameParams::MAX_3D_TEXTURES) { + continue; + } + col.type = ParticlesFrameParams::COLLISION_TYPE_SDF; + Vector3 extents = pc->extents * scale; + col.extents[0] = extents.x; + col.extents[1] = extents.y; + col.extents[2] = extents.z; + col.texture_index = collision_3d_textures_used; + col.scale = (scale.x + scale.y + scale.z) * 0.333333333333; //non uniform scale non supported + + collision_3d_textures[collision_3d_textures_used] = pc->field_texture; + collision_3d_textures_used++; + } break; + case RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE: { + if (collision_heightmap_texture != RID()) { //already taken + continue; + } + + col.type = ParticlesFrameParams::COLLISION_TYPE_HEIGHT_FIELD; + Vector3 extents = pc->extents * scale; + col.extents[0] = extents.x; + col.extents[1] = extents.y; + col.extents[2] = extents.z; + collision_heightmap_texture = pc->heightfield_texture; + } break; + default: { + } + } + + frame_params.collider_count++; + } + } + + bool different = false; + if (collision_3d_textures_used == p_particles->collision_3d_textures_used) { + for (int i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { + if (p_particles->collision_3d_textures[i] != collision_3d_textures[i]) { + different = true; + break; + } + } + } + + if (collision_heightmap_texture != p_particles->collision_heightmap_texture) { + different = true; + } + + bool uniform_set_valid = RD::get_singleton()->uniform_set_is_valid(p_particles->collision_textures_uniform_set); + + if (different || !uniform_set_valid) { + if (uniform_set_valid) { + RD::get_singleton()->free(p_particles->collision_textures_uniform_set); + } + + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { + RID rd_tex; + if (i < collision_3d_textures_used) { + Texture *t = texture_owner.getornull(collision_3d_textures[i]); + if (t && t->type == Texture::TYPE_3D) { + rd_tex = t->rd_texture; + } + } + + if (rd_tex == RID()) { + rd_tex = default_rd_textures[DEFAULT_RD_TEXTURE_3D_WHITE]; + } + u.ids.push_back(rd_tex); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1; + if (collision_heightmap_texture.is_valid()) { + u.ids.push_back(collision_heightmap_texture); + } else { + u.ids.push_back(default_rd_textures[DEFAULT_RD_TEXTURE_BLACK]); + } + uniforms.push_back(u); + } + p_particles->collision_textures_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 2); + } + } + ParticlesShader::PushConstant push_constant; push_constant.clear = p_particles->clear; @@ -3783,8 +4005,10 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles_shader.base_uniform_set, 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->collision_textures_uniform_set, 2); + if (m->uniform_set.is_valid()) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 2); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 3); } RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant)); @@ -4190,7 +4414,7 @@ void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<Str } } - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 2); + uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); } RasterizerStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { @@ -4211,6 +4435,171 @@ RasterizerStorageRD::MaterialData *RasterizerStorageRD::_create_particles_materi return material_data; } //////// + +/* PARTICLES COLLISION API */ + +RID RasterizerStorageRD::particles_collision_create() { + return particles_collision_owner.make_rid(ParticlesCollision()); +} + +RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND_V(!particles_collision, RID()); + ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, RID()); + + if (particles_collision->heightfield_texture == RID()) { + //create + int resolutions[RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX] = { 256, 512, 1024, 2048, 4096, 8192 }; + Size2i size; + if (particles_collision->extents.x > particles_collision->extents.z) { + size.x = resolutions[particles_collision->heightfield_resolution]; + size.y = int32_t(particles_collision->extents.z / particles_collision->extents.x * size.x); + } else { + size.y = resolutions[particles_collision->heightfield_resolution]; + size.x = int32_t(particles_collision->extents.x / particles_collision->extents.z * size.y); + } + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_D32_SFLOAT; + tf.width = size.x; + tf.height = size.y; + tf.type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + particles_collision->heightfield_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector<RID> fb_tex; + fb_tex.push_back(particles_collision->heightfield_texture); + particles_collision->heightfield_fb = RD::get_singleton()->framebuffer_create(fb_tex); + particles_collision->heightfield_fb_size = size; + } + + return particles_collision->heightfield_fb; +} + +void RasterizerStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + if (p_type == particles_collision->type) { + return; + } + + if (particles_collision->heightfield_texture.is_valid()) { + RD::get_singleton()->free(particles_collision->heightfield_texture); + particles_collision->heightfield_texture = RID(); + } + particles_collision->type = p_type; + particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + particles_collision->cull_mask = p_cull_mask; +} + +void RasterizerStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + particles_collision->radius = p_radius; + particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + particles_collision->extents = p_extents; + particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + particles_collision->attractor_strength = p_strength; +} + +void RasterizerStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + particles_collision->attractor_directionality = p_directionality; +} + +void RasterizerStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + particles_collision->attractor_attenuation = p_curve; +} + +void RasterizerStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + particles_collision->field_texture = p_texture; +} + +void RasterizerStorageRD::particles_collision_height_field_update(RID p_particles_collision) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + particles_collision->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND(!particles_collision); + + if (particles_collision->heightfield_resolution == p_resolution) { + return; + } + + particles_collision->heightfield_resolution = p_resolution; + + if (particles_collision->heightfield_texture.is_valid()) { + RD::get_singleton()->free(particles_collision->heightfield_texture); + particles_collision->heightfield_texture = RID(); + } +} + +AABB RasterizerStorageRD::particles_collision_get_aabb(RID p_particles_collision) const { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND_V(!particles_collision, AABB()); + + switch (particles_collision->type) { + case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT: + case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: { + AABB aabb; + aabb.position = -Vector3(1, 1, 1) * particles_collision->radius; + aabb.size = Vector3(2, 2, 2) * particles_collision->radius; + return aabb; + } + default: { + AABB aabb; + aabb.position = -particles_collision->extents; + aabb.size = particles_collision->extents * 2; + return aabb; + } + } + + return AABB(); +} + +Vector3 RasterizerStorageRD::particles_collision_get_extents(RID p_particles_collision) const { + const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND_V(!particles_collision, Vector3()); + return particles_collision->extents; +} + +bool RasterizerStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const { + const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ERR_FAIL_COND_V(!particles_collision, false); + return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE; +} + /* SKELETON API */ RID RasterizerStorageRD::skeleton_create() { @@ -4680,6 +5069,9 @@ void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); + if (reflection_probe->extents == p_extents) { + return; + } reflection_probe->extents = p_extents; reflection_probe->instance_dependency.instance_notify_changed(true, false); } @@ -5797,6 +6189,9 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In } else if (particles_owner.owns(p_base)) { Particles *p = particles_owner.getornull(p_base); p_instance->update_dependency(&p->instance_dependency); + } else if (particles_collision_owner.owns(p_base)) { + ParticlesCollision *pc = particles_collision_owner.getornull(p_base); + p_instance->update_dependency(&pc->instance_dependency); } } @@ -5832,6 +6227,9 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { if (particles_owner.owns(p_rid)) { return RS::INSTANCE_PARTICLES; } + if (particles_collision_owner.owns(p_rid)) { + return RS::INSTANCE_PARTICLES_COLLISION; + } return RS::INSTANCE_NONE; } @@ -5871,7 +6269,7 @@ RID RasterizerStorageRD::decal_atlas_get_texture() const { } RID RasterizerStorageRD::decal_atlas_get_texture_srgb() const { - return decal_atlas.texture; + return decal_atlas.texture_srgb; } void RasterizerStorageRD::_update_decal_atlas() { @@ -6735,8 +7133,6 @@ void RasterizerStorageRD::update_dirty_resources() { _update_dirty_multimeshes(); _update_dirty_skeletons(); _update_decal_atlas(); - - update_particles(); } bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { @@ -6871,6 +7267,14 @@ bool RasterizerStorageRD::free(RID p_rid) { _particles_free_data(particles); particles->instance_dependency.instance_notify_deleted(p_rid); particles_owner.free(p_rid); + } else if (particles_collision_owner.owns(p_rid)) { + ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid); + + if (particles_collision->heightfield_texture.is_valid()) { + RD::get_singleton()->free(particles_collision->heightfield_texture); + } + particles_collision->instance_dependency.instance_notify_deleted(p_rid); + particles_collision_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { RenderTarget *rt = render_target_owner.getornull(p_rid); @@ -7379,14 +7783,19 @@ RasterizerStorageRD::RasterizerStorageRD() { actions.renames["RESTART_COLOR"] = "restart_color"; actions.renames["RESTART_CUSTOM"] = "restart_custom"; actions.renames["emit_particle"] = "emit_particle"; + actions.renames["COLLIDED"] = "collided"; + actions.renames["COLLISION_NORMAL"] = "collision_normal"; + actions.renames["COLLISION_DEPTH"] = "collision_depth"; + actions.renames["ATTRACTOR_FORCE"] = "attractor_force"; actions.render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; actions.render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; + actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISON_SCALE\n"; actions.sampler_array_name = "material_samplers"; actions.base_texture_binding_index = 1; - actions.texture_layout_set = 2; + actions.texture_layout_set = 3; actions.base_uniform_string = "material."; actions.base_varying_index = 10; @@ -7481,7 +7890,12 @@ RasterizerStorageRD::~RasterizerStorageRD() { for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) { RD::get_singleton()->free(mesh_default_rd_buffers[i]); } + giprobe_sdf_shader.version_free(giprobe_sdf_shader_version); + particles_shader.copy_shader.version_free(particles_shader.copy_shader_version); + + RenderingServer::get_singleton()->free(particles_shader.default_material); + RenderingServer::get_singleton()->free(particles_shader.default_shader); RD::get_singleton()->free(default_rd_storage_buffer); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index e14b9528cf..b03a26e200 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -475,6 +475,46 @@ private: }; struct ParticlesFrameParams { + enum { + MAX_ATTRACTORS = 32, + MAX_COLLIDERS = 32, + MAX_3D_TEXTURES = 7 + }; + + enum AttractorType { + ATTRACTOR_TYPE_SPHERE, + ATTRACTOR_TYPE_BOX, + ATTRACTOR_TYPE_VECTOR_FIELD, + }; + + struct Attractor { + float transform[16]; + float extents[3]; //exents or radius + uint32_t type; + + uint32_t texture_index; //texture index for vector field + float strength; + float attenuation; + float directionality; + }; + + enum CollisionType { + COLLISION_TYPE_SPHERE, + COLLISION_TYPE_BOX, + COLLISION_TYPE_SDF, + COLLISION_TYPE_HEIGHT_FIELD + }; + + struct Collider { + float transform[16]; + float extents[3]; //exents or radius + uint32_t type; + + uint32_t texture_index; //texture index for vector field + float scale; + uint32_t pad[2]; + }; + uint32_t emitting; float system_phase; float prev_system_phase; @@ -486,9 +526,14 @@ private: float delta; uint32_t random_seed; - uint32_t pad[3]; + uint32_t attractor_count; + uint32_t collider_count; + float particle_size; float emission_transform[16]; + + Attractor attractors[MAX_ATTRACTORS]; + Collider colliders[MAX_COLLIDERS]; }; struct ParticleEmissionBufferData { @@ -536,6 +581,11 @@ private: RID particles_material_uniform_set; RID particles_copy_uniform_set; RID particles_transforms_buffer_uniform_set; + RID collision_textures_uniform_set; + + RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES]; + uint32_t collision_3d_textures_used = 0; + RID collision_heightmap_texture; RID particles_sort_buffer; RID particles_sort_uniform_set; @@ -557,6 +607,7 @@ private: int fixed_fps; bool fractional_delta; float frame_remainder; + float collision_base_size; bool clear; @@ -569,6 +620,8 @@ private: ParticleEmissionBuffer *emission_buffer = nullptr; RID emission_storage_buffer; + Set<RasterizerScene::InstanceBase *> collisions; + Particles() : inactive(true), inactive_time(0.0), @@ -590,6 +643,7 @@ private: fixed_fps(0), fractional_delta(false), frame_remainder(0), + collision_base_size(0.01), clear(true) { } @@ -704,6 +758,28 @@ private: mutable RID_Owner<Particles> particles_owner; + /* Particles Collision */ + + struct ParticlesCollision { + RS::ParticlesCollisionType type = RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT; + uint32_t cull_mask = 0xFFFFFFFF; + float radius = 1.0; + Vector3 extents = Vector3(1, 1, 1); + float attractor_strength = 1.0; + float attractor_attenuation = 1.0; + float attractor_directionality = 0.0; + RID field_texture; + RID heightfield_texture; + RID heightfield_fb; + Size2i heightfield_fb_size; + + RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024; + + RasterizerScene::InstanceDependency instance_dependency; + }; + + mutable RID_Owner<ParticlesCollision> particles_collision_owner; + /* Skeleton */ struct Skeleton { @@ -1691,6 +1767,7 @@ public: void particles_set_process_material(RID p_particles, RID p_material); void particles_set_fixed_fps(RID p_particles, int p_fps); void particles_set_fractional_delta(RID p_particles, bool p_enable); + void particles_set_collision_base_size(RID p_particles, float p_size); void particles_restart(RID p_particles); void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); void particles_set_subemitter(RID p_particles, RID p_subemitter_particles); @@ -1748,6 +1825,27 @@ public: return particles->particles_transforms_buffer_uniform_set; } + virtual void particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); + virtual void particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); + + /* PARTICLES COLLISION */ + + virtual RID particles_collision_create(); + virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type); + virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask); + virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius); //for spheres + virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents); //for non-spheres + virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength); + virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality); + virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve); + virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture); //for SDF and vector field, heightfield is dynamic + virtual void particles_collision_height_field_update(RID p_particles_collision); //for SDF and vector field + virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution); //for SDF and vector field + virtual AABB particles_collision_get_aabb(RID p_particles_collision) const; + virtual Vector3 particles_collision_get_extents(RID p_particles_collision) const; + virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; + RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; + /* GLOBAL VARIABLES API */ virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value); diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl index e33b3face9..4a40584e16 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl @@ -101,7 +101,7 @@ void main() { offset += 1; } else { instance_color = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3)); - offser += 4; + offset += 4; } color *= instance_color; diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index e565bd8e3d..355a2b9d75 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -58,12 +58,20 @@ layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buff layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; #endif +#ifdef MODE_GAUSSIAN_GLOW +shared vec4 local_cache[256]; +shared vec4 temp_cache[128]; +#endif + void main() { // Pixel being shaded ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + +#ifndef MODE_GAUSSIAN_GLOW // Glow needs the extra threads if (any(greaterThanEqual(pos, params.section.zw))) { //too large, do nothing return; } +#endif #ifdef MODE_MIPMAP @@ -104,70 +112,69 @@ void main() { #ifdef MODE_GAUSSIAN_GLOW - //Glow uses larger sigma 1 for a more rounded blur effect + // First pass copy texture into 16x16 local memory for every 8x8 thread block + vec2 quad_center_uv = clamp(vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.5) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); + uint dest_index = gl_LocalInvocationID.x * 2 + gl_LocalInvocationID.y * 2 * 16; + + if (bool(params.flags & FLAG_HIGH_QUALITY_GLOW)) { + vec2 quad_offset_uv = clamp((vec2(gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.0)) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); -#define GLOW_ADD(m_ofs, m_mult) \ - { \ - ivec2 ofs = base_pos + m_ofs; \ - if (all(greaterThanEqual(ofs, section_begin)) && all(lessThan(ofs, section_end))) { \ - color += texelFetch(source_color, ofs, 0) * m_mult; \ - } \ + local_cache[dest_index] = (textureLod(source_color, quad_center_uv, 0) + textureLod(source_color, quad_offset_uv, 0)) * 0.5; + local_cache[dest_index + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.z, 0.0), 0)) * 0.5; + local_cache[dest_index + 16] = (textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0) + textureLod(source_color, quad_offset_uv + vec2(0.0, 1.0 / params.section.w), 0)) * 0.5; + local_cache[dest_index + 16 + 1] = (textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0) + textureLod(source_color, quad_offset_uv + vec2(1.0 / params.section.zw), 0)) * 0.5; + } else { + local_cache[dest_index] = textureLod(source_color, quad_center_uv, 0); + local_cache[dest_index + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0); + local_cache[dest_index + 16] = textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); + local_cache[dest_index + 16 + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0); } + memoryBarrierShared(); + barrier(); + + // Horizontal pass. Needs to copy into 8x16 chunk of local memory so vertical pass has full resolution + uint read_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 32 + 4; + vec4 color_top = vec4(0.0); + color_top += local_cache[read_index] * 0.174938; + color_top += local_cache[read_index + 1] * 0.165569; + color_top += local_cache[read_index + 2] * 0.140367; + color_top += local_cache[read_index + 3] * 0.106595; + color_top += local_cache[read_index - 1] * 0.165569; + color_top += local_cache[read_index - 2] * 0.140367; + color_top += local_cache[read_index - 3] * 0.106595; + + vec4 color_bottom = vec4(0.0); + color_bottom += local_cache[read_index + 16] * 0.174938; + color_bottom += local_cache[read_index + 1 + 16] * 0.165569; + color_bottom += local_cache[read_index + 2 + 16] * 0.140367; + color_bottom += local_cache[read_index + 3 + 16] * 0.106595; + color_bottom += local_cache[read_index - 1 + 16] * 0.165569; + color_bottom += local_cache[read_index - 2 + 16] * 0.140367; + color_bottom += local_cache[read_index - 3 + 16] * 0.106595; + + // rotate samples to take advantage of cache coherency + uint write_index = gl_LocalInvocationID.y * 2 + gl_LocalInvocationID.x * 16; + + temp_cache[write_index] = color_top; + temp_cache[write_index + 1] = color_bottom; + + memoryBarrierShared(); + barrier(); + + // Vertical pass + uint index = gl_LocalInvocationID.y + gl_LocalInvocationID.x * 16 + 4; vec4 color = vec4(0.0); - if (bool(params.flags & FLAG_HORIZONTAL)) { - ivec2 base_pos = ((pos + params.section.xy) << 1) + ivec2(1); - ivec2 section_begin = params.section.xy << 1; - ivec2 section_end = section_begin + (params.section.zw << 1); - - if (bool(params.flags & FLAG_HIGH_QUALITY_GLOW)) { - //Sample from two lines to capture single pixel features - GLOW_ADD(ivec2(0, 0), 0.152781); - GLOW_ADD(ivec2(1, 0), 0.144599); - GLOW_ADD(ivec2(2, 0), 0.122589); - GLOW_ADD(ivec2(3, 0), 0.093095); - GLOW_ADD(ivec2(4, 0), 0.063327); - GLOW_ADD(ivec2(-1, 0), 0.144599); - GLOW_ADD(ivec2(-2, 0), 0.122589); - GLOW_ADD(ivec2(-3, 0), 0.093095); - GLOW_ADD(ivec2(-4, 0), 0.063327); - - GLOW_ADD(ivec2(0, 1), 0.152781); - GLOW_ADD(ivec2(1, 1), 0.144599); - GLOW_ADD(ivec2(2, 1), 0.122589); - GLOW_ADD(ivec2(3, 1), 0.093095); - GLOW_ADD(ivec2(4, 1), 0.063327); - GLOW_ADD(ivec2(-1, 1), 0.144599); - GLOW_ADD(ivec2(-2, 1), 0.122589); - GLOW_ADD(ivec2(-3, 1), 0.093095); - GLOW_ADD(ivec2(-4, 1), 0.063327); - color *= 0.5; - } else { - GLOW_ADD(ivec2(0, 0), 0.174938); - GLOW_ADD(ivec2(1, 0), 0.165569); - GLOW_ADD(ivec2(2, 0), 0.140367); - GLOW_ADD(ivec2(3, 0), 0.106595); - GLOW_ADD(ivec2(-1, 0), 0.165569); - GLOW_ADD(ivec2(-2, 0), 0.140367); - GLOW_ADD(ivec2(-3, 0), 0.106595); - } - - color *= params.glow_strength; - } else { - ivec2 base_pos = pos + params.section.xy; - ivec2 section_begin = params.section.xy; - ivec2 section_end = section_begin + params.section.zw; - - GLOW_ADD(ivec2(0, 0), 0.288713); - GLOW_ADD(ivec2(0, 1), 0.233062); - GLOW_ADD(ivec2(0, 2), 0.122581); - GLOW_ADD(ivec2(0, -1), 0.233062); - GLOW_ADD(ivec2(0, -2), 0.122581); - color *= params.glow_strength; - } + color += temp_cache[index] * 0.174938; + color += temp_cache[index + 1] * 0.165569; + color += temp_cache[index + 2] * 0.140367; + color += temp_cache[index + 3] * 0.106595; + color += temp_cache[index - 1] * 0.165569; + color += temp_cache[index - 2] * 0.140367; + color += temp_cache[index - 3] * 0.106595; -#undef GLOW_ADD + color *= params.glow_strength; if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { #ifdef GLOW_USE_AUTO_EXPOSURE diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/rasterizer_rd/shaders/particles.glsl index 3de807b57c..926c7ef9fc 100644 --- a/servers/rendering/rasterizer_rd/shaders/particles.glsl +++ b/servers/rendering/rasterizer_rd/shaders/particles.glsl @@ -31,6 +31,40 @@ global_variables; /* Set 1: FRAME AND PARTICLE DATA */ // a frame history is kept for trail deterministic behavior + +#define MAX_ATTRACTORS 32 + +#define ATTRACTOR_TYPE_SPHERE 0 +#define ATTRACTOR_TYPE_BOX 1 +#define ATTRACTOR_TYPE_VECTOR_FIELD 2 + +struct Attractor { + mat4 transform; + vec3 extents; //exents or radius + uint type; + uint texture_index; //texture index for vector field + float strength; + float attenuation; + float directionality; +}; + +#define MAX_COLLIDERS 32 + +#define COLLIDER_TYPE_SPHERE 0 +#define COLLIDER_TYPE_BOX 1 +#define COLLIDER_TYPE_SDF 2 +#define COLLIDER_TYPE_HEIGHT_FIELD 3 + +struct Collider { + mat4 transform; + vec3 extents; //exents or radius + uint type; + + uint texture_index; //texture index for vector field + float scale; + uint pad[2]; +}; + struct FrameParams { bool emitting; float system_phase; @@ -43,9 +77,14 @@ struct FrameParams { float delta; uint random_seed; - uint pad[3]; + uint attractor_count; + uint collider_count; + float particle_size; mat4 emission_transform; + + Attractor attractors[MAX_ATTRACTORS]; + Collider colliders[MAX_COLLIDERS]; }; layout(set = 1, binding = 0, std430) restrict buffer FrameHistory { @@ -80,7 +119,7 @@ struct ParticleEmission { vec4 custom; }; -layout(set = 1, binding = 2, std430) restrict volatile coherent buffer SourceEmission { +layout(set = 1, binding = 2, std430) restrict buffer SourceEmission { int particle_count; uint pad0; uint pad1; @@ -89,7 +128,7 @@ layout(set = 1, binding = 2, std430) restrict volatile coherent buffer SourceEmi } src_particles; -layout(set = 1, binding = 3, std430) restrict volatile coherent buffer DestEmission { +layout(set = 1, binding = 3, std430) restrict buffer DestEmission { int particle_count; int particle_max; uint pad1; @@ -98,10 +137,17 @@ layout(set = 1, binding = 3, std430) restrict volatile coherent buffer DestEmiss } dst_particles; -/* SET 2: MATERIAL */ +/* SET 2: COLLIDER/ATTRACTOR TEXTURES */ + +#define MAX_3D_TEXTURES 7 + +layout(set = 2, binding = 0) uniform texture3D sdf_vec_textures[MAX_3D_TEXTURES]; +layout(set = 2, binding = 1) uniform texture2D height_field_texture; + +/* SET 3: MATERIAL */ #ifdef USE_MATERIAL_UNIFORMS -layout(set = 2, binding = 0, std140) uniform MaterialUniforms{ +layout(set = 3, binding = 0, std140) uniform MaterialUniforms{ /* clang-format off */ MATERIAL_UNIFORMS /* clang-format on */ @@ -140,29 +186,7 @@ bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, u atomicAdd(dst_particles.particle_count, -1); return false; } - /* - valid = true; - - int attempts = 256; // never trust compute - while(attempts-- > 0) { - dst_index = dst_particles.particle_count; - if (dst_index == dst_particles.particle_max) { - return false; //cant emit anymore - } - - if (atomicCompSwap(dst_particles.particle_count, dst_index, dst_index +1 ) != dst_index) { - continue; - } - valid=true; - break; - } - barrier(); - - if (!valid) { - return false; //gave up (attempts exhausted) - } -*/ dst_particles.data[dst_index].xform = p_xform; dst_particles.data[dst_index].velocity = p_velocity; dst_particles.data[dst_index].color = p_color; @@ -217,6 +241,199 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0)); } + bool collided = false; + vec3 collision_normal = vec3(0.0); + float collision_depth = 0.0; + + vec3 attractor_force = vec3(0.0); + +#if !defined(DISABLE_VELOCITY) + + if (PARTICLE.is_active) { + PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta; + } +#endif + + /* Process physics if active */ + + if (PARTICLE.is_active) { + for (uint i = 0; i < FRAME.attractor_count; i++) { + vec3 dir; + float amount; + vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.attractors[i].transform[3].xyz; + vec3 local_pos = rel_vec * mat3(FRAME.attractors[i].transform); + + switch (FRAME.attractors[i].type) { + case ATTRACTOR_TYPE_SPHERE: { + dir = normalize(rel_vec); + float d = length(local_pos) / FRAME.attractors[i].extents.x; + if (d > 1.0) { + continue; + } + amount = max(0.0, 1.0 - d); + } break; + case ATTRACTOR_TYPE_BOX: { + dir = normalize(rel_vec); + + vec3 abs_pos = abs(local_pos / FRAME.attractors[i].extents); + float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z)); + if (d > 1.0) { + continue; + } + amount = max(0.0, 1.0 - d); + + } break; + case ATTRACTOR_TYPE_VECTOR_FIELD: { + vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents) * 2.0 - 1.0; + if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) { + continue; + } + vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz; + dir = mat3(FRAME.attractors[i].transform) * normalize(s); //revert direction + amount = length(s); + + } break; + } + amount = pow(amount, FRAME.attractors[i].attenuation); + dir = normalize(mix(dir, FRAME.attractors[i].transform[2].xyz, FRAME.attractors[i].directionality)); + attractor_force -= amount * dir * FRAME.attractors[i].strength; + } + + float particle_size = FRAME.particle_size; + +#ifdef USE_COLLISON_SCALE + + particle_size *= dot(vec3(length(PARTICLE.xform[0].xyz), length(PARTICLE.xform[1].xyz), length(PARTICLE.xform[2].xyz)), vec3(0.33333333333)); + +#endif + + for (uint i = 0; i < FRAME.collider_count; i++) { + vec3 normal; + float depth; + bool col = false; + + vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz; + vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform); + + 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; + depth = -d; + normal = normalize(rel_vec); + } + + } 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 { + //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); + } + + } 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; + } + + 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; + + if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) { + continue; + } + + const float DELTA = 1.0 / 8192.0; + + vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5; + + float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r; + + if (y > uvw_pos.y) { + //inside heightfield + + 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; + + normal = normalize(cross(pos1 - pos2, pos1 - pos3)); + float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y; + + col = true; + depth = dot(normal, pos1) - dot(normal, local_pos_bottom); + } + + } 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); + } + } + } + } + if (params.sub_emitter_mode) { if (!PARTICLE.is_active) { int src_index = atomicAdd(src_particles.particle_count, -1) - 1; @@ -329,66 +546,4 @@ COMPUTE_SHADER_CODE /* clang-format on */ } - -#if !defined(DISABLE_VELOCITY) - - if (PARTICLE.is_active) { - PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta; - } -#endif - -#if 0 - if (PARTICLE.is_active) { - //execute shader - - - - - //!defined(DISABLE_FORCE) - - if (false) { - vec3 force = vec3(0.0); - for (int i = 0; i < attractor_count; i++) { - vec3 rel_vec = xform[3].xyz - attractors[i].pos; - float dist = length(rel_vec); - if (attractors[i].radius < dist) - continue; - if (attractors[i].eat_radius > 0.0 && attractors[i].eat_radius > dist) { - out_velocity_active.a = 0.0; - } - - rel_vec = normalize(rel_vec); - - float attenuation = pow(dist / attractors[i].radius, attractors[i].attenuation); - - if (attractors[i].dir == vec3(0.0)) { - //towards center - force += attractors[i].strength * rel_vec * attenuation * mass; - } else { - force += attractors[i].strength * attractors[i].dir * attenuation * mass; - } - } - - out_velocity_active.xyz += force * local_delta; - } - -#if !defined(DISABLE_VELOCITY) - - if (true) { - xform[3].xyz += out_velocity_active.xyz * local_delta; - } -#endif - } else { - xform = mat4(0.0); - } - - - xform = transpose(xform); - - out_velocity_active.a = mix(0.0, 1.0, shader_active); - - out_xform_1 = xform[0]; - out_xform_2 = xform[1]; - out_xform_3 = xform[2]; -#endif } diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 2a7b73d9aa..455a3d4a3a 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -681,7 +681,7 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS -// Produces cheap white noise, optmized for window-space +// Produces cheap white noise, optimized for window-space // Comes from: https://www.shadertoy.com/view/4djSRW // Copyright: Dave Hoskins, MIT License float quick_hash(vec2 pos) { @@ -1621,6 +1621,22 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) { vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data.fog_light_color; + if (scene_data.fog_aerial_perspective > 0.0) { + vec3 sky_fog_color = vec3(0.0); + vec3 cube_view = scene_data.radiance_inverse_xform * vertex; + // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred + float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)); +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + float lod, blend; + blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); + sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb; + sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend); +#else + sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective); + } + if (scene_data.fog_sun_scatter > 0.001) { vec4 sun_scatter = vec4(0.0); float sun_total = 0.0; @@ -1676,6 +1692,15 @@ void main() { float clearcoat_gloss = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); +#if defined(CUSTOM_FOG_USED) + vec4 custom_fog = vec4(0.0); +#endif +#if defined(CUSTOM_RADIANCE_USED) + vec4 custom_radiance = vec4(0.0); +#endif +#if defined(CUSTOM_IRRADIANCE_USED) + vec4 custom_irradiance = vec4(0.0); +#endif #if defined(AO_USED) float ao = 1.0; @@ -1893,6 +1918,10 @@ FRAGMENT_SHADER_CODE specular_light *= scene_data.ambient_light_color_energy.a; } +#if defined(CUSTOM_RADIANCE_USED) + specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); +#endif + #ifndef USE_LIGHTMAP //lightmap overrides everything if (scene_data.use_ambient_light) { @@ -1910,7 +1939,9 @@ FRAGMENT_SHADER_CODE } } #endif // USE_LIGHTMAP - +#if defined(CUSTOM_IRRADIANCE_USED) + ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); +#endif #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) //radiance @@ -2726,18 +2757,24 @@ FRAGMENT_SHADER_CODE specular_buffer = vec4(specular_light, metallic); #endif - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + if (scene_data.fog_enabled) { + vec4 fog = fog_process(vertex); diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); } - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); + if (scene_data.volumetric_fog_enabled) { + vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); } +#if defined(CUSTOM_FOG_USED) + diffuse_buffer.rgb = mix(diffuse_buffer.rgb, custom_fog.rgb, custom_fog.a); + specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), custom_fog.a); +#endif //CUSTOM_FOG_USED + #else //MODE_MULTIPLE_RENDER_TARGETS #ifdef MODE_UNSHADED @@ -2747,16 +2784,21 @@ FRAGMENT_SHADER_CODE //frag_color = vec4(1.0); #endif //USE_NO_SHADING - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + if (scene_data.fog_enabled) { + vec4 fog = fog_process(vertex); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); + if (scene_data.volumetric_fog_enabled) { + vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } +#if defined(CUSTOM_FOG_USED) + frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); +#endif //CUSTOM_FOG_USED + #endif //MODE_MULTIPLE_RENDER_TARGETS #endif //MODE_RENDER_DEPTH diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl index 66bfefbe89..e29a490ca1 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl @@ -43,12 +43,6 @@ layout(set = 0, binding = 3, std140) uniform SceneData { vec2 viewport_size; vec2 screen_pixel_size; - float time; - float reflection_multiplier; // one normally, zero when rendering reflections - - bool pancake_shadows; - uint pad; - //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted vec4 directional_penumbra_shadow_kernel[32]; vec4 directional_soft_shadow_kernel[32]; @@ -108,6 +102,13 @@ layout(set = 0, binding = 3, std140) uniform SceneData { vec3 fog_light_color; float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; // one normally, zero when rendering reflections + + bool pancake_shadows; } scene_data; @@ -252,7 +253,7 @@ layout(set = 1, binding = 0) uniform textureCube radiance_cubemap; #endif -/* Set 2, Reflection and Shadow Atlases (view dependant) */ +/* Set 2, Reflection and Shadow Atlases (view dependent) */ layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas; diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl index a8ee33a664..06dc4b13de 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl @@ -155,18 +155,14 @@ void main() { depth = imageLoad(source_depth, ivec2(pos - 0.5)).r; - if (-depth >= params.camera_z_far) { //went beyond camera - break; - } - z_from = z_to; z_to = z / w; if (depth > z_to) { // if depth was surpassed - if (depth <= max(z_to, z_from) + params.depth_tolerance) { - // check the depth tolerance - //check that normal is valid + if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far) { + // check the depth tolerance and far clip + // check that normal is valid found = true; } break; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl index c4b29216d5..61e4bf5e18 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl @@ -22,7 +22,7 @@ dispatch_data; struct ProcessVoxel { uint position; //xyz 7 bit packed, extra 11 bits for neigbours uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours //total neighbours: 26 }; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl index 1ec471d204..d516ab22c3 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl @@ -336,7 +336,7 @@ void main() { #ifdef MODE_STORE - // converting to octahedral in this step is requiered because + // converting to octahedral in this step is required because // octahedral is much faster to read from the screen than spherical harmonics, // despite the very slight quality loss @@ -512,7 +512,7 @@ void main() { imageStore(lightprobe_average_scroll_texture, dst_pos, value); } } else if (params.cascade < params.max_cascades - 1) { - //cant scroll, must look for position in parent cascade + //can't scroll, must look for position in parent cascade //to global coords float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl index dd0ca5c506..916c60ac89 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl @@ -103,7 +103,7 @@ dispatch_data; struct ProcessVoxel { uint position; //xyz 7 bit packed, extra 11 bits for neigbours uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours //total neighbours: 26 }; @@ -136,7 +136,7 @@ dispatch_data; struct ProcessVoxel { uint position; //xyz 7 bit packed, extra 11 bits for neigbours uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours - uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbous + uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours //total neighbours: 26 }; @@ -274,7 +274,7 @@ void main() { #ifdef MODE_JUMPFLOOD - //regular jumpflood, efficent for large steps, inefficient for small steps + //regular jumpflood, efficient for large steps, inefficient for small steps ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); vec3 posf = vec3(pos); diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl index 7b6de6a555..6c985e1f5c 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl @@ -62,7 +62,8 @@ layout(set = 0, binding = 2, std140) uniform SceneData { bool volumetric_fog_enabled; float volumetric_fog_inv_length; float volumetric_fog_detail_spread; - uint volumetric_fog_pad; + + float fog_aerial_perspective; vec3 fog_light_color; float fog_sun_scatter; @@ -140,8 +141,8 @@ vec4 volumetric_fog_process(vec2 screen_uv) { return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); } -vec4 fog_process(vec3 view) { - vec3 fog_color = scene_data.fog_light_color; +vec4 fog_process(vec3 view, vec3 sky_color) { + vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective); if (scene_data.fog_sun_scatter > 0.001) { vec4 sun_scatter = vec4(0.0); @@ -181,6 +182,7 @@ void main() { float alpha = 1.0; // Only available to subpasses vec4 half_res_color = vec4(1.0); vec4 quarter_res_color = vec4(1.0); + vec4 custom_fog = vec4(0.0); #ifdef USE_CUBEMAP_PASS vec3 inverted_cube_normal = cube_normal; @@ -223,14 +225,19 @@ FRAGMENT_SHADER_CODE #if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS) + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + if (scene_data.fog_enabled) { + vec4 fog = fog_process(cube_normal, frag_color.rgb); + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + } + if (scene_data.volumetric_fog_enabled) { vec4 fog = volumetric_fog_process(uv); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } - if (scene_data.fog_enabled) { - vec4 fog = fog_process(cube_normal); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + if (custom_fog.a > 0.0) { + frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); } #endif // DISABLE_FOG diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl index b7c46a7d0e..ee66de4192 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl @@ -37,16 +37,18 @@ layout(push_constant, binding = 1, std430) uniform Params { uvec2 glow_texture_size; float glow_intensity; - uint glow_level_flags; + uint pad3; uint glow_mode; + float glow_levels[7]; float exposure; float white; float auto_exposure_grey; + uint pad2; vec2 pixel_size; bool use_fxaa; - uint pad; + bool use_debanding; } params; @@ -155,6 +157,10 @@ vec3 tonemap_aces(vec3 color, float white) { } vec3 tonemap_reinhard(vec3 color, float white) { + // Ensure color values are positive. + // They can be negative in the case of negative lights, which leads to undesired behavior. + color = max(vec3(0.0), color); + return (white * color + color) / (color * white + white); } @@ -186,32 +192,32 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels vec3 glow = vec3(0.0f); - if (bool(params.glow_level_flags & (1 << 0))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb; + if (params.glow_levels[0] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb * params.glow_levels[0]; } - if (bool(params.glow_level_flags & (1 << 1))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb; + if (params.glow_levels[1] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb * params.glow_levels[1]; } - if (bool(params.glow_level_flags & (1 << 2))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb; + if (params.glow_levels[2] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb * params.glow_levels[2]; } - if (bool(params.glow_level_flags & (1 << 3))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb; + if (params.glow_levels[3] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb * params.glow_levels[3]; } - if (bool(params.glow_level_flags & (1 << 4))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb; + if (params.glow_levels[4] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb * params.glow_levels[4]; } - if (bool(params.glow_level_flags & (1 << 5))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb; + if (params.glow_levels[5] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb * params.glow_levels[5]; } - if (bool(params.glow_level_flags & (1 << 6))) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb; + if (params.glow_levels[6] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb * params.glow_levels[6]; } return glow; @@ -299,6 +305,20 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { } } +#define QUARTER_COLOR 1.0 / 1024.0 + +// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf +// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom) +// NOTE: `frag_coord` is in pixels (i.e. not normalized UV). +vec3 screen_space_dither(vec2 frag_coord) { + // Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR. + vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord)); + dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0)); + + // Subtract 0.5 to avoid slightly brightening the whole viewport. + return (dither.rgb - 0.5) / 255.0; +} + void main() { vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; @@ -322,6 +342,11 @@ void main() { if (params.use_fxaa) { color = do_fxaa(color, exposure, uv_interp); } + if (params.use_debanding) { + // For best results, debanding should be done before tonemapping. + // Otherwise, we're adding noise to an already-quantized image. + color += screen_space_dither(gl_FragCoord.xy); + } color = apply_tonemapping(color, params.white); color = linear_to_srgb(color); // regular linear -> SRGB conversion diff --git a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl index cb19fb0b69..13b162f0c9 100644 --- a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl @@ -485,7 +485,7 @@ void main() { //get depth at cell pos float z = get_depth_at_pos(fog_cell_size.z, i); - //get distance from previos pos + //get distance from previous pos float d = abs(prev_z - z); //compute exinction based on beer's float extinction = t * exp(-d * fog.a); |