From 404787a6a4f6f1a30ad6830a2176172f76645791 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 11 Mar 2024 11:16:07 +0100 Subject: [PATCH] Restore the Y Scale as a cascade layout setting. Fixed Volumetric Fog --- scene/resources/environment.cpp | 4 +- scene/resources/environment.h | 2 + .../rendering/renderer_rd/environment/gi.cpp | 29 +- .../rendering/renderer_rd/environment/gi.h | 1 - .../renderer_rd/renderer_scene_render_rd.cpp | 6 +- .../shaders/environment/hddagi_integrate.glsl | 397 +++++++++--------- .../environment/hddagi_preprocess.glsl | 6 +- .../environment/volumetric_fog_process.glsl | 7 +- servers/rendering_server.cpp | 3 + servers/rendering_server.h | 2 + 10 files changed, 232 insertions(+), 225 deletions(-) diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 7d253d531a6a..8d40124f343b 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1434,7 +1434,7 @@ void Environment::_bind_methods() { ADD_GROUP("DynamicGI", "dynamic_gi_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dynamic_gi_enabled"), "set_dynamic_gi_enabled", "is_dynamic_gi_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_gi_cascades", PROPERTY_HINT_RANGE, "1,8,1"), "set_dynamic_gi_cascades", "get_dynamic_gi_cascades"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_gi_cascade_format", PROPERTY_HINT_ENUM, "16x8x16,16x16x16"), "set_dynamic_gi_cascade_format", "get_dynamic_gi_cascade_format"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "dynamic_gi_cascade_format", PROPERTY_HINT_ENUM, "16x8x16,16x16x16,16x16x16 75% Height,16x16x16 50% Height"), "set_dynamic_gi_cascade_format", "get_dynamic_gi_cascade_format"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dynamic_gi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_dynamic_gi_min_cell_size", "get_dynamic_gi_min_cell_size"); // Don't store the values of `dynamic_gi_cascade0_distance` and `dynamic_gi_max_distance` // as they're derived from `dynamic_gi_min_cell_size`. @@ -1657,6 +1657,8 @@ void Environment::_bind_methods() { BIND_ENUM_CONSTANT(DYNAMIC_GI_CASCADE_FORMAT_16x8x16); BIND_ENUM_CONSTANT(DYNAMIC_GI_CASCADE_FORMAT_16x16x16); + BIND_ENUM_CONSTANT(DYNAMIC_GI_CASCADE_FORMAT_16x16x16_75_PERCENT_HEIGHT); + BIND_ENUM_CONSTANT(DYNAMIC_GI_CASCADE_FORMAT_16x16x16_50_PERCENT_HEIGHT); BIND_ENUM_CONSTANT(DYNAMIC_GI_CASCADE_FORMAT_MAX); } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 687b5c7d5ce7..45426b964fd1 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -72,6 +72,8 @@ class Environment : public Resource { enum DynamicGICascadeFormat { DYNAMIC_GI_CASCADE_FORMAT_16x8x16, DYNAMIC_GI_CASCADE_FORMAT_16x16x16, + DYNAMIC_GI_CASCADE_FORMAT_16x16x16_75_PERCENT_HEIGHT, + DYNAMIC_GI_CASCADE_FORMAT_16x16x16_50_PERCENT_HEIGHT, DYNAMIC_GI_CASCADE_FORMAT_MAX, }; diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index 9363edd4ce50..025cb5496150 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -354,12 +354,20 @@ void GI::HDDAGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_r switch (cascade_format) { case RS::ENV_HDDAGI_CASCADE_FORMAT_16x16x16: { cascade_size.y = CASCADE_SIZE; + y_mult = 1.0; } break; - case RS::ENV_HDDAGI_CASCADE_FORMAT_16x8x16: { - cascade_size.y = CASCADE_SIZE / 2; + case RS::ENV_HDDAGI_CASCADE_FORMAT_16x16x16_50_PERCENT_HEIGHT: { + cascade_size.y = CASCADE_SIZE; + y_mult = 2.0; } break; - default: { + case RS::ENV_HDDAGI_CASCADE_FORMAT_16x16x16_75_PERCENT_HEIGHT: { cascade_size.y = CASCADE_SIZE; + y_mult = 1.5; + } break; + case RS::ENV_HDDAGI_CASCADE_FORMAT_16x8x16: + default: { + cascade_size.y = CASCADE_SIZE / 2; + y_mult = 1.0; } break; } @@ -374,9 +382,6 @@ void GI::HDDAGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_r occlusion_bias = RendererSceneRenderRD::get_singleton()->environment_get_hddagi_occlusion_bias(p_env); normal_bias = RendererSceneRenderRD::get_singleton()->environment_get_hddagi_normal_bias(p_env); frames_to_converge = p_requested_history_size; - //y_scale_mode = RendererSceneRenderRD::get_singleton()->environment_get_hddagi_y_scale(p_env); - //static const float y_scale[3] = { 2.0, 1.5, 1.0 }; - //y_mult = y_scale[y_scale_mode]; version = gi->hddagi_current_version; cascades.resize(num_cascades); @@ -546,9 +551,9 @@ void GI::HDDAGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_r RD::TextureFormat tf_ambient = tf_lightprobes; tf_ambient.width = (PROBE_DIVISOR.x + 1); tf_ambient.height = (PROBE_DIVISOR.y + 1) * (PROBE_DIVISOR.z + 1); - - lightprobe_ambient_data = create_clear_texture(tf_ambient, String("HDDAGI Lighprobe Ambient")); - lightprobe_ambient_tex = RD::get_singleton()->texture_create_shared(tv, lightprobe_ambient_data); + tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf_ambient.shareable_formats.clear(); + lightprobe_ambient_tex = create_clear_texture(tf_ambient, String("HDDAGI Ambient Light Texture")); RD::TextureFormat tf_neighbours; tf_neighbours.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; @@ -819,7 +824,7 @@ void GI::HDDAGI::render_region(Ref p_render_buffers, int p 0, RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 1, lightprobe_specular_data), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 2, lightprobe_diffuse_data), - RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 3, lightprobe_ambient_data), + RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 3, lightprobe_ambient_tex), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 4, lightprobe_hit_cache_data), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 5, lightprobe_moving_average_history), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 6, lightprobe_moving_average), @@ -1041,7 +1046,7 @@ GI::HDDAGI::~HDDAGI() { RD::get_singleton()->free(lightprobe_specular_data); RD::get_singleton()->free(lightprobe_diffuse_data); - RD::get_singleton()->free(lightprobe_ambient_data); + RD::get_singleton()->free(lightprobe_ambient_tex); RD::get_singleton()->free(lightprobe_diffuse_filter_data); RD::get_singleton()->free(lightprobe_hit_cache_data); RD::get_singleton()->free(lightprobe_hit_cache_version_data); @@ -1360,7 +1365,7 @@ void GI::HDDAGI::update_probes(RID p_env, SkyRD::Sky *p_sky, uint32_t p_view_cou RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, 4, RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 5, lightprobe_specular_data), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 6, lightprobe_diffuse_data), - RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 7, lightprobe_ambient_data), + RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 7, lightprobe_ambient_tex), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 8, lightprobe_hit_cache_data), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 9, lightprobe_hit_cache_version_data), RD::Uniform(RD::UNIFORM_TYPE_IMAGE, 10, region_version_data), diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index 929d1b76aeee..be1434365b6b 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -653,7 +653,6 @@ class GI : public RendererGI { RID lightprobe_specular_data; RID lightprobe_diffuse_data; RID lightprobe_diffuse_tex; - RID lightprobe_ambient_data; RID lightprobe_ambient_tex; RID lightprobe_diffuse_filter_data; RID lightprobe_diffuse_filter_tex; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 189534b27249..5fa0552de489 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -230,7 +230,6 @@ void RendererSceneRenderRD::_debug_hddagi_probes(Ref p_ren Ref hddagi = p_render_buffers->get_custom_data(RB_SCOPE_HDDAGI); hddagi->debug_probes(p_framebuffer, p_view_count, p_camera_with_transforms); - } //////////////////////////////// @@ -794,7 +793,7 @@ bool RendererSceneRenderRD::_debug_draw_can_use_effects(RS::ViewportDebugDraw p_ case RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER: case RS::VIEWPORT_DEBUG_DRAW_SSAO: case RS::VIEWPORT_DEBUG_DRAW_SSIL: - case RS::VIEWPORT_DEBUG_DRAW_SDFGI: + case RS::VIEWPORT_DEBUG_DRAW_HDDAGI: case RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER: case RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS: can_use_effects = true; @@ -805,7 +804,7 @@ bool RendererSceneRenderRD::_debug_draw_can_use_effects(RS::ViewportDebugDraw p_ case RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION: case RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE: case RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS: - case RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES: + case RS::VIEWPORT_DEBUG_DRAW_HDDAGI_PROBES: case RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD: can_use_effects = true; break; @@ -1107,7 +1106,6 @@ void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bo } void RendererSceneRenderRD::render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_compositor, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderHDDAGIData *p_render_hddagi_regions, int p_render_hddagi_region_count, const RenderHDDAGIUpdateData *p_hddagi_update_data, RenderingMethod::RenderInfo *r_render_info) { - RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); diff --git a/servers/rendering/renderer_rd/shaders/environment/hddagi_integrate.glsl b/servers/rendering/renderer_rd/shaders/environment/hddagi_integrate.glsl index 699073cac6ab..fdd483013b62 100644 --- a/servers/rendering/renderer_rd/shaders/environment/hddagi_integrate.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/hddagi_integrate.glsl @@ -1,4 +1,4 @@ -ยดยด#[compute] +#[compute] #version 450 @@ -23,7 +23,7 @@ #ifdef MODE_PROCESS - layout(local_size_x = LIGHTPROBE_OCT_SIZE, local_size_y = LIGHTPROBE_OCT_SIZE, local_size_z = 1) in; +layout(local_size_x = LIGHTPROBE_OCT_SIZE, local_size_y = LIGHTPROBE_OCT_SIZE, local_size_z = 1) in; #define TRACE_SUBPIXEL @@ -34,7 +34,7 @@ layout(set = 0, binding = 3) uniform texture3D light_cascades; layout(set = 0, binding = 4) uniform sampler linear_sampler; layout(r32ui, set = 0, binding = 5) uniform restrict uimage2DArray lightprobe_texture_data; layout(r32ui, set = 0, binding = 6) uniform restrict writeonly uimage2DArray lightprobe_diffuse_data; -layout(r32ui, set = 0, binding = 7) uniform restrict writeonly uimage2DArray lightprobe_ambient_data; +layout(rgba16f, set = 0, binding = 7) uniform restrict writeonly image2DArray lightprobe_ambient_tex; layout(r32ui, set = 0, binding = 8) uniform restrict uimage2DArray ray_hit_cache; layout(r16ui, set = 0, binding = 9) uniform restrict uimage2DArray ray_hit_cache_version; layout(r16ui, set = 0, binding = 10) uniform restrict uimage3D region_versions; @@ -479,16 +479,16 @@ void main() { // Store it back. imageStore(lightprobe_update_frames, probe_texture_pos, uvec4(frame)); - ambient_accum = uvec3(0); } else { probe_history_index = -1; // No processing. } + + ambient_accum = uvec3(0); } memoryBarrierShared(); barrier(); - bool thread_active = true; vec3 light; ivec3 cache_texture_pos; vec3 ray_dir; @@ -502,150 +502,148 @@ void main() { uint cache_entry; if (probe_history_index < 0) { - thread_active = false; - } else { - float probe_cell_size = float(params.grid_size.x) / float(params.probe_axis_size.x - 1) / cascades.data[params.cascade].to_cell; + return; // All threads return, so no barrier will be executed. + } - ray_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size; + float probe_cell_size = float(params.grid_size.x) / float(params.probe_axis_size.x - 1) / cascades.data[params.cascade].to_cell; - // Ensure a unique hash that includes the probe world position, the local octahedron pixel, and the history frame index - uvec3 h3 = hash3(uvec3((uvec3(probe_world_pos) * LIGHTPROBE_OCT_SIZE * LIGHTPROBE_OCT_SIZE + uvec3(probe_index)) * uvec3(params.history_size) + uvec3(probe_history_index))); - uint h = (h3.x ^ h3.y) ^ h3.z; - sample_ofs = vec2(ivec2(h >> 16, h & 0xFFFF)) / vec2(0xFFFF); - ray_dir = octahedron_decode((vec2(local_pos) + sample_ofs) / vec2(LIGHTPROBE_OCT_SIZE)); + ray_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size; - ray_dir.y *= params.y_mult; - ray_dir = normalize(ray_dir); + // Ensure a unique hash that includes the probe world position, the local octahedron pixel, and the history frame index + uvec3 h3 = hash3(uvec3((uvec3(probe_world_pos) * LIGHTPROBE_OCT_SIZE * LIGHTPROBE_OCT_SIZE + uvec3(probe_index)) * uvec3(params.history_size) + uvec3(probe_history_index))); + uint h = (h3.x ^ h3.y) ^ h3.z; + sample_ofs = vec2(ivec2(h >> 16, h & 0xFFFF)) / vec2(0xFFFF); + ray_dir = octahedron_decode((vec2(local_pos) + sample_ofs) / vec2(LIGHTPROBE_OCT_SIZE)); - // Apply bias (by a cell) - float bias = params.ray_bias; - vec3 abs_ray_dir = abs(ray_dir); - ray_pos += ray_dir * 1.0 / max(abs_ray_dir.x, max(abs_ray_dir.y, abs_ray_dir.z)) * bias / cascades.data[params.cascade].to_cell; + ray_dir.y *= params.y_mult; + ray_dir = normalize(ray_dir); - cache_texture_pos = ivec3(probe_texture_pos.xy * LIGHTPROBE_OCT_SIZE + local_pos, probe_texture_pos.z * params.history_size + probe_history_index); - cache_entry = imageLoad(ray_hit_cache, cache_texture_pos).r; + // Apply bias (by a cell) + float bias = params.ray_bias; + vec3 abs_ray_dir = abs(ray_dir); + ray_pos += ray_dir * 1.0 / max(abs_ray_dir.x, max(abs_ray_dir.y, abs_ray_dir.z)) * bias / cascades.data[params.cascade].to_cell; - cache_valid = bool(cache_entry & CACHE_IS_VALID); + cache_texture_pos = ivec3(probe_texture_pos.xy * LIGHTPROBE_OCT_SIZE + local_pos, probe_texture_pos.z * params.history_size + probe_history_index); + cache_entry = imageLoad(ray_hit_cache, cache_texture_pos).r; - cache_invalidated_debug = vec3(0.0); + cache_valid = bool(cache_entry & CACHE_IS_VALID); - if (cache_valid) { - // Make sure the cache is really valid - hit = bool(cache_entry & CACHE_IS_HIT); - uvec4 uhit = (uvec4(cache_entry) >> uvec4(0, 8, 16, 24)) & uvec4(0xFF, 0xFF, 0xFF, 0x7); - hit_cell = ivec3(uhit.xyz); - hit_cascade = int(uhit.w); - uint axis = (cache_entry >> 27) & 0x3; - if (bool((1 << axis) & params.motion_accum)) { - // There was motion in this axis, cache is no longer valid. + cache_invalidated_debug = vec3(0.0); + + if (cache_valid) { + // Make sure the cache is really valid + hit = bool(cache_entry & CACHE_IS_HIT); + uvec4 uhit = (uvec4(cache_entry) >> uvec4(0, 8, 16, 24)) & uvec4(0xFF, 0xFF, 0xFF, 0x7); + hit_cell = ivec3(uhit.xyz); + hit_cascade = int(uhit.w); + uint axis = (cache_entry >> 27) & 0x3; + if (bool((1 << axis) & params.motion_accum)) { + // There was motion in this axis, cache is no longer valid. + cache_valid = false; + cache_invalidated_debug = vec3(0, 0, 4.0); + } else if (hit) { + // Check if the region pointed to is still valid. + uint version = imageLoad(ray_hit_cache_version, cache_texture_pos).r; + uint region_version = imageLoad(region_versions, (hit_cell / REGION_SIZE) + ivec3(0, hit_cascade * (params.grid_size.y / REGION_SIZE), 0)).r; + + if (region_version != version) { cache_valid = false; - cache_invalidated_debug = vec3(0, 0, 4.0); - } else if (hit) { - // Check if the region pointed to is still valid. - uint version = imageLoad(ray_hit_cache_version, cache_texture_pos).r; - uint region_version = imageLoad(region_versions, (hit_cell / REGION_SIZE) + ivec3(0, hit_cascade * (params.grid_size.y / REGION_SIZE), 0)).r; - - if (region_version != version) { - cache_valid = false; - cache_invalidated_debug = (hit_cascade == params.cascade) ? vec3(0.0, 4.00, 0.0) : vec3(4.0, 0, 0.0); - } + cache_invalidated_debug = (hit_cascade == params.cascade) ? vec3(0.0, 4.00, 0.0) : vec3(4.0, 0, 0.0); } } + } - if (!cache_valid) { - ivec3 hit_face; - hit = trace_ray_hdda(ray_pos, ray_dir, params.cascade, hit_cell, hit_face, hit_cascade); - if (hit) { - hit_cell += hit_face; + if (!cache_valid) { + ivec3 hit_face; + hit = trace_ray_hdda(ray_pos, ray_dir, params.cascade, hit_cell, hit_face, hit_cascade); + if (hit) { + hit_cell += hit_face; - ivec3 reg_cell_offset = cascades.data[hit_cascade].region_world_offset * REGION_SIZE; - hit_cell = (hit_cell + reg_cell_offset) & (params.grid_size - 1); // Read from wrapped world coordinates - } + ivec3 reg_cell_offset = cascades.data[hit_cascade].region_world_offset * REGION_SIZE; + hit_cell = (hit_cell + reg_cell_offset) & (params.grid_size - 1); // Read from wrapped world coordinates } + } - if (hit) { - ivec3 spos = hit_cell; - spos.y += hit_cascade * params.grid_size.y; - light = texelFetch(sampler3D(light_cascades, linear_sampler), spos, 0).rgb; - } else if (params.sky_mode == SKY_MODE_SKY) { + if (hit) { + ivec3 spos = hit_cell; + spos.y += hit_cascade * params.grid_size.y; + light = texelFetch(sampler3D(light_cascades, linear_sampler), spos, 0).rgb; + } else if (params.sky_mode == SKY_MODE_SKY) { #ifdef USE_CUBEMAP_ARRAY - light = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. + light = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #else - light = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. + light = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #endif - light *= params.sky_energy; - } else if (params.sky_mode == SKY_MODE_COLOR) { - light = params.sky_color; - light *= params.sky_energy; - } else { - light = vec3(0); - } + light *= params.sky_energy; + } else if (params.sky_mode == SKY_MODE_COLOR) { + light = params.sky_color; + light *= params.sky_energy; + } else { + light = vec3(0); } memoryBarrierShared(); barrier(); - if (thread_active) { - // Plot the light to the octahedron using bilinear filtering + // Plot the light to the octahedron using bilinear filtering #ifdef TRACE_SUBPIXEL - sample_ofs = sample_ofs * 2.0 - 1.0; - ivec2 bilinear_base = ivec2(1) + local_pos - mix(ivec2(0), ivec2(1), lessThan(sample_ofs, vec2(0))); - vec2 blend = mix(sample_ofs, 1.0 + sample_ofs, lessThan(sample_ofs, vec2(0))); - for (int i = 0; i < 2; i++) { - float i_w = i == 0 ? 1.0 - blend.y : blend.y; - for (int j = 0; j < 2; j++) { - float j_w = j == 0 ? 1.0 - blend.x : blend.x; - uint wrap_neighbour = wrap_neighbours[(bilinear_base.y + i) * (LIGHTPROBE_OCT_SIZE + 2) + (bilinear_base.x + j)]; - ivec2 write_to = ivec2(wrap_neighbour & 0xFFFF, wrap_neighbour >> 16); - int write_offset = write_to.y * LIGHTPROBE_OCT_SIZE + write_to.x; - float write_weight = i_w * j_w; - - uvec3 lightu = uvec3(clamp((light * write_weight) * float(1 << FP_BITS), 0, float(FP_MAX))); - atomicAdd(neighbours_accum[write_offset].r, lightu.r); - atomicAdd(neighbours_accum[write_offset].g, lightu.g); - atomicAdd(neighbours_accum[write_offset].b, lightu.b); - } + sample_ofs = sample_ofs * 2.0 - 1.0; + ivec2 bilinear_base = ivec2(1) + local_pos - mix(ivec2(0), ivec2(1), lessThan(sample_ofs, vec2(0))); + vec2 blend = mix(sample_ofs, 1.0 + sample_ofs, lessThan(sample_ofs, vec2(0))); + for (int i = 0; i < 2; i++) { + float i_w = i == 0 ? 1.0 - blend.y : blend.y; + for (int j = 0; j < 2; j++) { + float j_w = j == 0 ? 1.0 - blend.x : blend.x; + uint wrap_neighbour = wrap_neighbours[(bilinear_base.y + i) * (LIGHTPROBE_OCT_SIZE + 2) + (bilinear_base.x + j)]; + ivec2 write_to = ivec2(wrap_neighbour & 0xFFFF, wrap_neighbour >> 16); + int write_offset = write_to.y * LIGHTPROBE_OCT_SIZE + write_to.x; + float write_weight = i_w * j_w; + + uvec3 lightu = uvec3(clamp((light * write_weight) * float(1 << FP_BITS), 0, float(FP_MAX))); + atomicAdd(neighbours_accum[write_offset].r, lightu.r); + atomicAdd(neighbours_accum[write_offset].g, lightu.g); + atomicAdd(neighbours_accum[write_offset].b, lightu.b); } + } #else - neighbours[probe_index] = light; + neighbours[probe_index] = light; #endif - if (!cache_valid) { - cache_entry = CACHE_IS_VALID; - if (hit) { - // Determine the side of the cascade box this ray exited through, this is important for invalidation purposes. - - vec3 unit_pos = ray_pos - cascades.data[params.cascade].offset; - unit_pos *= cascades.data[params.cascade].to_cell; - - vec3 t0 = -unit_pos / ray_dir; - vec3 t1 = (vec3(params.grid_size) - unit_pos) / ray_dir; - vec3 tmax = max(t0, t1); - - uint axis; - float m; - if (tmax.x < tmax.y) { - axis = 0; - m = tmax.x; - } else { - axis = 1; - m = tmax.y; - } - if (tmax.z < m) { - axis = 2; - } + if (!cache_valid) { + cache_entry = CACHE_IS_VALID; + if (hit) { + // Determine the side of the cascade box this ray exited through, this is important for invalidation purposes. - uvec3 ucell = (uvec3(hit_cell) & uvec3(0xFF)) << uvec3(0, 8, 16); - cache_entry |= CACHE_IS_HIT | ucell.x | ucell.y | ucell.z | (uint(min(7, hit_cascade)) << 24) | (axis << 27); + vec3 unit_pos = ray_pos - cascades.data[params.cascade].offset; + unit_pos *= cascades.data[params.cascade].to_cell; - uint region_version = imageLoad(region_versions, (hit_cell >> REGION_SIZE) + ivec3(0, hit_cascade * (params.grid_size.y / REGION_SIZE), 0)).r; + vec3 t0 = -unit_pos / ray_dir; + vec3 t1 = (vec3(params.grid_size) - unit_pos) / ray_dir; + vec3 tmax = max(t0, t1); - imageStore(ray_hit_cache_version, cache_texture_pos, uvec4(region_version)); + uint axis; + float m; + if (tmax.x < tmax.y) { + axis = 0; + m = tmax.x; + } else { + axis = 1; + m = tmax.y; + } + if (tmax.z < m) { + axis = 2; } - imageStore(ray_hit_cache, cache_texture_pos, uvec4(cache_entry)); + uvec3 ucell = (uvec3(hit_cell) & uvec3(0xFF)) << uvec3(0, 8, 16); + cache_entry |= CACHE_IS_HIT | ucell.x | ucell.y | ucell.z | (uint(min(7, hit_cascade)) << 24) | (axis << 27); + + uint region_version = imageLoad(region_versions, (hit_cell >> REGION_SIZE) + ivec3(0, hit_cascade * (params.grid_size.y / REGION_SIZE), 0)).r; + + imageStore(ray_hit_cache_version, cache_texture_pos, uvec4(region_version)); } + + imageStore(ray_hit_cache, cache_texture_pos, uvec4(cache_entry)); } groupMemoryBarrier(); @@ -653,120 +651,117 @@ void main() { // convert back to float and do moving average - if (thread_active) { #ifdef TRACE_SUBPIXEL - light = vec3(neighbours_accum[probe_index]) / float(1 << FP_BITS); + light = vec3(neighbours_accum[probe_index]) / float(1 << FP_BITS); #else - light = neighbours[probe_index]; + light = neighbours[probe_index]; #endif - // Encode to RGBE to store in accumulator - - uint light_rgbe = rgbe_encode(light); + // Encode to RGBE to store in accumulator - ivec3 ma_pos = ivec3(cache_texture_pos.xy * ivec2(3, 1), params.cascade); + uint light_rgbe = rgbe_encode(light); - uvec3 moving_average = uvec3( - imageLoad(lightprobe_moving_average, ma_pos + ivec3(0, 0, 0)).r, - imageLoad(lightprobe_moving_average, ma_pos + ivec3(1, 0, 0)).r, - imageLoad(lightprobe_moving_average, ma_pos + ivec3(2, 0, 0)).r); + ivec3 ma_pos = ivec3(cache_texture_pos.xy * ivec2(3, 1), params.cascade); - ivec3 history_pos = ivec3(probe_texture_pos.xy * 4 + ivec2(probe_index % 4, probe_index / 4), probe_texture_pos.z * params.history_size + probe_history_index); + uvec3 moving_average = uvec3( + imageLoad(lightprobe_moving_average, ma_pos + ivec3(0, 0, 0)).r, + imageLoad(lightprobe_moving_average, ma_pos + ivec3(1, 0, 0)).r, + imageLoad(lightprobe_moving_average, ma_pos + ivec3(2, 0, 0)).r); - uvec3 prev_val = rgbe_decode_fp(imageLoad(lightprobe_moving_average_history, cache_texture_pos).r, FP_BITS); + ivec3 history_pos = ivec3(probe_texture_pos.xy * 4 + ivec2(probe_index % 4, probe_index / 4), probe_texture_pos.z * params.history_size + probe_history_index); - moving_average -= prev_val; - uvec3 new_val = rgbe_decode_fp(light_rgbe, FP_BITS); // Round trip to ensure integer consistency - moving_average += new_val; + uvec3 prev_val = rgbe_decode_fp(imageLoad(lightprobe_moving_average_history, cache_texture_pos).r, FP_BITS); - imageStore(lightprobe_moving_average_history, cache_texture_pos, uvec4(light_rgbe)); + moving_average -= prev_val; + uvec3 new_val = rgbe_decode_fp(light_rgbe, FP_BITS); // Round trip to ensure integer consistency + moving_average += new_val; - imageStore(lightprobe_moving_average, ma_pos + ivec3(0, 0, 0), uvec4(moving_average.r)); - imageStore(lightprobe_moving_average, ma_pos + ivec3(1, 0, 0), uvec4(moving_average.g)); - imageStore(lightprobe_moving_average, ma_pos + ivec3(2, 0, 0), uvec4(moving_average.b)); + imageStore(lightprobe_moving_average_history, cache_texture_pos, uvec4(light_rgbe)); - moving_average /= params.history_size; + imageStore(lightprobe_moving_average, ma_pos + ivec3(0, 0, 0), uvec4(moving_average.r)); + imageStore(lightprobe_moving_average, ma_pos + ivec3(1, 0, 0), uvec4(moving_average.g)); + imageStore(lightprobe_moving_average, ma_pos + ivec3(2, 0, 0), uvec4(moving_average.b)); - if (params.store_ambient_texture) { - atomicAdd(ambient_accum.r, moving_average.r); - atomicAdd(ambient_accum.g, moving_average.g); - atomicAdd(ambient_accum.b, moving_average.b); - } + moving_average /= params.history_size; - light = vec3(moving_average) / float(1 << FP_BITS); - neighbours[probe_index] = light; + if (params.store_ambient_texture) { + atomicAdd(ambient_accum.r, moving_average.r); + atomicAdd(ambient_accum.g, moving_average.g); + atomicAdd(ambient_accum.b, moving_average.b); } + light = vec3(moving_average) / float(1 << FP_BITS); + neighbours[probe_index] = light; + groupMemoryBarrier(); barrier(); // Compute specular, diffuse, ambient - if (thread_active) { - vec3 diffuse_light = vec3(0); - vec3 specular_light = light; + vec3 diffuse_light = vec3(0); + vec3 specular_light = light; - for (uint i = 0; i < neighbour_max_weights; i++) { - uint n = neighbour_weights[probe_index * neighbour_max_weights + i]; - uint index = n >> 16; - float weight = float(n & 0xFFFF) / float(0xFFFF); - diffuse_light += neighbours[index] * weight; - } + for (uint i = 0; i < neighbour_max_weights; i++) { + uint n = neighbour_weights[probe_index * neighbour_max_weights + i]; + uint index = n >> 16; + float weight = float(n & 0xFFFF) / float(0xFFFF); + diffuse_light += neighbours[index] * weight; + } - ivec3 store_texture_pos = ivec3(probe_texture_pos.xy * (LIGHTPROBE_OCT_SIZE + 2) + ivec2(1), probe_texture_pos.z); - ivec3 probe_read_pos = store_texture_pos + ivec3(local_pos, 0); - - //if (cache_invalidated_debug!=vec3(0.0)) { - // diffuse_light = cache_invalidated_debug; - //} - - // Store in octahedral map - - ivec3 copy_to[4] = ivec3[](ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2)); - copy_to[0] = probe_read_pos; - - if (local_pos == ivec2(0, 0)) { - copy_to[1] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - 1, -1, 0); - copy_to[2] = store_texture_pos + ivec3(-1, LIGHTPROBE_OCT_SIZE - 1, 0); - copy_to[3] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, LIGHTPROBE_OCT_SIZE, 0); - } else if (local_pos == ivec2(LIGHTPROBE_OCT_SIZE - 1, 0)) { - copy_to[1] = store_texture_pos + ivec3(0, -1, 0); - copy_to[2] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, LIGHTPROBE_OCT_SIZE - 1, 0); - copy_to[3] = store_texture_pos + ivec3(-1, LIGHTPROBE_OCT_SIZE, 0); - } else if (local_pos == ivec2(0, LIGHTPROBE_OCT_SIZE - 1)) { - copy_to[1] = store_texture_pos + ivec3(-1, 0, 0); - copy_to[2] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - 1, LIGHTPROBE_OCT_SIZE, 0); - copy_to[3] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, -1, 0); - } else if (local_pos == ivec2(LIGHTPROBE_OCT_SIZE - 1, LIGHTPROBE_OCT_SIZE - 1)) { - copy_to[1] = store_texture_pos + ivec3(0, LIGHTPROBE_OCT_SIZE, 0); - copy_to[2] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, 0, 0); - copy_to[3] = store_texture_pos + ivec3(-1, -1, 0); - } else if (local_pos.y == 0) { - copy_to[1] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - local_pos.x - 1, local_pos.y - 1, 0); - } else if (local_pos.x == 0) { - copy_to[1] = store_texture_pos + ivec3(local_pos.x - 1, LIGHTPROBE_OCT_SIZE - local_pos.y - 1, 0); - } else if (local_pos.y == LIGHTPROBE_OCT_SIZE - 1) { - copy_to[1] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - local_pos.x - 1, local_pos.y + 1, 0); - } else if (local_pos.x == LIGHTPROBE_OCT_SIZE - 1) { - copy_to[1] = store_texture_pos + ivec3(local_pos.x + 1, LIGHTPROBE_OCT_SIZE - local_pos.y - 1, 0); - } + ivec3 store_texture_pos = ivec3(probe_texture_pos.xy * (LIGHTPROBE_OCT_SIZE + 2) + ivec2(1), probe_texture_pos.z); + ivec3 probe_read_pos = store_texture_pos + ivec3(local_pos, 0); - uint light_rgbe = rgbe_encode(specular_light); - uint diffuse_rgbe = rgbe_encode(diffuse_light); + //if (cache_invalidated_debug!=vec3(0.0)) { + // diffuse_light = cache_invalidated_debug; + //} - for (int i = 0; i < 4; i++) { - if (copy_to[i] == ivec3(-2, -2, -2)) { - continue; - } - imageStore(lightprobe_texture_data, copy_to[i], uvec4(light_rgbe)); - imageStore(lightprobe_diffuse_data, copy_to[i], uvec4(diffuse_rgbe)); - // also to diffuse - } + // Store in octahedral map + + ivec3 copy_to[4] = ivec3[](ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2)); + copy_to[0] = probe_read_pos; - if (params.store_ambient_texture && probe_index == 0) { - vec3 ambient_light = vec3(ambient_accum) / float(1 << FP_BITS); - imageStore(lightprobe_ambient_data, ivec3(probe_texture_pos.xy, params.cascade), uvec4(rgbe_encode(ambient_light))); + if (local_pos == ivec2(0, 0)) { + copy_to[1] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - 1, -1, 0); + copy_to[2] = store_texture_pos + ivec3(-1, LIGHTPROBE_OCT_SIZE - 1, 0); + copy_to[3] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, LIGHTPROBE_OCT_SIZE, 0); + } else if (local_pos == ivec2(LIGHTPROBE_OCT_SIZE - 1, 0)) { + copy_to[1] = store_texture_pos + ivec3(0, -1, 0); + copy_to[2] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, LIGHTPROBE_OCT_SIZE - 1, 0); + copy_to[3] = store_texture_pos + ivec3(-1, LIGHTPROBE_OCT_SIZE, 0); + } else if (local_pos == ivec2(0, LIGHTPROBE_OCT_SIZE - 1)) { + copy_to[1] = store_texture_pos + ivec3(-1, 0, 0); + copy_to[2] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - 1, LIGHTPROBE_OCT_SIZE, 0); + copy_to[3] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, -1, 0); + } else if (local_pos == ivec2(LIGHTPROBE_OCT_SIZE - 1, LIGHTPROBE_OCT_SIZE - 1)) { + copy_to[1] = store_texture_pos + ivec3(0, LIGHTPROBE_OCT_SIZE, 0); + copy_to[2] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE, 0, 0); + copy_to[3] = store_texture_pos + ivec3(-1, -1, 0); + } else if (local_pos.y == 0) { + copy_to[1] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - local_pos.x - 1, local_pos.y - 1, 0); + } else if (local_pos.x == 0) { + copy_to[1] = store_texture_pos + ivec3(local_pos.x - 1, LIGHTPROBE_OCT_SIZE - local_pos.y - 1, 0); + } else if (local_pos.y == LIGHTPROBE_OCT_SIZE - 1) { + copy_to[1] = store_texture_pos + ivec3(LIGHTPROBE_OCT_SIZE - local_pos.x - 1, local_pos.y + 1, 0); + } else if (local_pos.x == LIGHTPROBE_OCT_SIZE - 1) { + copy_to[1] = store_texture_pos + ivec3(local_pos.x + 1, LIGHTPROBE_OCT_SIZE - local_pos.y - 1, 0); + } + + light_rgbe = rgbe_encode(specular_light); + uint diffuse_rgbe = rgbe_encode(diffuse_light); + + for (int i = 0; i < 4; i++) { + if (copy_to[i] == ivec3(-2, -2, -2)) { + continue; } + imageStore(lightprobe_texture_data, copy_to[i], uvec4(light_rgbe)); + imageStore(lightprobe_diffuse_data, copy_to[i], uvec4(diffuse_rgbe)); + // also to diffuse + } + + if (params.store_ambient_texture && probe_index == 0) { + vec3 ambient_light = vec3(ambient_accum) / float(1 << FP_BITS); + ambient_light /= LIGHTPROBE_OCT_SIZE * LIGHTPROBE_OCT_SIZE; + imageStore(lightprobe_ambient_tex, ivec3(probe_texture_pos.xy, params.cascade), vec4(ambient_light, 1)); } #endif diff --git a/servers/rendering/renderer_rd/shaders/environment/hddagi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/environment/hddagi_preprocess.glsl index b56e224e2d5b..59546774132f 100644 --- a/servers/rendering/renderer_rd/shaders/environment/hddagi_preprocess.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/hddagi_preprocess.glsl @@ -203,7 +203,7 @@ layout(local_size_x = LIGHTPROBE_OCT_SIZE, local_size_y = LIGHTPROBE_OCT_SIZE, l layout(r32ui, set = 0, binding = 1) uniform restrict uimage2DArray lightprobe_specular_data; layout(r32ui, set = 0, binding = 2) uniform restrict uimage2DArray lightprobe_diffuse_data; -layout(r32ui, set = 0, binding = 3) uniform restrict uimage2DArray lightprobe_ambient_data; +layout(rgba16f, set = 0, binding = 3) uniform restrict image2DArray lightprobe_ambient_tex; layout(r32ui, set = 0, binding = 4) uniform restrict uimage2DArray ray_hit_cache; layout(r32ui, set = 0, binding = 5) uniform restrict uimage2DArray lightprobe_moving_average_history; layout(r32ui, set = 0, binding = 6) uniform restrict uimage2DArray lightprobe_moving_average; @@ -1407,7 +1407,7 @@ void main() { if (local_pos == ivec2(0)) { tex_array_pos = ivec3(base_tex_pos, upper_cascade); - ambient_light += rgbe_decode(imageLoad(lightprobe_ambient_data, tex_array_pos).r) * occlusion_blend[i]; + ambient_light += imageLoad(lightprobe_ambient_tex, tex_array_pos).rgb * occlusion_blend[i]; } } } @@ -1458,7 +1458,7 @@ void main() { } if (local_pos == ivec2(0)) { - imageStore(lightprobe_ambient_data, ivec3(probe_tex_pos, params.cascade), uvec4(rgbe_encode(ambient_light))); + imageStore(lightprobe_ambient_tex, ivec3(probe_tex_pos, params.cascade), vec4(ambient_light, 1)); } // Cache and history invalidation diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index b565fb9e4f03..f2cb2a15f7b0 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -641,7 +641,7 @@ void main() { //hddagi #ifdef ENABLE_HDDAGI - { + if (params.gi_inject > 0.001) { vec3 ambient_total = vec3(0.0); int cascade = HDDAGI_MAX_CASCADES; @@ -706,14 +706,15 @@ void main() { ivec2 tex_pos = probe_to_tex(probe, cascade); vec3 probe_light = texelFetch(sampler2DArray(hddagi_ambient_texture, linear_sampler), ivec3(tex_pos, cascade), 0).rgb; - ambient_accum.rgb += probe_light * weight * hddagi.cascades[i].exposure_normalization; + ambient_accum.rgb += probe_light * weight; ambient_accum.a += weight; } if (ambient_accum.a > 0) { ambient_accum.rgb /= ambient_accum.a; } - ambient_total = ambient_accum.rgb; + + ambient_total = ambient_accum.rgb * hddagi.cascades[cascade].exposure_normalization; } total_light += ambient_total * params.gi_inject; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 342de5e624e3..a4094e860a46 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3052,6 +3052,9 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_HDDAGI_CASCADE_FORMAT_16x8x16); BIND_ENUM_CONSTANT(ENV_HDDAGI_CASCADE_FORMAT_16x16x16); + BIND_ENUM_CONSTANT(ENV_HDDAGI_CASCADE_FORMAT_16x16x16_75_PERCENT_HEIGHT); + BIND_ENUM_CONSTANT(ENV_HDDAGI_CASCADE_FORMAT_16x16x16_50_PERCENT_HEIGHT); + BIND_ENUM_CONSTANT(ENV_HDDAGI_CASCADE_FORMAT_MAX); BIND_ENUM_CONSTANT(ENV_HDDAGI_CONVERGE_IN_6_FRAMES); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 838bb8677b63..05cbb7758c1e 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1203,6 +1203,8 @@ class RenderingServer : public Object { enum EnvironmentHDDAGICascadeFormat { ENV_HDDAGI_CASCADE_FORMAT_16x8x16, ENV_HDDAGI_CASCADE_FORMAT_16x16x16, + ENV_HDDAGI_CASCADE_FORMAT_16x16x16_75_PERCENT_HEIGHT, + ENV_HDDAGI_CASCADE_FORMAT_16x16x16_50_PERCENT_HEIGHT, ENV_HDDAGI_CASCADE_FORMAT_MAX, };