diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index dad7281e9ed..95b667eb368 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -3226,7 +3226,7 @@ Lower-end override for [member rendering/reflections/sky_reflections/ggx_samples] on mobile devices, due to performance concerns or driver support. - + Limits the number of layers to use in radiance maps when using importance sampling. A lower number will be slightly faster and take up less VRAM. diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 81960f43bd3..4130a5e4640 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -986,6 +986,10 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ return true; } +bool LightStorage::reflection_probe_instance_end_render(RID p_instance, RID p_reflection_atlas) { + return true; +} + Ref LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) { ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas); ERR_FAIL_NULL_V(atlas, Ref()); diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index 167e9d88bc0..487a14e54d0 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -687,6 +687,7 @@ public: virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; + virtual bool reflection_probe_instance_end_render(RID p_instance, RID p_reflection_atlas) override; virtual Ref reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override; virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override; diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index f4154024dbc..ba50245e1ea 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -165,6 +165,7 @@ public: virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; } virtual bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; } virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; } + virtual bool reflection_probe_instance_end_render(RID p_instance, RID p_reflection_atlas) override { return false; } virtual Ref reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override { return Ref(); } virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; } diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index 41b2104135e..fedc8742437 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -43,11 +43,11 @@ CopyEffects *CopyEffects::get_singleton() { return singleton; } -CopyEffects::CopyEffects(bool p_prefer_raster_effects) { +CopyEffects::CopyEffects(BitField p_raster_effects) { singleton = this; - prefer_raster_effects = p_prefer_raster_effects; + raster_effects = p_raster_effects; - if (prefer_raster_effects) { + if (raster_effects.has_flag(RASTER_EFFECT_GAUSSIAN_BLUR)) { // init blur shader (on compute use copy shader) Vector blur_modes; @@ -96,8 +96,8 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { copy_modes.push_back("\n#define MODE_SET_COLOR\n#define DST_IMAGE_8BIT\n"); copy_modes.push_back("\n#define MODE_MIPMAP\n"); copy_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n"); - copy_modes.push_back("\n#define MODE_CUBEMAP_TO_PANORAMA\n"); - copy_modes.push_back("\n#define MODE_CUBEMAP_ARRAY_TO_PANORAMA\n"); + copy_modes.push_back("\n#define MODE_OCTMAP_TO_PANORAMA\n"); + copy_modes.push_back("\n#define MODE_OCTMAP_ARRAY_TO_PANORAMA\n"); copy.shader.initialize(copy_modes); memset(©.push_constant, 0, sizeof(CopyPushConstant)); @@ -157,23 +157,27 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { } { - //Initialize cubemap downsampler - Vector cubemap_downsampler_modes; - cubemap_downsampler_modes.push_back(""); + // Initialize cubemap to octmap copier. + cube_to_octmap.shader.initialize({ "" }); + cube_to_octmap.shader_version = cube_to_octmap.shader.version_create(); + RID shader = cube_to_octmap.shader.version_get_shader(cube_to_octmap.shader_version, 0); + cube_to_octmap.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled()); + } - if (prefer_raster_effects) { - cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes); - - cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create(); - - cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + { + // Initialize octmap downsampler. + if (raster_effects.has_flag(RASTER_EFFECT_OCTMAP)) { + octmap_downsampler.raster_shader.initialize({ "", "\n#define USE_HIGH_QUALITY\n" }); + octmap_downsampler.shader_version = octmap_downsampler.raster_shader.version_create(); + for (int i = 0; i < DOWNSAMPLER_MODE_MAX; i++) { + octmap_downsampler.raster_pipelines[i].setup(octmap_downsampler.raster_shader.version_get_shader(octmap_downsampler.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } } else { - cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes); - - cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create(); - - cubemap_downsampler.compute_pipeline.create_compute_pipeline(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0)); - cubemap_downsampler.raster_pipeline.clear(); + octmap_downsampler.compute_shader.initialize({ "", "\n#define USE_HIGH_QUALITY\n" }); + octmap_downsampler.shader_version = octmap_downsampler.compute_shader.version_create(); + for (int i = 0; i < DOWNSAMPLER_MODE_MAX; i++) { + octmap_downsampler.compute_pipelines[i].create_compute_pipeline(octmap_downsampler.compute_shader.version_get_shader(octmap_downsampler.shader_version, i)); + } } } @@ -195,7 +199,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]); } - if (prefer_raster_effects) { + if (raster_effects.has_flag(RASTER_EFFECT_OCTMAP)) { filter.raster_shader.initialize(cubemap_filter_modes); // array variants are not supported in raster @@ -247,7 +251,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { Vector cubemap_roughness_modes; cubemap_roughness_modes.push_back(""); - if (prefer_raster_effects) { + if (raster_effects.has_flag(RASTER_EFFECT_OCTMAP)) { roughness.raster_shader.initialize(cubemap_roughness_modes); roughness.shader_version = roughness.raster_shader.version_create(); @@ -324,17 +328,17 @@ CopyEffects::~CopyEffects() { filter.compute_pipelines[i].free(); } - cubemap_downsampler.compute_pipeline.free(); - roughness.compute_pipeline.free(); - - if (prefer_raster_effects) { + if (raster_effects.has_flag(RASTER_EFFECT_GAUSSIAN_BLUR)) { blur_raster.shader.version_free(blur_raster.shader_version); RD::get_singleton()->free_rid(blur_raster.glow_sampler); - cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version); + } + + if (raster_effects.has_flag(RASTER_EFFECT_OCTMAP)) { + octmap_downsampler.raster_shader.version_free(octmap_downsampler.shader_version); filter.raster_shader.version_free(filter.shader_version); roughness.raster_shader.version_free(roughness.shader_version); } else { - cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version); + octmap_downsampler.compute_shader.version_free(octmap_downsampler.shader_version); filter.compute_shader.version_free(filter.shader_version); roughness.compute_shader.version_free(roughness.shader_version); } @@ -354,6 +358,7 @@ CopyEffects::~CopyEffects() { copy_to_fb.shader.version_free(copy_to_fb.shader_version); cube_to_dp.shader.version_free(cube_to_dp.shader_version); + cube_to_octmap.shader.version_free(cube_to_octmap.shader_version); singleton = nullptr; } @@ -411,7 +416,7 @@ void CopyEffects::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, cons RD::get_singleton()->compute_list_end(); } -void CopyEffects::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) { +void CopyEffects::copy_octmap_to_panorama(RID p_source_octmap, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array, const Size2 &p_source_octmap_border_size) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -426,22 +431,25 @@ void CopyEffects::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panoram copy.push_constant.target[0] = 0; copy.push_constant.target[1] = 0; copy.push_constant.camera_z_far = p_lod; + copy.push_constant.octmap_border_size[0] = p_source_octmap_border_size.x; + copy.push_constant.octmap_border_size[1] = p_source_octmap_border_size.y; - copy.push_constant.luminance_multiplier = prefer_raster_effects ? 2.0 : 1.0; + // TODO, if this is needed at the copy stage, then we need to pass in the multiplier. + copy.push_constant.luminance_multiplier = raster_effects.has_flag(RASTER_EFFECT_COPY) ? 2.0 : 1.0; // setup our uniforms RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - RD::Uniform u_source_cube(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_cube })); + RD::Uniform u_source_octmap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_octmap })); RD::Uniform u_dest_panorama(RD::UNIFORM_TYPE_IMAGE, 0, p_dest_panorama); - CopyMode mode = p_is_array ? COPY_MODE_CUBE_ARRAY_TO_PANORAMA : COPY_MODE_CUBE_TO_PANORAMA; + CopyMode mode = p_is_array ? COPY_MODE_OCTMAP_ARRAY_TO_PANORAMA : COPY_MODE_OCTMAP_TO_PANORAMA; RID shader = copy.shader.version_get_shader(copy.shader_version, mode); ERR_FAIL_COND(shader.is_null()); RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid()); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cube), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_octmap), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_panorama), 3); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_panorama_size.width, p_panorama_size.height, 1); @@ -561,7 +569,7 @@ void CopyEffects::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuff RD::get_singleton()->draw_list_draw(draw_list, true); } -void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one, bool p_linear, bool p_normal, const Rect2 &p_src_rect) { +void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one, bool p_linear, bool p_normal, const Rect2 &p_src_rect, float p_linear_luminance_multiplier) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -586,10 +594,8 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_ALPHA_TO_ONE; } if (p_linear) { - // Used for copying to a linear buffer. In the mobile renderer we divide the contents of the linear buffer - // to allow for a wider effective range. copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_LINEAR; - copy_to_fb.push_constant.luminance_multiplier = prefer_raster_effects ? 2.0 : 1.0; + copy_to_fb.push_constant.luminance_multiplier = p_linear_luminance_multiplier; } if (p_normal) { @@ -633,7 +639,7 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe RD::get_singleton()->draw_list_end(); } -void CopyEffects::copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear) { +void CopyEffects::copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear, float p_linear_luminance_multiplier) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -643,10 +649,8 @@ void CopyEffects::copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFo copy_to_fb.push_constant.luminance_multiplier = 1.0; if (p_linear) { - // Used for copying to a linear buffer. In the mobile renderer we divide the contents of the linear buffer - // to allow for a wider effective range. copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_LINEAR; - copy_to_fb.push_constant.luminance_multiplier = prefer_raster_effects ? 2.0 : 1.0; + copy_to_fb.push_constant.luminance_multiplier = p_linear_luminance_multiplier; } // setup our uniforms @@ -668,7 +672,7 @@ void CopyEffects::copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFo } void CopyEffects::copy_raster(RID p_source_texture, RID p_dest_framebuffer) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the copy with the clustered renderer."); + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_COPY), "Can't use the raster version of the copy."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -696,7 +700,7 @@ void CopyEffects::copy_raster(RID p_source_texture, RID p_dest_framebuffer) { } void CopyEffects::gaussian_blur(RID p_source_rd_texture, RID p_texture, const Rect2i &p_region, const Size2i &p_size, bool p_8bit_dst) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian blur with the mobile renderer."); + ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_GAUSSIAN_BLUR), "Can't use the compute version of the gaussian blur."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -735,7 +739,7 @@ void CopyEffects::gaussian_blur(RID p_source_rd_texture, RID p_texture, const Re } void CopyEffects::gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_region, const Size2i &p_size) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian blur with the clustered renderer."); + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_GAUSSIAN_BLUR), "Can't use the raster version of the gaussian blur."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -770,7 +774,7 @@ void CopyEffects::gaussian_blur_raster(RID p_source_rd_texture, RID p_dest_textu } void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_scale) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian glow with the mobile renderer."); + ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_GAUSSIAN_BLUR), "Can't use the compute version of the gaussian glow."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -821,7 +825,7 @@ void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, con } void CopyEffects::gaussian_glow_downsample_raster(RID p_source_rd_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer."); + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_GAUSSIAN_BLUR), "Can't use the raster version of the gaussian glow."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -864,7 +868,7 @@ void CopyEffects::gaussian_glow_downsample_raster(RID p_source_rd_texture, RID p } void CopyEffects::gaussian_glow_upsample_raster(RID p_source_rd_texture, RID p_dest_texture, RID p_blend_texture, float p_luminance_multiplier, const Size2i &p_source_size, const Size2i &p_dest_size, float p_level, float p_base_strength, bool p_use_debanding) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer."); + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_GAUSSIAN_BLUR), "Can't use the raster version of the gaussian glow."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -908,7 +912,7 @@ void CopyEffects::gaussian_glow_upsample_raster(RID p_source_rd_texture, RID p_d } void CopyEffects::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the make_mipmap shader with the mobile renderer."); + ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_COPY), "Can't use the compute version of the make_mipmap shader."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -942,7 +946,7 @@ void CopyEffects::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const } void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of mipmap with the clustered renderer."); + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_COPY), "Can't use the raster version of mipmap."); RID dest_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_dest_texture); @@ -976,7 +980,7 @@ void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture } void CopyEffects::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the set_color shader with the mobile renderer."); + ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_COPY), "Can't use the compute version of the set_color shader."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -1010,7 +1014,7 @@ void CopyEffects::set_color(RID p_dest_texture, const Color &p_color, const Rect } void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, const Rect2i &p_region) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the set_color shader with the clustered renderer."); + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_COPY), "Can't use the raster version of the set_color shader."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); @@ -1078,85 +1082,131 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf RD::get_singleton()->draw_list_end(); } -void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer."); +void CopyEffects::copy_cubemap_to_octmap(RID p_source_rd_texture, RID p_dst_framebuffer, float p_border_size) { + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + RID shader = cube_to_octmap.shader.version_get_shader(cube_to_octmap.shader_version, 0); + ERR_FAIL_COND(shader.is_null()); + + cube_to_octmap.push_constant.border_size = 1.0f - p_border_size * 2.0f; + + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_rd_texture })); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_octmap.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &cube_to_octmap.push_constant, sizeof(CopyToOctmapPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +void CopyEffects::octmap_downsample(RID p_source_octmap, RID p_dest_octmap, const Size2i &p_size, bool p_use_filter_quality, float p_border_size) { + ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use compute based octmap downsample."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); - cubemap_downsampler.push_constant.face_size = p_size.x; - cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call + octmap_downsampler.push_constant.size = p_size.x; + octmap_downsampler.push_constant.border_size = 1.0f - p_border_size * 2.0f; // setup our uniforms RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_cubemap })); - RD::Uniform u_dest_cubemap(RD::UNIFORM_TYPE_IMAGE, 0, Vector({ p_dest_cubemap })); + RD::Uniform u_source_octmap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_octmap })); + RD::Uniform u_dest_octmap(RD::UNIFORM_TYPE_IMAGE, 0, Vector({ p_dest_octmap })); - RID shader = cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0); + RID shader = octmap_downsampler.compute_shader.version_get_shader(octmap_downsampler.shader_version, 0); ERR_FAIL_COND(shader.is_null()); + int pipeline_index = (!p_use_filter_quality || filter.use_high_quality) ? DOWNSAMPLER_MODE_HIGH_QUALITY : DOWNSAMPLER_MODE_LOW_QUALITY; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline.get_rid()); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_cubemap), 1); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, octmap_downsampler.compute_pipelines[pipeline_index].get_rid()); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_octmap), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_octmap), 1); int x_groups = Math::division_round_up(p_size.x, 8); int y_groups = Math::division_round_up(p_size.y, 8); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &octmap_downsampler.push_constant, sizeof(OctmapDownsamplerPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); RD::get_singleton()->compute_list_end(); } -void CopyEffects::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer."); - ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time."); +void CopyEffects::octmap_downsample_raster(RID p_source_octmap, RID p_dest_framebuffer, const Size2i &p_size, bool p_use_filter_quality, float p_border_size) { + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use raster based octmap downsample."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); - cubemap_downsampler.push_constant.face_size = p_size.x; - cubemap_downsampler.push_constant.face_id = p_face_id; + octmap_downsampler.push_constant.size = p_size.x; + octmap_downsampler.push_constant.border_size = 1.0f - p_border_size * 2.0f; // setup our uniforms RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_cubemap })); + RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_octmap })); - RID shader = cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0); + RID shader = octmap_downsampler.raster_shader.version_get_shader(octmap_downsampler.shader_version, 0); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + int pipeline_index = (!p_use_filter_quality || filter.use_high_quality) ? DOWNSAMPLER_MODE_HIGH_QUALITY : DOWNSAMPLER_MODE_LOW_QUALITY; + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::DRAW_IGNORE_COLOR_ALL); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, octmap_downsampler.raster_pipelines[pipeline_index].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &octmap_downsampler.push_constant, sizeof(OctmapDownsamplerPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u); RD::get_singleton()->draw_list_end(); } -void CopyEffects::cubemap_filter(RID p_source_cubemap, Vector p_dest_cubemap, bool p_use_array) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer."); +static constexpr int _compute_dispatch_size(bool p_use_array) { + constexpr int SIZE = 320; + constexpr int GROUP = 64; + constexpr int LEVELS = 6; // One less than Sky::REAL_TIME_ROUGHNESS_LAYERS. + int size = 0; + if (p_use_array) { + size = SIZE * SIZE * LEVELS; + } else { + int dim = SIZE; + for (int i = 0; i < LEVELS && dim >= 2; i++) { + size += dim * dim; + dim >>= 1; + } + } + + return (size + GROUP - 1) / GROUP; +} + +void CopyEffects::octmap_filter(RID p_source_octmap, const Vector &p_dest_octmap, bool p_use_array, float p_border_size) { + ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use compute based octmap filter."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); + OctmapFilterPushConstant push_constant; + push_constant.border_size[0] = p_border_size; + push_constant.border_size[1] = 1.0f - p_border_size * 2.0f; + push_constant.size = 320; + Vector uniforms; - for (int i = 0; i < p_dest_cubemap.size(); i++) { + for (int i = 0; i < p_dest_octmap.size(); i++) { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = i; - u.append_id(p_dest_cubemap[i]); + u.append_id(p_dest_octmap[i]); uniforms.push_back(u); } if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { @@ -1167,7 +1217,7 @@ void CopyEffects::cubemap_filter(RID p_source_cubemap, Vector p_dest_cubema // setup our uniforms RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_mipmap_sampler, p_source_cubemap })); + RD::Uniform u_source_octmap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_mipmap_sampler, p_source_octmap })); int mode = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY; mode = filter.use_high_quality ? mode : mode + 1; @@ -1177,68 +1227,69 @@ void CopyEffects::cubemap_filter(RID p_source_cubemap, Vector p_dest_cubema RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[mode].get_rid()); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_octmap), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2); - int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64 + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(OctmapFilterPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face + RD::get_singleton()->compute_list_dispatch(compute_list, _compute_dispatch_size(p_use_array), 1, 1); RD::get_singleton()->compute_list_end(); } -void CopyEffects::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer."); - ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time."); +void CopyEffects::octmap_filter_raster(RID p_source_octmap, RID p_dest_framebuffer, uint32_t p_mip_level, float p_border_size) { + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use raster based octmap filter."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); - // TODO implement! - CubemapFilterRasterPushConstant push_constant; + OctmapFilterRasterPushConstant push_constant; + push_constant.border_size[0] = p_border_size; + push_constant.border_size[1] = 1.0f - p_border_size * 2.0f; push_constant.mip_level = p_mip_level; - push_constant.face_id = p_face_id; // setup our uniforms RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_mipmap_sampler, p_source_cubemap })); + RD::Uniform u_source_octmap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_mipmap_sampler, p_source_octmap })); - CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY; + OctmapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY; RID shader = filter.raster_shader.version_get_shader(filter.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::DRAW_IGNORE_COLOR_ALL); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_octmap), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(OctmapFilterRasterPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u); RD::get_singleton()->draw_list_end(); } -void CopyEffects::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer."); +void CopyEffects::octmap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_sample_count, float p_roughness, uint32_t p_source_size, uint32_t p_dest_size, float p_border_size) { + ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use compute based octmap roughness."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); - memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); + memset(&roughness.push_constant, 0, sizeof(OctmapRoughnessPushConstant)); - roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; - // Remap to perceptual-roughness^2 to create more detail in lower mips and match the mapping of cubemap_filter. + // Remap to perceptual-roughness^2 to create more detail in lower mips and match the mapping of octmap_filter. roughness.push_constant.roughness = p_roughness * p_roughness; roughness.push_constant.sample_count = p_sample_count; + roughness.push_constant.source_size = p_source_size; + roughness.push_constant.dest_size = p_dest_size; roughness.push_constant.use_direct_write = p_roughness == 0.0; - roughness.push_constant.face_size = p_size; + roughness.push_constant.border_size[0] = p_border_size; + roughness.push_constant.border_size[1] = 1.0f - p_border_size * 2.0; // setup our uniforms RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); @@ -1255,32 +1306,33 @@ void CopyEffects::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_texture), 1); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(OctmapRoughnessPushConstant)); - int x_groups = Math::division_round_up(p_size, 8); + int x_groups = (p_dest_size + 7) / 8; int y_groups = x_groups; - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); RD::get_singleton()->compute_list_end(); } -void CopyEffects::cubemap_roughness_raster(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) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer."); - ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time."); +void CopyEffects::octmap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_sample_count, float p_roughness, uint32_t p_source_size, uint32_t p_dest_size, float p_border_size) { + ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use raster based octmap roughness."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); - memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); + memset(&roughness.push_constant, 0, sizeof(OctmapRoughnessPushConstant)); - roughness.push_constant.face_id = p_face_id; roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in. roughness.push_constant.sample_count = p_sample_count; + roughness.push_constant.source_size = p_source_size; + roughness.push_constant.dest_size = p_dest_size; roughness.push_constant.use_direct_write = p_roughness == 0.0; - roughness.push_constant.face_size = p_size; + roughness.push_constant.border_size[0] = p_border_size; + roughness.push_constant.border_size[1] = 1.0f - p_border_size * 2.0; // Setup our uniforms. RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); @@ -1290,11 +1342,11 @@ void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_f RID shader = roughness.raster_shader.version_get_shader(roughness.shader_version, 0); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::DRAW_IGNORE_COLOR_ALL); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(OctmapRoughnessPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u); RD::get_singleton()->draw_list_end(); diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index a9842fd261b..8bf9763f720 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -36,12 +36,13 @@ #include "servers/rendering/renderer_rd/shaders/effects/copy.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cube_to_octmap.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/octmap_downsampler_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/octmap_filter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/octmap_filter_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/octmap_roughness.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/octmap_roughness_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl.gen.h" #include "servers/rendering/renderer_scene_render.h" @@ -50,8 +51,15 @@ namespace RendererRD { class CopyEffects { +public: + enum RasterEffects { + RASTER_EFFECT_COPY = 1 << 0, + RASTER_EFFECT_GAUSSIAN_BLUR = 1 << 1, + RASTER_EFFECT_OCTMAP = 1 << 2, + }; + private: - bool prefer_raster_effects; + BitField raster_effects; // Blur raster shader @@ -115,8 +123,8 @@ private: COPY_MODE_SET_COLOR_8BIT, COPY_MODE_MIPMAP, COPY_MODE_LINEARIZE_DEPTH, - COPY_MODE_CUBE_TO_PANORAMA, - COPY_MODE_CUBE_ARRAY_TO_PANORAMA, + COPY_MODE_OCTMAP_TO_PANORAMA, + COPY_MODE_OCTMAP_ARRAY_TO_PANORAMA, COPY_MODE_MAX, }; @@ -152,7 +160,8 @@ private: // DOF. float camera_z_far; float camera_z_near; - uint32_t pad2[2]; + // Octmap. + float octmap_border_size[2]; //SET color float set_color[4]; }; @@ -224,24 +233,44 @@ private: PipelineCacheRD pipeline; } cube_to_dp; - // Cubemap effects + // Copy to Octmap - struct CubemapDownsamplerPushConstant { - uint32_t face_size; - uint32_t face_id; - float pad[2]; + struct CopyToOctmapPushConstant { + float border_size; + float pad[3]; }; - struct CubemapDownsampler { - CubemapDownsamplerPushConstant push_constant; - CubemapDownsamplerShaderRD compute_shader; - CubemapDownsamplerRasterShaderRD raster_shader; + struct CopyToOctmap { + CopyToOctmapPushConstant push_constant; + CubeToOctmapShaderRD shader; RID shader_version; - PipelineDeferredRD compute_pipeline; - PipelineCacheRD raster_pipeline; - } cubemap_downsampler; + PipelineCacheRD pipeline; + } cube_to_octmap; - enum CubemapFilterMode { + // Octmap effects + + struct OctmapDownsamplerPushConstant { + float border_size; + uint32_t size; + uint32_t pad[2]; + }; + + enum OctmapDownsamplerMode { + DOWNSAMPLER_MODE_LOW_QUALITY, + DOWNSAMPLER_MODE_HIGH_QUALITY, + DOWNSAMPLER_MODE_MAX + }; + + struct OctmapDownsampler { + OctmapDownsamplerPushConstant push_constant; + OctmapDownsamplerShaderRD compute_shader; + OctmapDownsamplerRasterShaderRD raster_shader; + RID shader_version; + PipelineDeferredRD compute_pipelines[DOWNSAMPLER_MODE_MAX]; + PipelineCacheRD raster_pipelines[DOWNSAMPLER_MODE_MAX]; + } octmap_downsampler; + + enum OctmapFilterMode { FILTER_MODE_HIGH_QUALITY, FILTER_MODE_LOW_QUALITY, FILTER_MODE_HIGH_QUALITY_ARRAY, @@ -249,15 +278,21 @@ private: FILTER_MODE_MAX, }; - struct CubemapFilterRasterPushConstant { - uint32_t mip_level; - uint32_t face_id; - float pad[2]; + struct OctmapFilterPushConstant { + float border_size[2]; + uint32_t size; + uint32_t pad; }; - struct CubemapFilter { - CubemapFilterShaderRD compute_shader; - CubemapFilterRasterShaderRD raster_shader; + struct OctmapFilterRasterPushConstant { + float border_size[2]; + uint32_t mip_level; + uint32_t pad; + }; + + struct OctmapFilter { + OctmapFilterShaderRD compute_shader; + OctmapFilterRasterShaderRD raster_shader; RID shader_version; PipelineDeferredRD compute_pipelines[FILTER_MODE_MAX]; PipelineCacheRD raster_pipelines[FILTER_MODE_MAX]; @@ -269,19 +304,21 @@ private: } filter; - struct CubemapRoughnessPushConstant { - uint32_t face_id; + struct OctmapRoughnessPushConstant { uint32_t sample_count; float roughness; + uint32_t source_size; + uint32_t dest_size; + + float border_size[2]; uint32_t use_direct_write; - float face_size; - float pad[3]; + uint32_t pad; }; - struct CubemapRoughness { - CubemapRoughnessPushConstant push_constant; - CubemapRoughnessShaderRD compute_shader; - CubemapRoughnessRasterShaderRD raster_shader; + struct OctmapRoughness { + OctmapRoughnessPushConstant push_constant; + OctmapRoughnessShaderRD compute_shader; + OctmapRoughnessRasterShaderRD raster_shader; RID shader_version; PipelineDeferredRD compute_pipeline; PipelineCacheRD raster_pipeline; @@ -319,18 +356,18 @@ private: public: static CopyEffects *get_singleton(); - CopyEffects(bool p_prefer_raster_effects); + CopyEffects(BitField p_raster_effects); ~CopyEffects(); - bool get_prefer_raster_effects() { return prefer_raster_effects; } + BitField get_raster_effects() { return raster_effects; } void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false, bool p_sanitize_inf_nan = false); - void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); + void copy_octmap_to_panorama(RID p_source_octmap, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array, const Size2 &p_source_octmap_border_size); void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); 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_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false, bool p_normal = false, const Rect2 &p_src_rect = Rect2()); + void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false, bool p_normal = false, const Rect2 &p_src_rect = Rect2(), float p_linear_luminance_multiplier = 1.0); 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 copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear = false); + void copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear = false, float p_linear_luminance_multiplier = 1.0); void copy_raster(RID p_source_texture, RID p_dest_framebuffer); void gaussian_blur(RID p_source_rd_texture, RID p_texture, const Rect2i &p_region, const Size2i &p_size, bool p_8bit_dst = false); @@ -346,13 +383,13 @@ public: void set_color_raster(RID p_dest_texture, const Color &p_color, const Rect2i &p_region); void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip); - void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); - void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size); - void cubemap_filter(RID p_source_cubemap, Vector p_dest_cubemap, bool p_use_array); - void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level); - - void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); - void cubemap_roughness_raster(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 copy_cubemap_to_octmap(RID p_source_rd_texture, RID p_dst_framebuffer, float p_border_size); + void octmap_downsample(RID p_source_octmap, RID p_dest_octmap, const Size2i &p_size, bool p_use_filter_quality, float p_border_size); + void octmap_downsample_raster(RID p_source_octmap, RID p_dest_framebuffer, const Size2i &p_size, bool p_use_filter_quality, float p_border_size); + void octmap_filter(RID p_source_octmap, const Vector &p_dest_octmap, bool p_use_array, float p_border_size); + void octmap_filter_raster(RID p_source_octmap, RID p_dest_framebuffer, uint32_t p_mip_level, float p_border_size); + void octmap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_sample_count, float p_roughness, uint32_t p_source_size, uint32_t p_dest_size, float p_border_size); + void octmap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_sample_count, float p_roughness, uint32_t p_source_size, uint32_t p_dest_size, float p_border_size); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection, uint32_t p_view_count); }; diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index af44ac4688f..a4d68d09511 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -211,7 +211,7 @@ void Fog::fog_instance_free(RID p_rid) { //////////////////////////////////////////////////////////////////////////////// // Volumetric Fog Shader -void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_layers, bool p_is_using_radiance_cubemap_array) { +void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_layers, bool p_is_using_radiance_octmap_array) { MaterialStorage *material_storage = MaterialStorage::get_singleton(); { @@ -302,8 +302,8 @@ ALBEDO = vec3(1.0); { String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(p_max_directional_lights) + "\n"; defines += "\n#define MAX_SKY_LOD " + itos(p_roughness_layers - 1) + ".0\n"; - if (p_is_using_radiance_cubemap_array) { - defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + if (p_is_using_radiance_octmap_array) { + defines += "\n#define USE_RADIANCE_OCTMAP_ARRAY \n"; } Vector volumetric_fog_modes; int shader_group = 0; @@ -977,7 +977,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 19; - RID radiance_texture = texture_storage->texture_rd_get_default(p_settings.is_using_radiance_cubemap_array ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RID radiance_texture = texture_storage->texture_rd_get_default(p_settings.is_using_radiance_octmap_array ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); RID sky_texture = RendererSceneRenderRD::get_singleton()->environment_get_sky(p_settings.env).is_valid() ? p_settings.sky->sky_get_radiance_texture_rd(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_settings.env)) : RID(); u.append_id(sky_texture.is_valid() ? sky_texture : radiance_texture); uniforms.push_back(u); @@ -1118,6 +1118,13 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P params.use_temporal_reprojection = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env); params.temporal_blend = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection_amount(p_settings.env); + RID sky_rid = RendererSceneRenderRD::get_singleton()->environment_get_sky(p_settings.env); + if (sky_rid.is_valid()) { + float uv_border_size = p_settings.sky->sky_get_uv_border_size(sky_rid); + params.sky_border_size[0] = uv_border_size; + params.sky_border_size[1] = 1.0f - uv_border_size * 2.0f; + } + { uint32_t cluster_size = p_settings.cluster_builder->get_cluster_size(); params.cluster_shift = get_shift_from_power_of_2(cluster_size); diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h index 478756aa335..db8e3352bc5 100644 --- a/servers/rendering/renderer_rd/environment/fog.h +++ b/servers/rendering/renderer_rd/environment/fog.h @@ -182,6 +182,9 @@ private: uint32_t temporal_frame; float temporal_blend; + float sky_border_size[2]; + float pad[2]; + float cam_rotation[12]; float to_prev_view[16]; float radiance_inverse_xform[12]; @@ -340,13 +343,13 @@ public: ~VolumetricFog(); }; - void init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_layers, bool p_is_using_radiance_cubemap_array); + void init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_layers, bool p_is_using_radiance_octmap_array); void free_fog_shader(); struct VolumetricFogSettings { Vector2i rb_size; double time; - bool is_using_radiance_cubemap_array; + bool is_using_radiance_octmap_array; uint32_t max_cluster_elements; bool volumetric_fog_filter_active; RID shadow_sampler; diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index f4dc14238f0..c32dc533031 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -1306,6 +1306,10 @@ void GI::SDFGI::update_probes(RID p_env, SkyRD::Sky *p_sky) { push_constant.image_size[1] = probe_axis_count; push_constant.store_ambient_texture = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_enabled(p_env); + const float sky_irradiance_border_size = p_sky != nullptr ? p_sky->uv_border_size : 0.0f; + push_constant.sky_irradiance_border_size[0] = sky_irradiance_border_size; + push_constant.sky_irradiance_border_size[1] = 1.0 - sky_irradiance_border_size * 2.0f; + RID sky_uniform_set = gi->sdfgi_shader.integrate_default_sky_uniform_set; push_constant.sky_flags = 0; push_constant.y_mult = y_mult; @@ -3521,8 +3525,8 @@ void GI::init(SkyRD *p_sky) { //calculate tables String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; - if (p_sky->sky_use_cubemap_array) { - defines += "\n#define USE_CUBEMAP_ARRAY\n"; + if (p_sky->sky_use_octmap_array) { + defines += "\n#define USE_OCTMAP_ARRAY\n"; } Vector integrate_modes; @@ -3544,10 +3548,10 @@ void GI::init(SkyRD *p_sky) { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; - if (p_sky->sky_use_cubemap_array) { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_WHITE)); + if (p_sky->sky_use_octmap_array) { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE)); } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); + u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE)); } uniforms.push_back(u); } diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index f2abda785ae..a46b44bd717 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -419,8 +419,9 @@ private: float sky_color_or_orientation[3]; float y_mult; + float sky_irradiance_border_size[2]; uint32_t store_ambient_texture; - uint32_t pad[3]; + uint32_t pad; }; SdfgiIntegrateShaderRD integrate; diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index d0480b6d33a..a876ad2915e 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -215,7 +215,7 @@ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_ar p_array[11] = 0; } -void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier, float p_brightness_multiplier) { +void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier, float p_brightness_multiplier, float p_border_size) { SkyPushConstant sky_push_constant; memset(&sky_push_constant, 0, sizeof(SkyPushConstant)); @@ -230,6 +230,8 @@ void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineC sky_push_constant.position[1] = p_position.y; sky_push_constant.position[2] = p_position.z; sky_push_constant.time = p_time; + sky_push_constant.border_size[0] = p_border_size; + sky_push_constant.border_size[1] = 1.0f - p_border_size * 2.0; sky_push_constant.luminance_multiplier = p_luminance_multiplier; sky_push_constant.brightness_multiplier = p_brightness_multiplier; store_transform_3x3(p_orientation, sky_push_constant.orientation); @@ -265,44 +267,41 @@ void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineC void SkyRD::ReflectionData::clear_reflection_data() { layers.clear(); - radiance_base_cubemap = RID(); - if (downsampled_radiance_cubemap.is_valid()) { - RD::get_singleton()->free_rid(downsampled_radiance_cubemap); + radiance_base_octmap = RID(); + if (downsampled_radiance_octmap.is_valid()) { + RD::get_singleton()->free_rid(downsampled_radiance_octmap); } - downsampled_radiance_cubemap = RID(); + downsampled_radiance_octmap = RID(); downsampled_layer.mipmaps.clear(); coefficient_buffer = RID(); } -void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format) { +void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format, float p_border_size) { //recreate radiance and all data int mipmaps = p_mipmaps; uint32_t w = p_size, h = p_size; - bool render_buffers_can_be_storage = RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage(); + bool use_raster_effect = RendererRD::CopyEffects::get_singleton()->get_raster_effects().has_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); + uv_border_size = p_border_size; if (p_use_array) { - int num_layers = p_low_quality ? 8 : p_roughness_layers; - + int num_layers = p_low_quality ? Sky::REAL_TIME_ROUGHNESS_LAYERS : p_roughness_layers; for (int i = 0; i < num_layers; i++) { ReflectionData::Layer layer; uint32_t mmw = w; uint32_t mmh = h; layer.mipmaps.resize(mipmaps); - layer.views.resize(mipmaps); for (int j = 0; j < mipmaps; j++) { - ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; + ReflectionData::Layer::Mipmap &mm = layer.mipmaps[j]; mm.size.width = mmw; mm.size.height = mmh; - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, 1, RD::TEXTURE_SLICE_CUBEMAP); + mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i, j); + + Vector fbtex; + fbtex.append(mm.view); + mm.framebuffer = RD::get_singleton()->framebuffer_create(fbtex); mmw = MAX(1u, mmw >> 1); mmh = MAX(1u, mmh >> 1); @@ -310,27 +309,22 @@ void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bo layers.push_back(layer); } - } else { - mipmaps = p_low_quality ? 8 : mipmaps; - //regular cubemap, lower quality (aliasing, less memory) + mipmaps = p_low_quality ? Sky::REAL_TIME_ROUGHNESS_LAYERS : mipmaps; + ReflectionData::Layer layer; uint32_t mmw = w; uint32_t mmh = h; layer.mipmaps.resize(mipmaps); - layer.views.resize(mipmaps); for (int j = 0; j < mipmaps; j++) { - ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; + ReflectionData::Layer::Mipmap &mm = layer.mipmaps[j]; mm.size.width = mmw; mm.size.height = mmh; - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } + mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j); - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, 1, RD::TEXTURE_SLICE_CUBEMAP); + Vector fbtex; + fbtex.push_back(mm.view); + mm.framebuffer = RD::get_singleton()->framebuffer_create(fbtex); mmw = MAX(1u, mmw >> 1); mmh = MAX(1u, mmh >> 1); @@ -339,43 +333,36 @@ void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bo layers.push_back(layer); } - radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, 1, RD::TEXTURE_SLICE_CUBEMAP); - RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap"); + radiance_base_octmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0); + RD::get_singleton()->set_resource_name(radiance_base_octmap, "Radiance Base Octmap"); RD::TextureFormat tf; tf.format = p_texture_format; - tf.width = p_low_quality ? 64 : p_size >> 1; // Always 64x64 when using REALTIME. - tf.height = p_low_quality ? 64 : p_size >> 1; - tf.texture_type = RD::TEXTURE_TYPE_CUBE; - tf.array_layers = 6; + tf.width = p_low_quality ? 160 : p_size >> 1; // Always 160x160 when using REALTIME. + tf.height = p_low_quality ? 160 : p_size >> 1; tf.mipmaps = p_low_quality ? 7 : mipmaps - 1; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - if (render_buffers_can_be_storage) { + if (!use_raster_effect) { tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; } - downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(downsampled_radiance_cubemap, "downsampled radiance cubemap"); + downsampled_radiance_octmap = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(downsampled_radiance_octmap, "Downsampled Radiance Octmap"); { uint32_t mmw = tf.width; uint32_t mmh = tf.height; downsampled_layer.mipmaps.resize(tf.mipmaps); - for (int j = 0; j < downsampled_layer.mipmaps.size(); j++) { - ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j]; + for (uint32_t j = 0; j < downsampled_layer.mipmaps.size(); j++) { + ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps[j]; mm.size.width = mmw; mm.size.height = mmh; - mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, 1, RD::TEXTURE_SLICE_CUBEMAP); - RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " "); - if (!render_buffers_can_be_storage) { - // we need a framebuffer for each side of our cubemap - - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, k, j); - RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip: " + itos(j) + " Face: " + itos(k) + " "); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } + mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_octmap, 0, j); + RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Octmap Mip " + itos(j) + " "); + if (use_raster_effect) { + // We need a framebuffer for the octmap. + Vector fbtex; + fbtex.push_back(mm.view); + mm.framebuffer = RD::get_singleton()->framebuffer_create(fbtex); } mmw = MAX(1u, mmw >> 1); @@ -387,125 +374,105 @@ void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bo void SkyRD::ReflectionData::create_reflection_fast_filter(bool p_use_arrays) { RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialized"); - bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); + bool use_raster_effect = copy_effects->get_raster_effects().has_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); - if (prefer_raster_effects) { + if (use_raster_effect) { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); - } + copy_effects->octmap_downsample_raster(radiance_base_octmap, downsampled_layer.mipmaps[0].framebuffer, downsampled_layer.mipmaps[0].size, true, uv_border_size); - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); - } + for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { + copy_effects->octmap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffer, downsampled_layer.mipmaps[i].size, true, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance if (p_use_arrays) { RD::get_singleton()->draw_command_begin_label("Filter Radiance Map into Array Heads"); - for (int i = 0; i < layers.size(); i++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i); - } + for (uint32_t i = 0; i < layers.size(); i++) { + copy_effects->octmap_filter_raster(downsampled_radiance_octmap, layers[i].mipmaps[0].framebuffer, i, uv_border_size); } } else { RD::get_singleton()->draw_command_begin_label("Filter Radiance Map into Mipmaps Directly"); - for (int j = 0; j < layers[0].mipmaps.size(); j++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j); - } + for (uint32_t j = 0; j < layers[0].mipmaps.size(); j++) { + copy_effects->octmap_filter_raster(downsampled_radiance_octmap, layers[0].mipmaps[j].framebuffer, j, uv_border_size); } } RD::get_singleton()->draw_command_end_label(); // Filter radiance } else { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + copy_effects->octmap_downsample(radiance_base_octmap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size, true, uv_border_size); - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { + copy_effects->octmap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size, true, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance Vector views; if (p_use_arrays) { - for (int i = 1; i < layers.size(); i++) { - views.push_back(layers[i].views[0]); + for (uint32_t i = 1; i < layers.size(); i++) { + views.push_back(layers[i].mipmaps[0].view); } } else { - for (int i = 1; i < layers[0].views.size(); i++) { - views.push_back(layers[0].views[i]); + for (uint32_t i = 1; i < layers[0].mipmaps.size(); i++) { + views.push_back(layers[0].mipmaps[i].view); } } RD::get_singleton()->draw_command_begin_label("Fast Filter Radiance"); - copy_effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); + copy_effects->octmap_filter(downsampled_radiance_octmap, views, p_use_arrays, uv_border_size); RD::get_singleton()->draw_command_end_label(); // Filter radiance } } -void SkyRD::ReflectionData::create_reflection_importance_sample(bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) { +void SkyRD::ReflectionData::create_reflection_importance_sample(bool p_use_arrays, int p_base_layer, uint32_t p_sky_ggx_samples_quality) { RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialized"); - bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); + bool use_raster_effect = copy_effects->get_raster_effects().has_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); - if (prefer_raster_effects) { + if (use_raster_effect) { if (p_base_layer == 1) { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); - } + copy_effects->octmap_downsample_raster(radiance_base_octmap, downsampled_layer.mipmaps[0].framebuffer, downsampled_layer.mipmaps[0].size, false, uv_border_size); - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); - } + for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { + copy_effects->octmap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffer, downsampled_layer.mipmaps[i].size, false, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance } RD::get_singleton()->draw_command_begin_label("High Quality Filter Radiance"); if (p_use_arrays) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_roughness_raster( - downsampled_radiance_cubemap, - layers[p_base_layer].mipmaps[0].framebuffers[k], - k, - p_sky_ggx_samples_quality, - float(p_base_layer) / (layers.size() - 1.0), - layers[p_base_layer].mipmaps[0].size.x); - } + copy_effects->octmap_roughness_raster( + downsampled_radiance_octmap, + layers[p_base_layer].mipmaps[0].framebuffer, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers.size() - 1.0), + downsampled_layer.mipmaps[0].size.x, + layers[p_base_layer].mipmaps[0].size.x, + uv_border_size); } else { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_roughness_raster( - downsampled_radiance_cubemap, - layers[0].mipmaps[p_base_layer].framebuffers[k], - k, - p_sky_ggx_samples_quality, - float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), - layers[0].mipmaps[p_base_layer].size.x); - } + copy_effects->octmap_roughness_raster( + downsampled_radiance_octmap, + layers[0].mipmaps[p_base_layer].framebuffer, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), + downsampled_layer.mipmaps[0].size.x, + layers[0].mipmaps[p_base_layer].size.x, + uv_border_size); } } else { if (p_base_layer == 1) { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + copy_effects->octmap_downsample(radiance_base_octmap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size, false, uv_border_size); - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { + copy_effects->octmap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size, false, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance } RD::get_singleton()->draw_command_begin_label("High Quality Filter Radiance"); if (p_use_arrays) { - copy_effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); + copy_effects->octmap_roughness(downsampled_radiance_octmap, layers[p_base_layer].mipmaps[0].view, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), downsampled_layer.mipmaps[0].size.x, layers[p_base_layer].mipmaps[0].size.x, uv_border_size); } else { - copy_effects->cubemap_roughness( - downsampled_radiance_cubemap, - layers[0].views[p_base_layer], - p_cube_side, - p_sky_ggx_samples_quality, - float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), - layers[0].mipmaps[p_base_layer].size.x); + copy_effects->octmap_roughness(downsampled_radiance_octmap, layers[0].mipmaps[p_base_layer].view, p_sky_ggx_samples_quality, float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), downsampled_layer.mipmaps[0].size.x, layers[0].mipmaps[p_base_layer].size.x, uv_border_size); } } RD::get_singleton()->draw_command_end_label(); // Filter radiance @@ -514,21 +481,19 @@ void SkyRD::ReflectionData::create_reflection_importance_sample(bool p_use_array void SkyRD::ReflectionData::update_reflection_mipmaps(int p_start, int p_end) { RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialized"); - bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); + bool use_raster_effect = copy_effects->get_raster_effects().has_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); - RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps"); + RD::get_singleton()->draw_command_begin_label("Update Radiance Octmap Array Mipmaps"); for (int i = p_start; i < p_end; i++) { - for (int j = 0; j < layers[i].views.size() - 1; j++) { - RID view = layers[i].views[j]; + for (uint32_t j = 0; j < layers[i].mipmaps.size() - 1; j++) { + RID view = layers[i].mipmaps[j].view; Size2i size = layers[i].mipmaps[j + 1].size; - if (prefer_raster_effects) { - for (int k = 0; k < 6; k++) { - RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k]; - copy_effects->cubemap_downsample_raster(view, framebuffer, k, size); - } + if (use_raster_effect) { + RID framebuffer = layers[i].mipmaps[j + 1].framebuffer; + copy_effects->octmap_downsample_raster(view, framebuffer, size, false, uv_border_size); } else { - RID texture = layers[i].views[j + 1]; - copy_effects->cubemap_downsample(view, texture, size); + RID texture = layers[i].mipmaps[j + 1].view; + copy_effects->octmap_downsample(view, texture, size, false, uv_border_size); } } } @@ -568,7 +533,7 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade if (radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { u.append_id(radiance); } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK)); } uniforms.push_back(u); } @@ -576,11 +541,11 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; // half res - if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { - if (reflection.layers.size() && reflection.layers[0].views.size() >= 2 && reflection.layers[0].views[1].is_valid() && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { - u.append_id(reflection.layers[0].views[1]); + if (p_version >= SKY_TEXTURE_SET_OCTMAP) { + if (reflection.layers.size() && reflection.layers[0].mipmaps.size() >= 2 && reflection.layers[0].mipmaps[1].view.is_valid() && p_version != SKY_TEXTURE_SET_OCTMAP_HALF_RES) { + u.append_id(reflection.layers[0].mipmaps[1].view); } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK)); } } else { RID half_texture = p_render_buffers->has_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE) ? p_render_buffers->get_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE) : RID(); @@ -596,11 +561,11 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; // quarter res - if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { - if (reflection.layers.size() && reflection.layers[0].views.size() >= 3 && reflection.layers[0].views[2].is_valid() && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { - u.append_id(reflection.layers[0].views[2]); + if (p_version >= SKY_TEXTURE_SET_OCTMAP) { + if (reflection.layers.size() && reflection.layers[0].mipmaps.size() >= 3 && reflection.layers[0].mipmaps[2].view.is_valid() && p_version != SKY_TEXTURE_SET_OCTMAP_QUARTER_RES) { + u.append_id(reflection.layers[0].mipmaps[2].view); } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK)); } } else { RID quarter_texture = p_render_buffers->has_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE) ? p_render_buffers->get_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE) : RID(); @@ -623,9 +588,9 @@ bool SkyRD::Sky::set_radiance_size(int p_radiance_size) { } radiance_size = p_radiance_size; - if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { - WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); - radiance_size = 256; + if (mode == RS::SKY_MODE_REALTIME && radiance_size != REAL_TIME_SIZE) { + WARN_PRINT(vformat("Realtime Skies can only use a radiance size of %d. Radiance size will be set to %d internally.", REAL_TIME_SIZE, REAL_TIME_SIZE)); + radiance_size = REAL_TIME_SIZE; } if (radiance.is_valid()) { @@ -637,6 +602,10 @@ bool SkyRD::Sky::set_radiance_size(int p_radiance_size) { return true; } +int SkyRD::Sky::get_radiance_size() const { + return radiance_size; +} + bool SkyRD::Sky::set_mode(RS::SkyMode p_mode) { if (mode == p_mode) { return false; @@ -644,9 +613,9 @@ bool SkyRD::Sky::set_mode(RS::SkyMode p_mode) { mode = p_mode; - if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { - WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); - set_radiance_size(256); + if (mode == RS::SKY_MODE_REALTIME && radiance_size != REAL_TIME_SIZE) { + WARN_PRINT(vformat("Realtime Skies can only use a radiance size of %d. Radiance size will be set to %d internally.", REAL_TIME_SIZE, REAL_TIME_SIZE)); + set_radiance_size(REAL_TIME_SIZE); } if (radiance.is_valid()) { @@ -678,7 +647,7 @@ Ref SkyRD::Sky::bake_panorama(float p_energy, int p_roughness_layers, con tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView()); - copy_effects->copy_cubemap_to_panorama(radiance, rad_tex, p_size, p_roughness_layers, reflection.layers.size() > 1); + copy_effects->copy_octmap_to_panorama(radiance, rad_tex, p_size, p_roughness_layers, reflection.layers.size() > 1, Size2(uv_border_size, 1.0f - uv_border_size * 2.0)); Vector data = RD::get_singleton()->texture_get_data(rad_tex, 0); RD::get_singleton()->free_rid(rad_tex); @@ -726,13 +695,7 @@ RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_funcs(Ren SkyRD::SkyRD() { roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers"); sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"); - sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections"); -#if defined(MACOS_ENABLED) && defined(__x86_64__) - if (OS::get_singleton()->get_current_rendering_driver_name() == "vulkan" && RenderingDevice::get_singleton()->get_device_name().contains("Intel")) { - // Disable texture array reflections on macOS on Intel GPUs due to driver bugs. - sky_use_cubemap_array = false; - } -#endif + sky_use_octmap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections"); } void SkyRD::init() { @@ -1273,7 +1236,7 @@ void SkyRD::update_radiance_buffers(Ref p_render_buffers, RS::SkyMode sky_mode = sky->mode; if (sky_mode == RS::SKY_MODE_AUTOMATIC) { - if ((shader_data->uses_time || shader_data->uses_position) && sky->radiance_size == 256) { + if ((shader_data->uses_time || shader_data->uses_position) && sky->radiance_size == Sky::REAL_TIME_SIZE) { update_single_frame = true; sky_mode = RS::SKY_MODE_REALTIME; } else if (shader_data->uses_light || shader_data->ubo_size > 0) { @@ -1291,27 +1254,10 @@ void SkyRD::update_radiance_buffers(Ref p_render_buffers, sky_mode = RS::SKY_MODE_QUALITY; } - int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size(); + int max_processing_layer = sky_use_octmap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size(); - // Update radiance cubemap + // Update radiance octmap if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) { - static const Vector3 view_normals[6] = { - Vector3(+1, 0, 0), - Vector3(-1, 0, 0), - Vector3(0, +1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1) - }; - static const Vector3 view_up[6] = { - Vector3(0, -1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1), - Vector3(0, -1, 0), - Vector3(0, -1, 0) - }; - Projection cm; cm.set_perspective(90, 1, 0.01, 10.0); Projection correction; @@ -1322,20 +1268,18 @@ void SkyRD::update_radiance_buffers(Ref p_render_buffers, if (shader_data->uses_quarter_res && roughness_layers >= 3) { RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter-Resolution Cubemap"); - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_OCTMAP_QUARTER_RES]; Vector clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID cubemap_draw_list; + RD::DrawListID octmap_draw_list; - for (int i = 0; i < 6; i++) { - Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers); + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_OCTMAP_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers); + + octmap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffer, RD::DRAW_IGNORE_COLOR_ALL); + _render_sky(octmap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffer, pipeline, material->uniform_set, texture_uniform_set, cm, Basis(), p_global_pos, p_luminance_multiplier, p_brightness_multiplier, sky->uv_border_size); + RD::get_singleton()->draw_list_end(); - cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i]); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier, p_brightness_multiplier); - RD::get_singleton()->draw_list_end(); - } RD::get_singleton()->draw_command_end_label(); } else if (shader_data->uses_quarter_res && roughness_layers < 3) { ERR_PRINT_ED("Cannot use quarter res buffer in sky shader when roughness layers is less than 3. Please increase rendering/reflections/sky_reflections/roughness_layers."); @@ -1343,54 +1287,51 @@ void SkyRD::update_radiance_buffers(Ref p_render_buffers, if (shader_data->uses_half_res && roughness_layers >= 2) { RD::get_singleton()->draw_command_begin_label("Render Sky to Half-Resolution Cubemap"); - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_OCTMAP_HALF_RES]; Vector clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID cubemap_draw_list; - for (int i = 0; i < 6; i++) { - Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd, p_render_buffers); + RD::DrawListID octmap_draw_list; + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_OCTMAP_HALF_RES, sky_shader.default_shader_rd, p_render_buffers); + + octmap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffer, RD::DRAW_IGNORE_COLOR_ALL); + _render_sky(octmap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffer, pipeline, material->uniform_set, texture_uniform_set, cm, Basis(), p_global_pos, p_luminance_multiplier, p_brightness_multiplier, sky->uv_border_size); + RD::get_singleton()->draw_list_end(); - cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i]); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier, p_brightness_multiplier); - RD::get_singleton()->draw_list_end(); - } RD::get_singleton()->draw_command_end_label(); } else if (shader_data->uses_half_res && roughness_layers < 2) { ERR_PRINT_ED("Cannot use half res buffer in sky shader when roughness layers is less than 2. Please increase rendering/reflections/sky_reflections/roughness_layers."); } - RD::DrawListID cubemap_draw_list; - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; + RD::DrawListID octmap_draw_list; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_OCTMAP]; - RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap"); - for (int i = 0; i < 6; i++) { - Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd, p_render_buffers); + RD::get_singleton()->draw_command_begin_label("Render Sky Octmap"); + + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_OCTMAP, sky_shader.default_shader_rd, p_render_buffers); + + octmap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffer, RD::DRAW_IGNORE_COLOR_ALL, Vector(), 1.0f, 0, Rect2(), RDD::BreadcrumbMarker::SKY_PASS); + _render_sky(octmap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffer, pipeline, material->uniform_set, texture_uniform_set, cm, Basis(), p_global_pos, p_luminance_multiplier, p_brightness_multiplier, sky->uv_border_size); + RD::get_singleton()->draw_list_end(); - cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::DRAW_DEFAULT_ALL, Vector(), 1.0f, 0, Rect2(), RDD::BreadcrumbMarker::SKY_PASS | uint32_t(i)); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier, p_brightness_multiplier); - RD::get_singleton()->draw_list_end(); - } RD::get_singleton()->draw_command_end_label(); if (sky_mode == RS::SKY_MODE_REALTIME) { - sky->reflection.create_reflection_fast_filter(sky_use_cubemap_array); - if (sky_use_cubemap_array) { + sky->reflection.create_reflection_fast_filter(sky_use_octmap_array); + if (sky_use_octmap_array) { sky->reflection.update_reflection_mipmaps(0, sky->reflection.layers.size()); } } else { if (update_single_frame) { for (int i = 1; i < max_processing_layer; i++) { - sky->reflection.create_reflection_importance_sample(sky_use_cubemap_array, 10, i, sky_ggx_samples_quality); + sky->reflection.create_reflection_importance_sample(sky_use_octmap_array, i, sky_ggx_samples_quality); } - if (sky_use_cubemap_array) { + if (sky_use_octmap_array) { sky->reflection.update_reflection_mipmaps(0, sky->reflection.layers.size()); } } else { - if (sky_use_cubemap_array) { + if (sky_use_octmap_array) { // Multi-Frame so just update the first array level sky->reflection.update_reflection_mipmaps(0, 1); } @@ -1402,9 +1343,9 @@ void SkyRD::update_radiance_buffers(Ref p_render_buffers, } else { if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) { - sky->reflection.create_reflection_importance_sample(sky_use_cubemap_array, 10, sky->processing_layer, sky_ggx_samples_quality); + sky->reflection.create_reflection_importance_sample(sky_use_octmap_array, sky->processing_layer, sky_ggx_samples_quality); - if (sky_use_cubemap_array) { + if (sky_use_octmap_array) { sky->reflection.update_reflection_mipmaps(sky->processing_layer, sky->processing_layer + 1); } @@ -1480,10 +1421,7 @@ void SkyRD::update_res_buffers(Ref p_render_buffers, RID p RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers); - Vector clear_colors; - clear_colors.push_back(Color(0.0, 0.0, 0.0)); - - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::DRAW_CLEAR_ALL, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::DRAW_IGNORE_COLOR_ALL); _render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier, p_brightness_multiplier); RD::get_singleton()->draw_list_end(); } @@ -1499,10 +1437,7 @@ void SkyRD::update_res_buffers(Ref p_render_buffers, RID p RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd, p_render_buffers); - Vector clear_colors; - clear_colors.push_back(Color(0.0, 0.0, 0.0)); - - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::DRAW_CLEAR_ALL, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::DRAW_IGNORE_COLOR_ALL); _render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier, p_brightness_multiplier); RD::get_singleton()->draw_list_end(); } @@ -1580,6 +1515,7 @@ void SkyRD::invalidate_sky(Sky *p_sky) { } void SkyRD::update_dirty_skys() { + bool use_raster_effect = RendererRD::CopyEffects::get_singleton()->get_raster_effects().has_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); Sky *sky = dirty_sky_list; while (sky) { @@ -1591,50 +1527,59 @@ void SkyRD::update_dirty_skys() { if (sky->radiance.is_null()) { int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; - uint32_t w = sky->radiance_size, h = sky->radiance_size; int layers = roughness_layers; if (sky->mode == RS::SKY_MODE_REALTIME) { - layers = 8; - if (roughness_layers != 8) { - WARN_PRINT("When using the Real-Time sky update mode (or Automatic with a sky shader using \"TIME\"), \"rendering/reflections/sky_reflections/roughness_layers\" should be set to 8 in the project settings for best quality reflections."); + layers = Sky::REAL_TIME_ROUGHNESS_LAYERS; + if (roughness_layers != layers) { + WARN_PRINT(vformat("When using the Real-Time sky update mode (or Automatic with a sky shader using \"TIME\"), \"rendering/reflections/sky_reflections/roughness_layers\" should be set to %d in the project settings for best quality reflections.", Sky::REAL_TIME_ROUGHNESS_LAYERS)); } } - if (sky_use_cubemap_array) { - //array (higher quality, 6 times more memory) + if (sky_use_octmap_array) { + mipmaps -= 2; // reduce the number of mipmaps to keep the border size reasonable. + // Double size to approximate texel density of cubemaps + add border for proper filtering/mipmapping. + uint32_t padding_pixels = (1 << (mipmaps - 1)); + uint32_t w = sky->radiance_size * 2 + padding_pixels * 2; + uint32_t h = w; + sky->uv_border_size = float(padding_pixels) / float(w); + + // Array (higher quality, more memory). RD::TextureFormat tf; - tf.array_layers = layers * 6; + tf.array_layers = layers; tf.format = texture_format; - tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; tf.mipmaps = mipmaps; tf.width = w; tf.height = h; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { + if (!use_raster_effect) { tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; } sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); - + sky->reflection.update_reflection_data(w, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format, sky->uv_border_size); } else { - //regular cubemap, lower quality (aliasing, less memory) + // Double size to approximate texel density of cubemaps + add border for proper filtering/mipmapping. + uint32_t padding_pixels = (1 << (MIN(mipmaps, layers) - 1)); + uint32_t w = sky->radiance_size * 2 + padding_pixels * 2; + uint32_t h = w; + sky->uv_border_size = float(padding_pixels) / float(w); + + // Single texture (lower quality, less memory). RD::TextureFormat tf; - tf.array_layers = 6; tf.format = texture_format; - tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.mipmaps = MIN(mipmaps, layers); tf.width = w; tf.height = h; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { + if (!use_raster_effect) { tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; } sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); + sky->reflection.update_reflection_data(w, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format, sky->uv_border_size); } } @@ -1693,6 +1638,13 @@ void SkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { } } +int SkyRD::sky_get_radiance_size(RID p_sky) const { + Sky *sky = get_sky(p_sky); + ERR_FAIL_NULL_V(sky, 0); + + return sky->get_radiance_size(); +} + void SkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { Sky *sky = get_sky(p_sky); ERR_FAIL_NULL(sky); @@ -1726,3 +1678,10 @@ RID SkyRD::sky_get_radiance_texture_rd(RID p_sky) const { return sky->radiance; } + +float SkyRD::sky_get_uv_border_size(RID p_sky) { + Sky *sky = get_sky(p_sky); + ERR_FAIL_NULL_V(sky, 1.0); + + return sky->uv_border_size; +} diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h index 6c5dcb11aad..f562c002b6d 100644 --- a/servers/rendering/renderer_rd/environment/sky.h +++ b/servers/rendering/renderer_rd/environment/sky.h @@ -74,9 +74,9 @@ private: SKY_TEXTURE_SET_BACKGROUND, SKY_TEXTURE_SET_HALF_RES, SKY_TEXTURE_SET_QUARTER_RES, - SKY_TEXTURE_SET_CUBEMAP, - SKY_TEXTURE_SET_CUBEMAP_HALF_RES, - SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, + SKY_TEXTURE_SET_OCTMAP, + SKY_TEXTURE_SET_OCTMAP_HALF_RES, + SKY_TEXTURE_SET_OCTMAP_QUARTER_RES, SKY_TEXTURE_SET_MAX }; @@ -84,9 +84,9 @@ private: SKY_VERSION_BACKGROUND, SKY_VERSION_HALF_RES, SKY_VERSION_QUARTER_RES, - SKY_VERSION_CUBEMAP, - SKY_VERSION_CUBEMAP_HALF_RES, - SKY_VERSION_CUBEMAP_QUARTER_RES, + SKY_VERSION_OCTMAP, + SKY_VERSION_OCTMAP_HALF_RES, + SKY_VERSION_OCTMAP_QUARTER_RES, SKY_VERSION_BACKGROUND_MULTIVIEW, SKY_VERSION_HALF_RES_MULTIVIEW, @@ -100,7 +100,7 @@ private: float projection[4]; // 16 - 64 float position[3]; // 12 - 76 float time; // 4 - 80 - float pad[2]; // 8 - 88 + float border_size[2]; // 8 - 88 float luminance_multiplier; // 4 - 92 float brightness_multiplier; // 4 - 96 // 128 is the max size of a push constant. We can replace "pad" but we can't add any more. @@ -134,7 +134,7 @@ private: virtual ~SkyShaderData(); }; - void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier, float p_brightness_modifier); + void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier, float p_brightness_modifier, float p_border_size = 0.0); public: struct SkySceneState { @@ -186,12 +186,11 @@ public: struct ReflectionData { struct Layer { struct Mipmap { - RID framebuffers[6]; - RID views[6]; + RID framebuffer; + RID view; Size2i size; }; - Vector mipmaps; //per-face view - Vector views; // per-cubemap view + LocalVector mipmaps; }; struct DownsampleLayer { @@ -199,26 +198,27 @@ public: RID view; Size2i size; - // for mobile only - RID views[6]; - RID framebuffers[6]; + // Used only for the raster version. + RID octmap_view; + RID framebuffer; }; - Vector mipmaps; + LocalVector mipmaps; }; - RID radiance_base_cubemap; //cubemap for first layer, first cubemap - RID downsampled_radiance_cubemap; + RID radiance_base_octmap; + RID downsampled_radiance_octmap; DownsampleLayer downsampled_layer; RID coefficient_buffer; bool dirty = true; + float uv_border_size = 0.0; // Border size in UV space. - Vector layers; + LocalVector layers; void clear_reflection_data(); - void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format); + void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_oct, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format, float p_border_size); void create_reflection_fast_filter(bool p_use_arrays); - void create_reflection_importance_sample(bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality); + void create_reflection_importance_sample(bool p_use_arrays, int p_base_layer, uint32_t p_sky_ggx_samples_quality); void update_reflection_mipmaps(int p_start, int p_end); }; @@ -245,6 +245,9 @@ public: }; struct Sky { + static inline const int REAL_TIME_SIZE = 256; + static inline const int REAL_TIME_ROUGHNESS_LAYERS = 7; + RID radiance; RID quarter_res_pass; RID quarter_res_framebuffer; @@ -255,7 +258,8 @@ public: RID material; RID uniform_buffer; - int radiance_size = 256; + int radiance_size = REAL_TIME_SIZE; + float uv_border_size = 0.0; // Border size in UV space. RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC; @@ -265,7 +269,7 @@ public: Sky *dirty_list = nullptr; float baked_exposure = 1.0; - //State to track when radiance cubemap needs updating + // State to track when radiance octmap needs updating. SkyMaterialData *prev_material = nullptr; Vector3 prev_position; float prev_time; @@ -274,13 +278,14 @@ public: RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd, Ref p_render_buffers); bool set_radiance_size(int p_radiance_size); + int get_radiance_size() const; bool set_mode(RS::SkyMode p_mode); bool set_material(RID p_material); Ref bake_panorama(float p_energy, int p_roughness_layers, const Size2i &p_size); }; uint32_t sky_ggx_samples_quality; - bool sky_use_cubemap_array; + bool sky_use_octmap_array; Sky *dirty_sky_list = nullptr; mutable RID_Owner sky_owner; @@ -314,9 +319,11 @@ public: Sky *get_sky(RID p_sky) const; void free_sky(RID p_sky); void sky_set_radiance_size(RID p_sky, int p_radiance_size); + int sky_get_radiance_size(RID p_sky) const; void sky_set_mode(RID p_sky, RS::SkyMode p_mode); void sky_set_material(RID p_sky, RID p_material); Ref sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size); + float sky_get_uv_border_size(RID p_sky); }; } // namespace RendererRD diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index f0520dab038..1b8d65872c5 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1347,7 +1347,7 @@ void RenderForwardClustered::_update_volumetric_fog(Ref p_ RendererRD::Fog::VolumetricFogSettings settings; settings.rb_size = size; settings.time = time; - settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array(); + settings.is_using_radiance_octmap_array = is_using_radiance_octmap_array(); settings.max_cluster_elements = RendererRD::LightStorage::get_singleton()->get_max_cluster_elements(); settings.volumetric_fog_filter_active = get_volumetric_fog_filter_active(); @@ -3306,7 +3306,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend if (p_radiance_texture.is_valid()) { radiance_texture = p_radiance_texture; } else { - radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_octmap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); } RD::Uniform u; u.binding = 3; @@ -3672,7 +3672,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te } { // No radiance texture. - RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_octmap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); RD::Uniform u; u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; @@ -4436,13 +4436,13 @@ static RD::FramebufferFormatID _get_color_framebuffer_format_for_pipeline(RD::Da return RD::get_singleton()->framebuffer_format_create_multipass(attachments, passes, p_view_count); } -static RD::FramebufferFormatID _get_reflection_probe_color_framebuffer_format_for_pipeline() { +static RD::FramebufferFormatID _get_reflection_probe_color_framebuffer_format_for_pipeline(bool p_storage) { RD::AttachmentFormat attachment; thread_local Vector attachments; attachments.clear(); attachment.format = RendererRD::LightStorage::get_reflection_probe_color_format(); - attachment.usage_flags = RendererRD::LightStorage::get_reflection_probe_color_usage_bits(); + attachment.usage_flags = RendererRD::LightStorage::get_reflection_probe_color_usage_bits(p_storage); attachments.push_back(attachment); attachment.format = RendererRD::LightStorage::get_reflection_probe_depth_format(); @@ -4543,6 +4543,7 @@ void RenderForwardClustered::_mesh_compile_pipeline_for_surface(SceneShaderForwa void RenderForwardClustered::_mesh_compile_pipelines_for_surface(const SurfacePipelineData &p_surface, const GlobalPipelineData &p_global, RS::PipelineSource p_source, Vector *r_pipeline_pairs) { RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); + bool octmap_use_storage = !copy_effects->get_raster_effects().has_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); // Retrieve from the scene shader which groups are currently enabled. const bool multiview_enabled = p_global.use_multiview && scene_shader.is_multiview_shader_group_enabled(); @@ -4578,7 +4579,7 @@ void RenderForwardClustered::_mesh_compile_pipelines_for_surface(const SurfacePi pipeline_key.color_pass_flags |= SceneShaderForwardClustered::PIPELINE_COLOR_PASS_FLAG_MULTIVIEW; } else if (p_global.use_reflection_probes) { // Reflection probe can't be rendered in multiview. - pipeline_key.framebuffer_format_id = _get_reflection_probe_color_framebuffer_format_for_pipeline(); + pipeline_key.framebuffer_format_id = _get_reflection_probe_color_framebuffer_format_for_pipeline(octmap_use_storage); _mesh_compile_pipeline_for_surface(p_surface.shader, p_surface.mesh_surface, true, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs); } @@ -4978,8 +4979,8 @@ RenderForwardClustered::RenderForwardClustered() { { String defines; defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; - if (is_using_radiance_cubemap_array()) { - defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + if (is_using_radiance_octmap_array()) { + defines += "\n#define USE_RADIANCE_OCTMAP_ARRAY \n"; } defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index dc7e9a8bd34..012f339748c 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -495,7 +495,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ if (p_radiance_texture.is_valid()) { radiance_texture = p_radiance_texture; } else { - radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_octmap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); } RD::Uniform u; u.binding = 2; @@ -1226,7 +1226,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target()); bool convert_to_linear = !hdr_render_target; - copy_effects->copy_to_drawlist(draw_list, fb_format, texture, convert_to_linear); + copy_effects->copy_to_drawlist(draw_list, fb_format, texture, convert_to_linear, 2.0f); } } @@ -3137,13 +3137,13 @@ static RD::FramebufferFormatID _get_color_framebuffer_format_for_pipeline(RD::Da return RD::get_singleton()->framebuffer_format_create_multipass(attachments, passes, p_view_count, vrs_attachment); } -static RD::FramebufferFormatID _get_reflection_probe_color_framebuffer_format_for_pipeline() { +static RD::FramebufferFormatID _get_reflection_probe_color_framebuffer_format_for_pipeline(bool p_storage) { RD::AttachmentFormat attachment; thread_local Vector attachments; attachments.clear(); attachment.format = RendererRD::LightStorage::get_reflection_probe_color_format(); - attachment.usage_flags = RendererRD::LightStorage::get_reflection_probe_color_usage_bits(); + attachment.usage_flags = RendererRD::LightStorage::get_reflection_probe_color_usage_bits(p_storage); attachments.push_back(attachment); attachment.format = RendererRD::LightStorage::get_reflection_probe_depth_format(); @@ -3192,6 +3192,7 @@ void RenderForwardMobile::_mesh_compile_pipeline_for_surface(SceneShaderForwardM void RenderForwardMobile::_mesh_compile_pipelines_for_surface(const SurfacePipelineData &p_surface, const GlobalPipelineData &p_global, RS::PipelineSource p_source, Vector *r_pipeline_pairs) { RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); + bool octmap_use_storage = !copy_effects->get_raster_effects().has_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); // Set the attributes common to all pipelines. SceneShaderForwardMobile::ShaderData::PipelineKey pipeline_key; @@ -3241,7 +3242,7 @@ void RenderForwardMobile::_mesh_compile_pipelines_for_surface(const SurfacePipel if (p_global.use_reflection_probes) { pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS; - pipeline_key.framebuffer_format_id = _get_reflection_probe_color_framebuffer_format_for_pipeline(); + pipeline_key.framebuffer_format_id = _get_reflection_probe_color_framebuffer_format_for_pipeline(octmap_use_storage); _mesh_compile_pipeline_for_surface(p_surface.shader, p_surface.mesh_surface, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs); } @@ -3404,8 +3405,8 @@ RenderForwardMobile::RenderForwardMobile() { String defines; defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; - if (is_using_radiance_cubemap_array()) { - defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + if (is_using_radiance_octmap_array()) { + defines += "\n#define USE_RADIANCE_OCTMAP_ARRAY \n"; } // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index c3a5a36de77..0a7b65ffd40 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -113,14 +113,14 @@ Ref RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba RS::EnvironmentAmbientSource ambient_source = environment_get_ambient_source(p_env); bool use_ambient_light = false; - bool use_cube_map = false; + bool use_octmap = false; if (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && (environment_background == RS::ENV_BG_CLEAR_COLOR || environment_background == RS::ENV_BG_COLOR)) { use_ambient_light = true; } else { - use_cube_map = (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && environment_background == RS::ENV_BG_SKY) || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY; - use_ambient_light = use_cube_map || ambient_source == RS::ENV_AMBIENT_SOURCE_COLOR; + use_octmap = (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && environment_background == RS::ENV_BG_SKY) || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY; + use_ambient_light = use_octmap || ambient_source == RS::ENV_AMBIENT_SOURCE_COLOR; } - use_cube_map = use_cube_map || (environment_background == RS::ENV_BG_SKY && environment_get_sky(p_env).is_valid()); + use_octmap = use_octmap || (environment_background == RS::ENV_BG_SKY && environment_get_sky(p_env).is_valid()); Color ambient_color; float ambient_color_sky_mix = 0.0; @@ -134,7 +134,7 @@ Ref RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba ambient_color.b *= ambient_energy; } - if (use_cube_map) { + if (use_octmap) { Ref panorama = sky_bake_panorama(environment_get_sky(p_env), environment_get_bg_energy_multiplier(p_env), p_bake_irradiance, p_size); if (use_ambient_light && panorama.is_valid()) { for (int x = 0; x < p_size.width; x++) { @@ -1234,8 +1234,8 @@ int RendererSceneRenderRD::get_roughness_layers() const { return sky.roughness_layers; } -bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const { - return sky.sky_use_cubemap_array; +bool RendererSceneRenderRD::is_using_radiance_octmap_array() const { + return sky.sky_use_octmap_array; } void RendererSceneRenderRD::_update_vrs(Ref p_render_buffers) { @@ -1360,6 +1360,22 @@ void RendererSceneRenderRD::render_scene(const Ref &p_render scene_data.directional_shadow_pixel_size.y = 1.0 / directional_shadow_size; } + if (p_environment.is_valid()) { + RID sky_rid = environment_get_sky(p_environment); + if (sky_rid.is_valid()) { + int radiance_size = sky.sky_get_radiance_size(sky_rid); + scene_data.radiance_pixel_size = 1.0f / radiance_size; + float uv_border_size = sky.sky_get_uv_border_size(sky_rid); + scene_data.radiance_border_size = uv_border_size; + } + } + + if (p_reflection_atlas.is_valid()) { + float border_size = light_storage->reflection_atlas_get_border_size(p_reflection_atlas); + scene_data.reflection_atlas_border_size.x = border_size; + scene_data.reflection_atlas_border_size.y = 1.0f - border_size * 2.0; + } + scene_data.time = time; scene_data.time_step = time_step; } @@ -1659,7 +1675,7 @@ void RendererSceneRenderRD::init() { } if (is_volumetric_supported()) { - RendererRD::Fog::get_singleton()->init_fog_shader(RendererRD::LightStorage::get_singleton()->get_max_directional_lights(), get_roughness_layers(), is_using_radiance_cubemap_array()); + RendererRD::Fog::get_singleton()->init_fog_shader(RendererRD::LightStorage::get_singleton()->get_max_directional_lights(), get_roughness_layers(), is_using_radiance_octmap_array()); } RSG::camera_attributes->camera_attributes_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape")))); @@ -1690,8 +1706,20 @@ void RendererSceneRenderRD::init() { bool can_use_storage = _render_buffers_can_be_storage(); bool can_use_vrs = is_vrs_supported(); + BitField raster_effects = {}; + if (!can_use_storage) { + raster_effects.set_flag(RendererRD::CopyEffects::RASTER_EFFECT_COPY); + raster_effects.set_flag(RendererRD::CopyEffects::RASTER_EFFECT_GAUSSIAN_BLUR); + + // This path can be used in the future to redirect certain devices to use the raster version of the effect, either due to performance or driver errors. + bool use_raster_for_octmaps = false; + if (use_raster_for_octmaps) { + raster_effects.set_flag(RendererRD::CopyEffects::RASTER_EFFECT_OCTMAP); + } + } + bokeh_dof = memnew(RendererRD::BokehDOF(!can_use_storage)); - copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage)); + copy_effects = memnew(RendererRD::CopyEffects(raster_effects)); debug_effects = memnew(RendererRD::DebugEffects); luminance = memnew(RendererRD::Luminance(!can_use_storage)); smaa = memnew(RendererRD::SMAA); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 831140da357..266323e2c04 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -325,7 +325,7 @@ public: } int get_roughness_layers() const; - bool is_using_radiance_cubemap_array() const; + bool is_using_radiance_octmap_array() const; virtual TypedArray bake_render_uv2(RID p_base, const TypedArray &p_material_overrides, const Size2i &p_image_size) override; diff --git a/servers/rendering/renderer_rd/shaders/effects/copy.glsl b/servers/rendering/renderer_rd/shaders/effects/copy.glsl index f01c7ec7301..e831b12cd7a 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "../oct_inc.glsl" + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #define FLAG_HORIZONTAL (1 << 0) @@ -35,16 +37,17 @@ layout(push_constant, std430) uniform Params { // DOF. float camera_z_far; float camera_z_near; - uint pad2[2]; + // Octmap. + vec2 octmap_border_size; vec4 set_color; } params; -#ifdef MODE_CUBEMAP_ARRAY_TO_PANORAMA -layout(set = 0, binding = 0) uniform samplerCubeArray source_color; -#elif defined(MODE_CUBEMAP_TO_PANORAMA) -layout(set = 0, binding = 0) uniform samplerCube source_color; +#ifdef MODE_OCTMAP_ARRAY_TO_PANORAMA +layout(set = 0, binding = 0) uniform sampler2DArray source_color; +#elif defined(MODE_OCTMAP_TO_PANORAMA) +layout(set = 0, binding = 0) uniform sampler2D source_color; #elif !defined(MODE_SET_COLOR) layout(set = 0, binding = 0) uniform sampler2D source_color; #endif @@ -262,7 +265,7 @@ void main() { imageStore(dest_buffer, pos + params.target, color); #endif // MODE_LINEARIZE_DEPTH_COPY -#if defined(MODE_CUBEMAP_TO_PANORAMA) || defined(MODE_CUBEMAP_ARRAY_TO_PANORAMA) +#if defined(MODE_OCTMAP_TO_PANORAMA) || defined(MODE_OCTMAP_ARRAY_TO_PANORAMA) const float PI = 3.14159265359; vec2 uv = vec2(pos) / vec2(params.section.zw); @@ -277,13 +280,13 @@ void main() { normal.y = cos(theta); normal.z = cos(phi) * sin(theta) * -1.0; -#ifdef MODE_CUBEMAP_TO_PANORAMA - vec4 color = textureLod(source_color, normal, params.camera_z_far); //the biggest the lod the least the acne +#ifdef MODE_OCTMAP_TO_PANORAMA + vec4 color = textureLod(source_color, vec3_to_oct_with_border(normal, params.octmap_border_size), params.camera_z_far); //the biggest the lod the least the acne #else - vec4 color = textureLod(source_color, vec4(normal, params.camera_z_far), 0.0); //the biggest the lod the least the acne + vec4 color = textureLod(source_color, vec3(vec3_to_oct_with_border(normal, params.octmap_border_size), params.camera_z_far), 0.0); //the biggest the lod the least the acne #endif imageStore(dest_buffer, pos + params.target, color * params.luminance_multiplier); -#endif // defined(MODE_CUBEMAP_TO_PANORAMA) || defined(MODE_CUBEMAP_ARRAY_TO_PANORAMA) +#endif // defined(MODE_OCTMAP_TO_PANORAMA) || defined(MODE_OCTMAP_ARRAY_TO_PANORAMA) #ifdef MODE_SET_COLOR imageStore(dest_buffer, pos + params.target, params.set_color); diff --git a/servers/rendering/renderer_rd/shaders/effects/cube_to_octmap.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_octmap.glsl new file mode 100644 index 00000000000..faf62fa028c --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_octmap.glsl @@ -0,0 +1,36 @@ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +layout(location = 0) out vec2 uv_interp; + +void main() { + vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0)); + uv_interp = base_arr[gl_VertexIndex]; + gl_Position = vec4(uv_interp, 0.0, 1.0); +} + +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#include "../oct_inc.glsl" + +layout(location = 0) in vec2 uv_interp; +layout(location = 0) out vec4 frag_color; + +layout(set = 0, binding = 0) uniform samplerCube source_cube; + +layout(push_constant, std430) uniform Params { + float border_size; +} +params; + +void main() { + vec3 dir = oct_to_vec3_with_border(uv_interp * 0.5 + 0.5, params.border_size); + frag_color = vec4(texture(source_cube, dir).rgb, 1.0); +} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl deleted file mode 100644 index 63f0ce690e7..00000000000 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2016 Activision Publishing, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#[compute] - -#version 450 - -#VERSION_DEFINES - -#define BLOCK_SIZE 8 - -layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in; - -layout(set = 0, binding = 0) uniform samplerCube source_cubemap; - -layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap; - -#include "cubemap_downsampler_inc.glsl" - -void main() { - uvec3 id = gl_GlobalInvocationID; - uint face_size = params.face_size; - - if (id.x < face_size && id.y < face_size) { - float inv_face_size = 1.0 / float(face_size); - - float u0 = (float(id.x) * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0; - float u1 = (float(id.x) * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0; - - float v0 = (float(id.y) * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0; - float v1 = (float(id.y) * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0; - - float weights[4]; - weights[0] = calcWeight(u0, v0); - weights[1] = calcWeight(u1, v0); - weights[2] = calcWeight(u0, v1); - weights[3] = calcWeight(u1, v1); - - const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]); - for (int i = 0; i < 4; i++) { - weights[i] = weights[i] * wsum + .125; - } - - vec3 dir; - vec4 color; - switch (id.z) { - case 0: - get_dir_0(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_0(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_0(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_0(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 1: - get_dir_1(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_1(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_1(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_1(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 2: - get_dir_2(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_2(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_2(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_2(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 3: - get_dir_3(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_3(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_3(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_3(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 4: - get_dir_4(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_4(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_4(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_4(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - default: - get_dir_5(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_5(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_5(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_5(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - } - imageStore(dest_cubemap, ivec3(id), color); - } -} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl deleted file mode 100644 index 641e0906f5f..00000000000 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl +++ /dev/null @@ -1,48 +0,0 @@ -layout(push_constant, std430) uniform Params { - uint face_size; - uint face_id; // only used in raster shader -} -params; - -#define M_PI 3.14159265359 - -void get_dir_0(out vec3 dir, in float u, in float v) { - dir[0] = 1.0; - dir[1] = v; - dir[2] = -u; -} - -void get_dir_1(out vec3 dir, in float u, in float v) { - dir[0] = -1.0; - dir[1] = v; - dir[2] = u; -} - -void get_dir_2(out vec3 dir, in float u, in float v) { - dir[0] = u; - dir[1] = 1.0; - dir[2] = -v; -} - -void get_dir_3(out vec3 dir, in float u, in float v) { - dir[0] = u; - dir[1] = -1.0; - dir[2] = v; -} - -void get_dir_4(out vec3 dir, in float u, in float v) { - dir[0] = u; - dir[1] = v; - dir[2] = 1.0; -} - -void get_dir_5(out vec3 dir, in float u, in float v) { - dir[0] = -u; - dir[1] = v; - dir[2] = -1.0; -} - -float calcWeight(float u, float v) { - float val = u * u + v * v + 1.0; - return val * sqrt(val); -} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl deleted file mode 100644 index 6c77ab4a91f..00000000000 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2016 Activision Publishing, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -/* clang-format off */ -#[vertex] - -#version 450 - -#VERSION_DEFINES - -#include "cubemap_downsampler_inc.glsl" - -layout(location = 0) out vec2 uv_interp; -/* clang-format on */ - -void main() { - vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); - gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0); - uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0 * float(params.face_size); // saturate(x) * 2.0 -} - -/* clang-format off */ -#[fragment] - -#version 450 - -#VERSION_DEFINES - -#include "cubemap_downsampler_inc.glsl" - -layout(set = 0, binding = 0) uniform samplerCube source_cubemap; - -layout(location = 0) in vec2 uv_interp; -layout(location = 0) out vec4 frag_color; -/* clang-format on */ - -void main() { - // Converted from compute shader which uses absolute coordinates. - // Could possibly simplify this - float face_size = float(params.face_size); - float inv_face_size = 1.0 / face_size; - vec2 id = floor(uv_interp); - - float u1 = (id.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0; - float u0 = (id.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0; - - float v0 = (id.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0; - float v1 = (id.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0; - - float weights[4]; - weights[0] = calcWeight(u0, v0); - weights[1] = calcWeight(u1, v0); - weights[2] = calcWeight(u0, v1); - weights[3] = calcWeight(u1, v1); - - const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]); - for (int i = 0; i < 4; i++) { - weights[i] = weights[i] * wsum + .125; - } - - vec3 dir; - vec4 color; - switch (params.face_id) { - case 0: - get_dir_0(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_0(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_0(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_0(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 1: - get_dir_1(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_1(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_1(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_1(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 2: - get_dir_2(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_2(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_2(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_2(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 3: - get_dir_3(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_3(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_3(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_3(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - case 4: - get_dir_4(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_4(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_4(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_4(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - default: - get_dir_5(dir, u0, v0); - color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0]; - - get_dir_5(dir, u1, v0); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1]; - - get_dir_5(dir, u0, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2]; - - get_dir_5(dir, u1, v1); - color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3]; - break; - } - frag_color = color; -} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl deleted file mode 100644 index 10bf90e7344..00000000000 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2016 Activision Publishing, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#[compute] - -#version 450 - -#VERSION_DEFINES - -#define GROUP_SIZE 64 - -layout(local_size_x = GROUP_SIZE, local_size_y = 1, local_size_z = 1) in; - -layout(set = 0, binding = 0) uniform samplerCube source_cubemap; -layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly imageCube dest_cubemap0; -layout(rgba16f, set = 2, binding = 1) uniform restrict writeonly imageCube dest_cubemap1; -layout(rgba16f, set = 2, binding = 2) uniform restrict writeonly imageCube dest_cubemap2; -layout(rgba16f, set = 2, binding = 3) uniform restrict writeonly imageCube dest_cubemap3; -layout(rgba16f, set = 2, binding = 4) uniform restrict writeonly imageCube dest_cubemap4; -layout(rgba16f, set = 2, binding = 5) uniform restrict writeonly imageCube dest_cubemap5; -layout(rgba16f, set = 2, binding = 6) uniform restrict writeonly imageCube dest_cubemap6; - -#ifdef USE_HIGH_QUALITY -#define NUM_TAPS 32 -#else -#define NUM_TAPS 8 -#endif - -#define BASE_RESOLUTION 128 - -#ifdef USE_HIGH_QUALITY -layout(set = 1, binding = 0, std430) buffer restrict readonly Data { - vec4[7][5][3][24] coeffs; -} -data; -#else -layout(set = 1, binding = 0, std430) buffer restrict readonly Data { - vec4[7][5][6] coeffs; -} -data; -#endif - -void get_dir(out vec3 dir, in vec2 uv, in uint face) { - switch (face) { - case 0: - dir = vec3(1.0, uv[1], -uv[0]); - break; - case 1: - dir = vec3(-1.0, uv[1], uv[0]); - break; - case 2: - dir = vec3(uv[0], 1.0, -uv[1]); - break; - case 3: - dir = vec3(uv[0], -1.0, uv[1]); - break; - case 4: - dir = vec3(uv[0], uv[1], 1.0); - break; - default: - dir = vec3(-uv[0], uv[1], -1.0); - break; - } -} - -void main() { - // INPUT: - // id.x = the linear address of the texel (ignoring face) - // id.y = the face - // -> use to index output texture - // id.x = texel x - // id.y = texel y - // id.z = face - uvec3 id = gl_GlobalInvocationID; - - // determine which texel this is -#ifndef USE_TEXTURE_ARRAY - // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name. - int mip_level = 0; - if (id.x < (128 * 128)) { - mip_level = 0; - } else if (id.x < (128 * 128 + 64 * 64)) { - mip_level = 1; - id.x -= (128 * 128); - } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32)) { - mip_level = 2; - id.x -= (128 * 128 + 64 * 64); - } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16)) { - mip_level = 3; - id.x -= (128 * 128 + 64 * 64 + 32 * 32); - } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8)) { - mip_level = 4; - id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16); - } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4)) { - mip_level = 5; - id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8); - } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4 + 2 * 2)) { - mip_level = 6; - id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4); - } else { - return; - } - int res = BASE_RESOLUTION >> mip_level; -#else // Using Texture Arrays so all levels are the same resolution - int res = BASE_RESOLUTION; - int mip_level = int(id.x / (BASE_RESOLUTION * BASE_RESOLUTION)); - id.x -= mip_level * BASE_RESOLUTION * BASE_RESOLUTION; -#endif - - // determine dir / pos for the texel - vec3 dir, adir, frameZ; - { - id.z = id.y; - id.y = id.x / res; - id.x -= id.y * res; - - vec2 uv; - uv.x = (float(id.x) * 2.0 + 1.0) / float(res) - 1.0; - uv.y = -(float(id.y) * 2.0 + 1.0) / float(res) + 1.0; - - get_dir(dir, uv, id.z); - frameZ = normalize(dir); - - adir = abs(dir); - } - - // GGX gather colors - vec4 color = vec4(0.0); - for (int axis = 0; axis < 3; axis++) { - const int otherAxis0 = 1 - (axis & 1) - (axis >> 1); - const int otherAxis1 = 2 - (axis >> 1); - - float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25; - if (frameweight > 0.0) { - // determine frame - vec3 UpVector; - switch (axis) { - case 0: - UpVector = vec3(1, 0, 0); - break; - case 1: - UpVector = vec3(0, 1, 0); - break; - default: - UpVector = vec3(0, 0, 1); - break; - } - - vec3 frameX = normalize(cross(UpVector, frameZ)); - vec3 frameY = cross(frameZ, frameX); - - // calculate parametrization for polynomial - float Nx = dir[otherAxis0]; - float Ny = dir[otherAxis1]; - float Nz = adir[axis]; - - float NmaxXY = max(abs(Ny), abs(Nx)); - Nx /= NmaxXY; - Ny /= NmaxXY; - - float theta; - if (Ny < Nx) { - if (Ny <= -0.999) { - theta = Nx; - } else { - theta = Ny; - } - } else { - if (Ny >= 0.999) { - theta = -Nx; - } else { - theta = -Ny; - } - } - - float phi; - if (Nz <= -0.999) { - phi = -NmaxXY; - } else if (Nz >= 0.999) { - phi = NmaxXY; - } else { - phi = Nz; - } - - float theta2 = theta * theta; - float phi2 = phi * phi; - - // sample - for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) { - const int index = (NUM_TAPS / 4) * axis + iSuperTap; - -#ifdef USE_HIGH_QUALITY - vec4 coeffsDir0[3]; - vec4 coeffsDir1[3]; - vec4 coeffsDir2[3]; - vec4 coeffsLevel[3]; - vec4 coeffsWeight[3]; - - for (int iCoeff = 0; iCoeff < 3; iCoeff++) { - coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index]; - coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index]; - coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index]; - coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index]; - coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index]; - } - - for (int iSubTap = 0; iSubTap < 4; iSubTap++) { - // determine sample attributes (dir, weight, mip_level) - vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2); - - float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2; - - float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2; -#else - vec4 coeffsDir0 = data.coeffs[mip_level][0][index]; - vec4 coeffsDir1 = data.coeffs[mip_level][1][index]; - vec4 coeffsDir2 = data.coeffs[mip_level][2][index]; - vec4 coeffsLevel = data.coeffs[mip_level][3][index]; - vec4 coeffsWeight = data.coeffs[mip_level][4][index]; - - for (int iSubTap = 0; iSubTap < 4; iSubTap++) { - // determine sample attributes (dir, weight, mip_level) - vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap]; - - float sample_level = coeffsLevel[iSubTap]; - - float sample_weight = coeffsWeight[iSubTap]; -#endif - - sample_weight *= frameweight; - - // adjust for jacobian - sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2]))); - sample_level += 0.75 * log2(dot(sample_dir, sample_dir)); -#ifndef USE_TEXTURE_ARRAY - sample_level += float(mip_level) / 6.0; // Hack to increase the perceived roughness and reduce upscaling artifacts -#endif - // sample cubemap - color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight; - color.w += sample_weight; - } - } - } - } - color /= color.w; - - // write color - color.xyz = max(vec3(0.0), color.xyz); - color.w = 1.0; -#ifdef USE_TEXTURE_ARRAY - id.xy *= uvec2(2, 2); -#endif - - switch (mip_level) { - case 0: - imageStore(dest_cubemap0, ivec3(id), color); -#ifdef USE_TEXTURE_ARRAY - imageStore(dest_cubemap0, ivec3(id) + ivec3(1.0, 0.0, 0.0), color); - imageStore(dest_cubemap0, ivec3(id) + ivec3(0.0, 1.0, 0.0), color); - imageStore(dest_cubemap0, ivec3(id) + ivec3(1.0, 1.0, 0.0), color); -#endif - break; - case 1: - imageStore(dest_cubemap1, ivec3(id), color); -#ifdef USE_TEXTURE_ARRAY - imageStore(dest_cubemap1, ivec3(id) + ivec3(1.0, 0.0, 0.0), color); - imageStore(dest_cubemap1, ivec3(id) + ivec3(0.0, 1.0, 0.0), color); - imageStore(dest_cubemap1, ivec3(id) + ivec3(1.0, 1.0, 0.0), color); -#endif - break; - case 2: - imageStore(dest_cubemap2, ivec3(id), color); -#ifdef USE_TEXTURE_ARRAY - imageStore(dest_cubemap2, ivec3(id) + ivec3(1.0, 0.0, 0.0), color); - imageStore(dest_cubemap2, ivec3(id) + ivec3(0.0, 1.0, 0.0), color); - imageStore(dest_cubemap2, ivec3(id) + ivec3(1.0, 1.0, 0.0), color); -#endif - break; - case 3: - imageStore(dest_cubemap3, ivec3(id), color); -#ifdef USE_TEXTURE_ARRAY - imageStore(dest_cubemap3, ivec3(id) + ivec3(1.0, 0.0, 0.0), color); - imageStore(dest_cubemap3, ivec3(id) + ivec3(0.0, 1.0, 0.0), color); - imageStore(dest_cubemap3, ivec3(id) + ivec3(1.0, 1.0, 0.0), color); -#endif - break; - case 4: - imageStore(dest_cubemap4, ivec3(id), color); -#ifdef USE_TEXTURE_ARRAY - imageStore(dest_cubemap4, ivec3(id) + ivec3(1.0, 0.0, 0.0), color); - imageStore(dest_cubemap4, ivec3(id) + ivec3(0.0, 1.0, 0.0), color); - imageStore(dest_cubemap4, ivec3(id) + ivec3(1.0, 1.0, 0.0), color); -#endif - break; - case 5: - imageStore(dest_cubemap5, ivec3(id), color); -#ifdef USE_TEXTURE_ARRAY - imageStore(dest_cubemap5, ivec3(id) + ivec3(1.0, 0.0, 0.0), color); - imageStore(dest_cubemap5, ivec3(id) + ivec3(0.0, 1.0, 0.0), color); - imageStore(dest_cubemap5, ivec3(id) + ivec3(1.0, 1.0, 0.0), color); -#endif - break; - default: - imageStore(dest_cubemap6, ivec3(id), color); -#ifdef USE_TEXTURE_ARRAY - imageStore(dest_cubemap6, ivec3(id) + ivec3(1.0, 0.0, 0.0), color); - imageStore(dest_cubemap6, ivec3(id) + ivec3(0.0, 1.0, 0.0), color); - imageStore(dest_cubemap6, ivec3(id) + ivec3(1.0, 1.0, 0.0), color); -#endif - break; - } -} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl deleted file mode 100644 index 1d46f594085..00000000000 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl +++ /dev/null @@ -1,63 +0,0 @@ -#[compute] - -#version 450 - -#VERSION_DEFINES - -#define GROUP_SIZE 8 - -layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in; - -layout(set = 0, binding = 0) uniform samplerCube source_cube; - -layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap; - -#include "cubemap_roughness_inc.glsl" - -void main() { - uvec3 id = gl_GlobalInvocationID; - id.z += params.face_id; - - vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0); - vec3 N = texelCoordToVec(uv, id.z); - - if (params.use_direct_write) { - imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0)); - } else { - vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); - - float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size); - float roughness2 = params.roughness * params.roughness; - float roughness4 = roughness2 * roughness2; - vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - mat3 T; - T[0] = normalize(cross(UpVector, N)); - T[1] = cross(N, T[0]); - T[2] = N; - - for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) { - vec2 xi = Hammersley(sampleNum, params.sample_count); - - vec3 H = T * ImportanceSampleGGX(xi, roughness4); - float NdotH = dot(N, H); - vec3 L = (2.0 * NdotH * H - N); - - float ndotl = clamp(dot(N, L), 0.0, 1.0); - - if (ndotl > 0.0) { - float D = DistributionGGX(NdotH, roughness4); - float pdf = D * NdotH / (4.0 * NdotH) + 0.0001; - - float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001); - - float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel); - - sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl; - sum.a += ndotl; - } - } - sum /= sum.a; - - imageStore(dest_cubemap, ivec3(id), vec4(sum.rgb, 1.0)); - } -} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl deleted file mode 100644 index c0597fe3f3d..00000000000 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl +++ /dev/null @@ -1,84 +0,0 @@ -#define M_PI 3.14159265359 - -layout(push_constant, std430) uniform Params { - uint face_id; - uint sample_count; - float roughness; - bool use_direct_write; - float face_size; -} -params; - -vec3 texelCoordToVec(vec2 uv, uint faceID) { - mat3 faceUvVectors[6]; - - // -x - faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z - faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face - - // +x - faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z - faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face - - // -y - faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z - faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face - - // +y - faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z - faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face - - // -z - faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x - faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face - - // +z - faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face - - // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. - vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; - return normalize(result); -} - -vec3 ImportanceSampleGGX(vec2 xi, float roughness4) { - // Compute distribution direction - float Phi = 2.0 * M_PI * xi.x; - float CosTheta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y)); - float SinTheta = sqrt(1.0 - CosTheta * CosTheta); - - // Convert to spherical direction - vec3 H; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - return H; -} - -float DistributionGGX(float NdotH, float roughness4) { - float NdotH2 = NdotH * NdotH; - float denom = (NdotH2 * (roughness4 - 1.0) + 1.0); - denom = M_PI * denom * denom; - - return roughness4 / denom; -} - -float radicalInverse_VdC(uint bits) { - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10; // / 0x100000000 -} - -vec2 Hammersley(uint i, uint N) { - return vec2(float(i) / float(N), radicalInverse_VdC(i)); -} diff --git a/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl new file mode 100644 index 00000000000..729b37355c4 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl @@ -0,0 +1,83 @@ +// Copyright 2016 Activision Publishing, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define BLOCK_SIZE 8 + +#include "../oct_inc.glsl" + +layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D source_octmap; + +layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D dest_octmap; + +layout(push_constant, std430) uniform Params { + float border_size; + uint size; + uint pad; + uint pad2; +} +params; + +// Use an approximation of the Jacobian. +float calcWeight(float u, float v) { + vec3 d = oct_to_vec3_with_border(vec2(u, v), params.border_size); + return 1.0 / pow(abs(d.z) + 1.0, 3.0); +} + +void main() { + uvec2 id = gl_GlobalInvocationID.xy; + if (id.x < params.size && id.y < params.size) { + float inv_size = 1.0 / float(params.size); + uvec2 sample_id = id; + +#ifdef USE_HIGH_QUALITY + float u0 = (float(sample_id.x) * 2.0f + 1.0f - 0.75f) * inv_size - 1.0f; + float u1 = (float(sample_id.x) * 2.0f + 1.0f + 0.75f) * inv_size - 1.0f; + float v0 = (float(sample_id.y) * 2.0f + 1.0f - 0.75f) * inv_size - 1.0f; + float v1 = (float(sample_id.y) * 2.0f + 1.0f + 0.75f) * inv_size - 1.0f; + float weights[4]; + weights[0] = calcWeight(u0, v0); + weights[1] = calcWeight(u1, v0); + weights[2] = calcWeight(u0, v1); + weights[3] = calcWeight(u1, v1); + + const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]); + for (int i = 0; i < 4; i++) { + weights[i] = weights[i] * wsum + 0.125; + } + + vec4 color = textureLod(source_octmap, vec2(u0, v0) * 0.5f + 0.5f, 0.0) * weights[0]; + color += textureLod(source_octmap, vec2(u1, v0) * 0.5f + 0.5f, 0.0) * weights[1]; + color += textureLod(source_octmap, vec2(u0, v1) * 0.5f + 0.5f, 0.0) * weights[2]; + color += textureLod(source_octmap, vec2(u1, v1) * 0.5f + 0.5f, 0.0) * weights[3]; + imageStore(dest_octmap, ivec2(id), color); +#else + vec2 uv = (vec2(sample_id.xy) + 0.5) * inv_size; + imageStore(dest_octmap, ivec2(id), textureLod(source_octmap, uv, 0.0)); +#endif + } +} diff --git a/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler_raster.glsl new file mode 100644 index 00000000000..21c6a35c191 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler_raster.glsl @@ -0,0 +1,94 @@ +// Copyright 2016 Activision Publishing, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#include "../oct_inc.glsl" + +layout(push_constant, std430) uniform Params { + uint size; +} +params; + +layout(location = 0) out vec2 uv_interp; +/* clang-format on */ + +void main() { + vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); + gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0); + uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0 +} + +/* clang-format off */ +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#include "../oct_inc.glsl" + +layout(push_constant, std430) uniform Params { + uint size; +} +params; + +layout(set = 0, binding = 0) uniform sampler2D source_octmap; + +layout(location = 0) in vec2 uv_interp; +layout(location = 0) out vec4 frag_color; +/* clang-format on */ + +float calcWeight(float u, float v) { + float val = u * u + v * v + 1.0; + return val * sqrt(val); +} + +void main() { +#ifdef USE_HIGH_QUALITY + float inv_size = 1.0 / float(params.size); + float u0 = (uv_interp.x * 2.0f - 0.75) * inv_size - 1.0f; + float u1 = (uv_interp.x * 2.0f + 0.75) * inv_size - 1.0f; + float v0 = (uv_interp.y * 2.0f - 0.75) * inv_size - 1.0f; + float v1 = (uv_interp.y * 2.0f + 0.75) * inv_size - 1.0f; + float weights[4]; + weights[0] = calcWeight(u0, v0); + weights[1] = calcWeight(u1, v0); + weights[2] = calcWeight(u0, v1); + weights[3] = calcWeight(u1, v1); + + const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]); + for (int i = 0; i < 4; i++) { + weights[i] = weights[i] * wsum + 0.125; + } + + frag_color = textureLod(source_octmap, vec2(u0, v0) * 0.5f + 0.5f, 0.0) * weights[0]; + frag_color += textureLod(source_octmap, vec2(u1, v0) * 0.5f + 0.5f, 0.0) * weights[1]; + frag_color += textureLod(source_octmap, vec2(u0, v1) * 0.5f + 0.5f, 0.0) * weights[2]; + frag_color += textureLod(source_octmap, vec2(u1, v1) * 0.5f + 0.5f, 0.0) * weights[3]; +#else + frag_color = textureLod(source_octmap, uv_interp, 0.0); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/effects/octmap_filter.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_filter.glsl new file mode 100644 index 00000000000..7e1ce0af397 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_filter.glsl @@ -0,0 +1,258 @@ +// Copyright 2016 Activision Publishing, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define GROUP_SIZE 64 + +#include "../oct_inc.glsl" + +layout(local_size_x = GROUP_SIZE, local_size_y = 1, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D source_octmap; +layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_octmap0; +layout(rgba16f, set = 2, binding = 1) uniform restrict writeonly image2D dest_octmap1; +layout(rgba16f, set = 2, binding = 2) uniform restrict writeonly image2D dest_octmap2; +layout(rgba16f, set = 2, binding = 3) uniform restrict writeonly image2D dest_octmap3; +layout(rgba16f, set = 2, binding = 4) uniform restrict writeonly image2D dest_octmap4; +layout(rgba16f, set = 2, binding = 5) uniform restrict writeonly image2D dest_octmap5; + +#ifdef USE_HIGH_QUALITY +#define NUM_TAPS 32 +#else +#define NUM_TAPS 8 +#endif + +layout(push_constant, std430) uniform Params { + vec2 border_size; + vec2 pad; +} +params; + +#define BASE_RESOLUTION 320 + +#ifdef USE_HIGH_QUALITY +layout(set = 1, binding = 0, std430) buffer restrict readonly Data { + vec4[7][5][3][24] coeffs; +} +data; +#else +layout(set = 1, binding = 0, std430) buffer restrict readonly Data { + vec4[7][5][6] coeffs; +} +data; +#endif + +void main() { + // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name. + uvec2 id = gl_GlobalInvocationID.xy; + uint mip_level = 0; +#ifndef USE_TEXTURE_ARRAY + uint res = BASE_RESOLUTION; + while ((id.x >= (res * res)) && (res > 1)) { + id.x -= res * res; + res = res >> 1; + mip_level++; + } +#else // Using Texture Arrays so all levels are the same resolution + uint res = BASE_RESOLUTION; + mip_level = id.x / (BASE_RESOLUTION * BASE_RESOLUTION); + id.x -= mip_level * BASE_RESOLUTION * BASE_RESOLUTION; +#endif + // Determine the direction from the texel's position. + id.y = id.x / res; + id.x -= id.y * res; + + vec2 inv_res = 1.0 / vec2(res); + vec3 dir = oct_to_vec3_with_border((vec2(id.xy) + vec2(0.5)) * inv_res, params.border_size.y); + vec3 adir = abs(dir); + vec3 frameZ = dir; + + // Gather colors using GGX. + vec4 color = vec4(0.0); + for (int axis = 0; axis < 3; axis++) { + const int otherAxis0 = 1 - (axis & 1) - (axis >> 1); + const int otherAxis1 = 2 - (axis >> 1); + const float lowerBound = 0.57735; // 1 / sqrt(3), magnitude for each component on a vector where all the components are equal. + float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - lowerBound) / (1.0 - lowerBound); + if (frameweight > 0.0) { + // determine frame + vec3 UpVector; + switch (axis) { + case 0: + UpVector = vec3(1, 0, 0); + break; + case 1: + UpVector = vec3(0, 1, 0); + break; + default: + UpVector = vec3(0, 0, 1); + break; + } + + vec3 frameX = normalize(cross(UpVector, frameZ)); + vec3 frameY = cross(frameZ, frameX); + + // Calculate parametrization for polynomial. + float Nx = dir[otherAxis0]; + float Ny = dir[otherAxis1]; + float Nz = adir[axis]; + + float NmaxXY = max(abs(Ny), abs(Nx)); + Nx /= NmaxXY; + Ny /= NmaxXY; + + float theta; + if (Ny < Nx) { + if (Ny <= -0.999) { + theta = Nx; + } else { + theta = Ny; + } + } else { + if (Ny >= 0.999) { + theta = -Nx; + } else { + theta = -Ny; + } + } + + float phi; + if (Nz <= -0.999) { + phi = -NmaxXY; + } else if (Nz >= 0.999) { + phi = NmaxXY; + } else { + phi = Nz; + } + + float theta2 = theta * theta; + float phi2 = phi * phi; + + // Sample. The coefficient table was computed with less mip levels than required, so we clamp the maximum level. + uint coeff_mip_level = min(mip_level, 5); + for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) { + const int index = (NUM_TAPS / 4) * axis + iSuperTap; + +#ifdef USE_HIGH_QUALITY + vec4 coeffsDir0[3]; + vec4 coeffsDir1[3]; + vec4 coeffsDir2[3]; + vec4 coeffsLevel[3]; + vec4 coeffsWeight[3]; + + for (int iCoeff = 0; iCoeff < 3; iCoeff++) { + coeffsDir0[iCoeff] = data.coeffs[coeff_mip_level][0][iCoeff][index]; + coeffsDir1[iCoeff] = data.coeffs[coeff_mip_level][1][iCoeff][index]; + coeffsDir2[iCoeff] = data.coeffs[coeff_mip_level][2][iCoeff][index]; + coeffsLevel[iCoeff] = data.coeffs[coeff_mip_level][3][iCoeff][index]; + coeffsWeight[iCoeff] = data.coeffs[coeff_mip_level][4][iCoeff][index]; + } + + for (int iSubTap = 0; iSubTap < 4; iSubTap++) { + // Determine sample attributes (dir, weight, coeff_mip_level) + vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2); + + float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2; + + float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2; +#else + vec4 coeffsDir0 = data.coeffs[coeff_mip_level][0][index]; + vec4 coeffsDir1 = data.coeffs[coeff_mip_level][1][index]; + vec4 coeffsDir2 = data.coeffs[coeff_mip_level][2][index]; + vec4 coeffsLevel = data.coeffs[coeff_mip_level][3][index]; + vec4 coeffsWeight = data.coeffs[coeff_mip_level][4][index]; + + for (int iSubTap = 0; iSubTap < 4; iSubTap++) { + // determine sample attributes (dir, weight, coeff_mip_level) + vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap]; + + float sample_level = coeffsLevel[iSubTap]; + + float sample_weight = coeffsWeight[iSubTap]; +#endif + + sample_weight *= frameweight; + +#ifdef USE_HIGH_QUALITY + // Adjust for Jacobian. + sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2]))); + sample_level += 0.75 * log2(dot(sample_dir, sample_dir)); +#endif + +#ifndef USE_TEXTURE_ARRAY + sample_level += float(mip_level) / 5.0; // Hack to increase the perceived roughness and reduce upscaling artifacts +#endif + // Sample Octmap. + vec2 sample_uv = vec3_to_oct_with_border(normalize(sample_dir), params.border_size); + color.rgb += textureLod(source_octmap, sample_uv, sample_level).rgb * sample_weight; + color.a += sample_weight; + } + } + } + } + + // Write out the result. + color = vec4(max(vec3(0.0), color.rgb / color.a), 1.0); + +#ifdef USE_TEXTURE_ARRAY + id.xy *= uvec2(2, 2); +#endif + + if (mip_level > 5) { + return; + } + +#ifdef USE_TEXTURE_ARRAY +#define IMAGE_STORE(x) \ + imageStore(x, ivec2(id), color); \ + imageStore(x, ivec2(id) + ivec2(1, 0), color); \ + imageStore(x, ivec2(id) + ivec2(0, 1), color); \ + imageStore(x, ivec2(id) + ivec2(1, 1), color) +#else +#define IMAGE_STORE(x) imageStore(x, ivec2(id), color) +#endif + + switch (mip_level) { + case 0: + IMAGE_STORE(dest_octmap0); + break; + case 1: + IMAGE_STORE(dest_octmap1); + break; + case 2: + IMAGE_STORE(dest_octmap2); + break; + case 3: + IMAGE_STORE(dest_octmap3); + break; + case 4: + IMAGE_STORE(dest_octmap4); + break; + case 5: + default: + IMAGE_STORE(dest_octmap5); + break; + } +} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_filter_raster.glsl similarity index 76% rename from servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl rename to servers/rendering/renderer_rd/shaders/effects/octmap_filter_raster.glsl index 6bca3b8ef89..0ed75b5f3a1 100644 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_filter_raster.glsl @@ -26,8 +26,9 @@ #VERSION_DEFINES layout(push_constant, std430) uniform Params { + vec2 border_size; int mip_level; - uint face_id; + int pad; } params; @@ -35,9 +36,9 @@ layout(location = 0) out vec2 uv_interp; /* clang-format on */ void main() { - vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); - gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0); - uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0 + vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0)); + uv_interp = base_arr[gl_VertexIndex]; + gl_Position = vec4(uv_interp, 0.0, 1.0); } /* clang-format off */ @@ -47,13 +48,16 @@ void main() { #VERSION_DEFINES +#include "../oct_inc.glsl" + layout(push_constant, std430) uniform Params { + vec2 border_size; int mip_level; - uint face_id; + int pad; } params; -layout(set = 0, binding = 0) uniform samplerCube source_cubemap; +layout(set = 0, binding = 0) uniform sampler2D source_octmap; layout(location = 0) in vec2 uv_interp; layout(location = 0) out vec4 frag_color; @@ -66,8 +70,6 @@ layout(location = 0) out vec4 frag_color; #define NUM_TAPS 8 #endif -#define BASE_RESOLUTION 128 - #ifdef USE_HIGH_QUALITY layout(set = 1, binding = 0, std430) buffer restrict readonly Data { vec4[7][5][3][24] coeffs; @@ -80,67 +82,35 @@ layout(set = 1, binding = 0, std430) buffer restrict readonly Data { data; #endif -void get_dir(out vec3 dir, in vec2 uv, in uint face) { - switch (face) { - case 0: - dir = vec3(1.0, uv[1], -uv[0]); - break; - case 1: - dir = vec3(-1.0, uv[1], uv[0]); - break; - case 2: - dir = vec3(uv[0], 1.0, -uv[1]); - break; - case 3: - dir = vec3(uv[0], -1.0, uv[1]); - break; - case 4: - dir = vec3(uv[0], uv[1], 1.0); - break; - default: - dir = vec3(-uv[0], uv[1], -1.0); - break; - } -} - void main() { - // determine dir / pos for the texel - vec3 dir, adir, frameZ; - { - vec2 uv; - uv.x = uv_interp.x; - uv.y = 1.0 - uv_interp.y; - uv = uv * 2.0 - 1.0; - - get_dir(dir, uv, params.face_id); - frameZ = normalize(dir); - - adir = abs(dir); - } - - // determine which texel this is // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name. int mip_level = 0; - + vec2 uv = uv_interp * 0.5 + 0.5; if (params.mip_level < 0) { - // return as is - frag_color.rgb = textureLod(source_cubemap, frameZ, 0.0).rgb; + // Just copy the octmap directly. + frag_color.rgb = textureLod(source_octmap, uv, 0.0).rgb; frag_color.a = 1.0; return; - } else if (params.mip_level > 6) { - // maximum level - mip_level = 6; + } else if (params.mip_level > 5) { + // Limit the level. + mip_level = 5; } else { + // Use the level from the push constant. mip_level = params.mip_level; } - // GGX gather colors + // Determine the direction from the texel's position. + vec3 dir = oct_to_vec3_with_border(uv, params.border_size.y); + vec3 adir = abs(dir); + vec3 frameZ = dir; + + // Gather colors using GGX. vec4 color = vec4(0.0); for (int axis = 0; axis < 3; axis++) { const int otherAxis0 = 1 - (axis & 1) - (axis >> 1); const int otherAxis1 = 2 - (axis >> 1); - - float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25; + const float lowerBound = 0.57735; // 1 / sqrt(3), magnitude for each component on a vector where all the components are equal. + float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - lowerBound) / (1.0 - lowerBound); if (frameweight > 0.0) { // determine frame vec3 UpVector; @@ -195,7 +165,7 @@ void main() { float theta2 = theta * theta; float phi2 = phi * phi; - // sample + // Sample. for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) { const int index = (NUM_TAPS / 4) * axis + iSuperTap; @@ -239,21 +209,15 @@ void main() { sample_weight *= frameweight; - // adjust for jacobian - sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2]))); - sample_level += 0.75 * log2(dot(sample_dir, sample_dir)); - // sample cubemap - color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight; - color.w += sample_weight; + // Sample Octmap. + vec2 sample_uv = vec3_to_oct_with_border(normalize(sample_dir), params.border_size); + color.rgb += textureLod(source_octmap, sample_uv, sample_level).rgb * sample_weight; + color.a += sample_weight; } } } } - color /= color.w; - // write color - color.xyz = max(vec3(0.0), color.xyz); - color.w = 1.0; - - frag_color = color; + // Write out the result. + frag_color = vec4(max(vec3(0.0), color.rgb / color.a), 1.0); } diff --git a/servers/rendering/renderer_rd/shaders/effects/octmap_roughness.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_roughness.glsl new file mode 100644 index 00000000000..7b910d58406 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_roughness.glsl @@ -0,0 +1,64 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define GROUP_SIZE 8 + +layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D source_oct; + +layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D dest_octmap; + +#include "../oct_inc.glsl" +#include "octmap_roughness_inc.glsl" + +void main() { + uvec2 id = gl_GlobalInvocationID.xy; + if (id.x < params.dest_size && id.y < params.dest_size) { + vec2 inv_source_size = 1.0 / vec2(params.source_size); + vec2 inv_dest_size = 1.0 / vec2(params.dest_size); + vec2 uv = (vec2(id.xy) + 0.5) * inv_dest_size; + if (params.use_direct_write) { + imageStore(dest_octmap, ivec2(id), vec4(texture(source_oct, uv).rgb, 1.0)); + } else { + vec3 N = oct_to_vec3_with_border(uv, params.border_size.y); + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + float solid_angle_texel = 4.0 * M_PI / float(params.dest_size * params.dest_size); + float roughness2 = params.roughness * params.roughness; + float roughness4 = roughness2 * roughness2; + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + mat3 T; + T[0] = normalize(cross(UpVector, N)); + T[1] = cross(N, T[0]); + T[2] = N; + + for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) { + vec2 xi = Hammersley(sampleNum, params.sample_count); + + vec3 H = T * ImportanceSampleGGX(xi, roughness4); + float NdotH = dot(N, H); + vec3 L = (2.0 * NdotH * H - N); + + float ndotl = clamp(dot(N, L), 0.0, 1.0); + + if (ndotl > 0.0) { + float D = DistributionGGX(NdotH, roughness4); + float pdf = D * NdotH / (4.0 * NdotH) + 0.0001; + + float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001); + + float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel); + + vec2 sample_uv = vec3_to_oct_with_border(L, params.border_size); + sum.rgb += textureLod(source_oct, sample_uv, mipLevel).rgb * ndotl; + sum.a += ndotl; + } + } + + imageStore(dest_octmap, ivec2(id), vec4(sum.rgb / sum.a, 1.0)); + } + } +} diff --git a/servers/rendering/renderer_rd/shaders/effects/octmap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_roughness_inc.glsl new file mode 100644 index 00000000000..654ee269eca --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_roughness_inc.glsl @@ -0,0 +1,49 @@ +#define M_PI 3.14159265359 + +layout(push_constant, std430) uniform Params { + uint sample_count; + float roughness; + uint source_size; + uint dest_size; + + vec2 border_size; + bool use_direct_write; + uint pad; +} +params; + +vec3 ImportanceSampleGGX(vec2 xi, float roughness4) { + // Compute distribution direction + float Phi = 2.0 * M_PI * xi.x; + float CosTheta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y)); + float SinTheta = sqrt(1.0 - CosTheta * CosTheta); + + // Convert to spherical direction + vec3 H; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + return H; +} + +float DistributionGGX(float NdotH, float roughness4) { + float NdotH2 = NdotH * NdotH; + float denom = (NdotH2 * (roughness4 - 1.0) + 1.0); + denom = M_PI * denom * denom; + + return roughness4 / denom; +} + +float radicalInverse_VdC(uint bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N) { + return vec2(float(i) / float(N), radicalInverse_VdC(i)); +} diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_roughness_raster.glsl similarity index 72% rename from servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl rename to servers/rendering/renderer_rd/shaders/effects/octmap_roughness_raster.glsl index 05a20c459b9..e5a0efc407d 100644 --- a/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_roughness_raster.glsl @@ -5,7 +5,7 @@ #VERSION_DEFINES -#include "cubemap_roughness_inc.glsl" +#include "octmap_roughness_inc.glsl" layout(location = 0) out vec2 uv_interp; /* clang-format on */ @@ -23,26 +23,24 @@ void main() { #VERSION_DEFINES -#include "cubemap_roughness_inc.glsl" +#include "../oct_inc.glsl" +#include "octmap_roughness_inc.glsl" layout(location = 0) in vec2 uv_interp; -layout(set = 0, binding = 0) uniform samplerCube source_cube; +layout(set = 0, binding = 0) uniform sampler2D source_oct; layout(location = 0) out vec4 frag_color; /* clang-format on */ void main() { - vec3 N = texelCoordToVec(uv_interp * 2.0 - 1.0, params.face_id); - - //vec4 color = color_interp; - if (params.use_direct_write) { - frag_color = vec4(texture(source_cube, N).rgb, 1.0); + frag_color = vec4(texture(source_oct, uv_interp).rgb, 1.0); } else { + vec2 inv_size = 1.0 / vec2(params.size); + vec3 N = oct_to_vec3_with_border(uv_interp, params.border_size.y); vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); - - float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size); + float solid_angle_texel = 4.0 * M_PI / (params.size * params.size); float roughness2 = params.roughness * params.roughness; float roughness4 = roughness2 * roughness2; vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); @@ -68,12 +66,12 @@ void main() { float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel); - sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl; + vec2 sample_uv = vec3_to_oct_with_border(L, params.border_size); + sum.rgb += textureLod(source_oct, sample_uv, mipLevel).rgb * ndotl; sum.a += ndotl; } } - sum /= sum.a; - frag_color = vec4(sum.rgb, 1.0); + frag_color = vec4(sum.rgb / sum.a, 1.0); } } diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl index aaaa7dfb431..310bcd3fb4c 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "../oct_inc.glsl" + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #define MAX_CASCADES 8 @@ -40,10 +42,10 @@ layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_aver layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture; -#ifdef USE_CUBEMAP_ARRAY -layout(set = 1, binding = 0) uniform textureCubeArray sky_irradiance; +#ifdef USE_RADIANCE_OCTMAP_ARRAY +layout(set = 1, binding = 0) uniform texture2DArray sky_irradiance; #else -layout(set = 1, binding = 0) uniform textureCube sky_irradiance; +layout(set = 1, binding = 0) uniform texture2D sky_irradiance; #endif layout(set = 1, binding = 1) uniform sampler linear_sampler_mipmaps; @@ -75,8 +77,9 @@ layout(push_constant, std430) uniform Params { vec3 sky_color_or_orientation; float y_mult; + vec2 sky_irradiance_border_size; bool store_ambient_texture; - uint pad[3]; + uint pad; } params; @@ -271,10 +274,10 @@ void main() { vec4 sky_quat = vec4(params.sky_color_or_orientation, sky_sign * sqrt(1.0 - dot(params.sky_color_or_orientation, params.sky_color_or_orientation))); vec3 sky_dir = cross(sky_quat.xyz, ray_dir); sky_dir = ray_dir + ((sky_dir * sky_quat.w) + cross(sky_quat.xyz, sky_dir)) * 2.0; -#ifdef USE_CUBEMAP_ARRAY - light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(sky_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. +#ifdef USE_RADIANCE_OCTMAP_ARRAY + light.rgb = textureLod(sampler2DArray(sky_irradiance, linear_sampler_mipmaps), vec3(vec3_to_oct_with_border(sky_dir, params.sky_irradiance_border_size), 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #else - light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), sky_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. + light.rgb = textureLod(sampler2D(sky_irradiance, linear_sampler_mipmaps), vec3_to_oct_with_border(sky_dir, params.sky_irradiance_border_size), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #endif light.rgb *= params.sky_energy; light.a = 0.0; diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl index 55e2c538d3c..a34ead01911 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl @@ -29,6 +29,8 @@ void main() { #VERSION_DEFINES +#include "../oct_inc.glsl" + #ifdef USE_MULTIVIEW #extension GL_EXT_multiview : enable #define ViewIndex gl_ViewIndex @@ -43,7 +45,7 @@ layout(push_constant, std430) uniform Params { vec4 projection; // only applicable if not multiview vec3 position; float time; - vec2 pad; + vec2 border_size; float luminance_multiplier; float brightness_multiplier; } @@ -100,10 +102,10 @@ layout(set = 1, binding = 0, std140) uniform MaterialUniforms { /* clang-format on */ #endif -layout(set = 2, binding = 0) uniform textureCube radiance; +layout(set = 2, binding = 0) uniform texture2D radiance; #ifdef USE_CUBEMAP_PASS -layout(set = 2, binding = 1) uniform textureCube half_res; -layout(set = 2, binding = 2) uniform textureCube quarter_res; +layout(set = 2, binding = 1) uniform texture2D half_res; +layout(set = 2, binding = 2) uniform texture2D quarter_res; #elif defined(USE_MULTIVIEW) layout(set = 2, binding = 1) uniform texture2DArray half_res; layout(set = 2, binding = 2) uniform texture2DArray quarter_res; @@ -199,7 +201,11 @@ float atan2_approx(float y, float x) { } void main() { + vec2 uv = uv_interp * 0.5 + 0.5; vec3 cube_normal; +#ifdef USE_CUBEMAP_PASS + cube_normal = oct_to_vec3_with_border(uv, params.border_size.y); +#else #ifdef USE_MULTIVIEW // In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject. vec4 unproject = vec4(uv_interp.x, uv_interp.y, 0.0, 1.0); // unproject at the far plane @@ -215,8 +221,7 @@ void main() { #endif cube_normal = mat3(params.orientation) * cube_normal; cube_normal = normalize(cube_normal); - - vec2 uv = uv_interp * 0.5 + 0.5; +#endif vec2 panorama_coords = vec2(atan2_approx(cube_normal.x, -cube_normal.z), acos_approx(cube_normal.y)); @@ -235,10 +240,10 @@ void main() { #ifdef USE_CUBEMAP_PASS #ifdef USES_HALF_RES_COLOR - half_res_color = texture(samplerCube(half_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_normal) / params.luminance_multiplier; + half_res_color = texture(sampler2D(half_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3_to_oct_with_border(cube_normal, params.border_size)) / params.luminance_multiplier; #endif #ifdef USES_QUARTER_RES_COLOR - quarter_res_color = texture(samplerCube(quarter_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_normal) / params.luminance_multiplier; + quarter_res_color = texture(sampler2D(quarter_res, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3_to_oct_with_border(cube_normal, params.border_size)) / params.luminance_multiplier; #endif #else 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 3c26cd76e56..41bc6bf607d 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -16,6 +16,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #include "../cluster_data_inc.glsl" #include "../light_data_inc.glsl" +#include "../oct_inc.glsl" #define M_PI 3.14159265359 @@ -176,6 +177,9 @@ layout(set = 0, binding = 14, std140) uniform Params { uint temporal_frame; float temporal_blend; + vec2 sky_border_size; + vec2 pad; + mat3x4 cam_rotation; mat4 to_prev_view; @@ -201,10 +205,10 @@ layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map; layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map; #endif -#ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 0, binding = 19) uniform textureCubeArray sky_texture; +#ifdef USE_RADIANCE_OCTMAP_ARRAY +layout(set = 0, binding = 19) uniform texture2DArray sky_texture; #else -layout(set = 0, binding = 19) uniform textureCube sky_texture; +layout(set = 0, binding = 19) uniform texture2D sky_texture; #endif #endif // MODE_COPY @@ -429,13 +433,13 @@ void main() { if (params.sky_contribution > 0.0) { float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g); -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb; - anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb; +#ifdef USE_RADIANCE_OCTMAP_ARRAY + isotropic = texture(sampler2DArray(sky_texture, linear_sampler_with_mipmaps), vec3(vec3_to_oct_with_border(vec3(0.0, 1.0, 0.0), params.sky_border_size), mip_bias)).rgb; + anisotropic = texture(sampler2DArray(sky_texture, linear_sampler_with_mipmaps), vec3(vec3_to_oct_with_border(scatter_direction, params.sky_border_size), mip_bias)).rgb; #else - isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb; - anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY + isotropic = textureLod(sampler2D(sky_texture, linear_sampler_with_mipmaps), vec3_to_oct_with_border(vec3(0.0, 1.0, 0.0), params.sky_border_size), mip_bias).rgb; + anisotropic = textureLod(sampler2D(sky_texture, linear_sampler_with_mipmaps), vec3_to_oct_with_border(scatter_direction, params.sky_border_size), mip_bias).rgb; +#endif //USE_RADIANCE_OCTMAP_ARRAY } total_light += mix(params.ambient_color, mix(isotropic, anisotropic, abs(params.phase_g)), params.sky_contribution) * params.ambient_inject; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 19e90a926d1..eb1628d44b3 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -71,13 +71,6 @@ layout(location = 13) in vec4 previous_normal_attrib; #endif // MOTION_VECTORS -vec3 oct_to_vec3(vec2 e) { - vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); - float t = max(-v.z, 0.0); - v.xy += t * -sign(v.xy); - return normalize(v); -} - void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { float c = cos(angle); float s = sin(angle); @@ -1102,14 +1095,19 @@ vec4 fog_process(vec3 vertex) { vec3 cube_view = scene_data_block.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_block.data.z_near) / (scene_data_block.data.z_far - scene_data_block.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, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb; - sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend); +#ifdef USE_RADIANCE_OCTMAP_ARRAY + float roughness_lod, blend; + blend = modf(mip_level * MAX_ROUGHNESS_LOD, roughness_lod); + float cube_lod = vec3_to_oct_lod(dFdx(cube_view), dFdy(cube_view), scene_data_block.data.radiance_pixel_size); + vec2 cube_uv = vec3_to_oct_with_border(cube_view, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + vec3 sky_sample_a = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(cube_uv, roughness_lod), cube_lod).rgb; + vec3 sky_sample_b = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(cube_uv, roughness_lod + 1), cube_lod).rgb; + sky_fog_color = mix(sky_sample_a, sky_sample_b, blend); #else - sky_fog_color = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY + float roughness_lod = mip_level * MAX_ROUGHNESS_LOD; + vec2 cube_uv = vec3_to_oct_with_border(cube_view, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + sky_fog_color = textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_uv, roughness_lod).rgb; +#endif //USE_RADIANCE_OCTMAP_ARRAY fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective); } @@ -1693,18 +1691,24 @@ void fragment_shader(in SceneData scene_data) { float horizon = min(1.0 + dot(ref_vec, normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY +#ifdef USE_RADIANCE_OCTMAP_ARRAY - float lod, blend; + float roughness_lod, blend; - blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod); - indirect_specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; - indirect_specular_light = mix(indirect_specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); + blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, roughness_lod); + + float ref_lod = vec3_to_oct_lod(dFdx(ref_vec), dFdy(ref_vec), scene_data_block.data.radiance_pixel_size); + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + vec3 indirect_sample_a = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_uv, roughness_lod), ref_lod).rgb; + vec3 indirect_sample_b = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_uv, roughness_lod + 1), ref_lod).rgb; + indirect_specular_light = mix(indirect_sample_a, indirect_sample_b, blend); #else - indirect_specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb; + float roughness_lod = sqrt(roughness) * MAX_ROUGHNESS_LOD; + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + indirect_specular_light = textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_uv, roughness_lod).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY +#endif //USE_RADIANCE_OCTMAP_ARRAY indirect_specular_light *= scene_data.IBL_exposure_normalization; indirect_specular_light *= horizon * horizon; indirect_specular_light *= scene_data.ambient_light_color_energy.a; @@ -1721,11 +1725,15 @@ void fragment_shader(in SceneData scene_data) { if (bool(scene_data.flags & SCENE_DATA_FLAGS_USE_AMBIENT_CUBEMAP)) { vec3 ambient_dir = scene_data.radiance_inverse_xform * indirect_normal; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; +#ifdef USE_RADIANCE_OCTMAP_ARRAY + float ambient_lod = vec3_to_oct_lod(dFdx(ambient_dir), dFdy(ambient_dir), scene_data_block.data.radiance_pixel_size); + vec2 ambient_uv = vec3_to_oct_with_border(ambient_dir, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + vec3 cubemap_ambient = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ambient_uv, MAX_ROUGHNESS_LOD), ambient_lod).rgb; #else - vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY + float roughness_lod = MAX_ROUGHNESS_LOD; + vec2 ambient_uv = vec3_to_oct_with_border(ambient_dir, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + vec3 cubemap_ambient = textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_uv, roughness_lod).rgb; +#endif //USE_RADIANCE_OCTMAP_ARRAY cubemap_ambient *= scene_data.IBL_exposure_normalization; ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix); } @@ -1750,17 +1758,22 @@ void fragment_shader(in SceneData scene_data) { float horizon = min(1.0 + dot(ref_vec, indirect_normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; float roughness_lod = mix(0.001, 0.1, sqrt(clearcoat_roughness)) * MAX_ROUGHNESS_LOD; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY +#ifdef USE_RADIANCE_OCTMAP_ARRAY float lod, blend; blend = modf(roughness_lod, lod); - vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; - clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); + + float ref_lod = vec3_to_oct_lod(dFdx(ref_vec), dFdy(ref_vec), scene_data_block.data.radiance_pixel_size); + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + vec3 clearcoat_sample_a = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_uv, lod), ref_lod).rgb; + vec3 clearcoat_sample_b = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_uv, lod + 1), ref_lod).rgb; + vec3 clearcoat_light = mix(clearcoat_sample_a, clearcoat_sample_b, blend); #else - vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb; + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + vec3 clearcoat_light = textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_uv, roughness_lod).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY +#endif //USE_RADIANCE_OCTMAP_ARRAY indirect_specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; } #endif // LIGHT_CLEARCOAT_USED diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index d1eddfac71e..41f3b0a10d7 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -10,6 +10,7 @@ #include "../cluster_data_inc.glsl" #include "../decal_data_inc.glsl" +#include "../oct_inc.glsl" #include "../scene_data_inc.glsl" #if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) @@ -352,17 +353,17 @@ layout(set = 1, binding = 2, std430) buffer restrict readonly InstanceDataBuffer } instances; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY +#ifdef USE_RADIANCE_OCTMAP_ARRAY -layout(set = 1, binding = 3) uniform textureCubeArray radiance_cubemap; +layout(set = 1, binding = 3) uniform texture2DArray radiance_octmap; #else -layout(set = 1, binding = 3) uniform textureCube radiance_cubemap; +layout(set = 1, binding = 3) uniform texture2D radiance_octmap; #endif -layout(set = 1, binding = 4) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 4) uniform texture2DArray reflection_atlas; layout(set = 1, binding = 5) uniform texture2D shadow_atlas; diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 43277ba3041..79036f5efe6 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -78,13 +78,6 @@ layout(location = 13) in vec4 previous_normal_attrib; #endif // MODE_RENDER_MOTION_VECTORS -vec3 oct_to_vec3(vec2 e) { - vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); - float t = max(-v.z, 0.0); - v.xy += t * -sign(v.xy); - return normalize(v); -} - void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { float c = cos(angle); float s = sin(angle); @@ -1048,14 +1041,19 @@ hvec4 fog_process(vec3 vertex) { vec3 cube_view = scene_data_block.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_block.data.z_near) / (scene_data_block.data.z_far - scene_data_block.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, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb; - sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend); +#ifdef USE_RADIANCE_OCTMAP_ARRAY + float roughness_lod, blend; + blend = modf(mip_level * MAX_ROUGHNESS_LOD, roughness_lod); + float cube_lod = vec3_to_oct_lod(dFdx(cube_view), dFdy(cube_view), scene_data_block.data.radiance_pixel_size); + vec2 cube_uv = vec3_to_oct_with_border(cube_view, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + vec3 sky_sample_a = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(cube_uv, roughness_lod), cube_lod).rgb; + vec3 sky_sample_b = textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(cube_uv, roughness_lod + 1), cube_lod).rgb; + sky_fog_color = mix(sky_sample_a, sky_sample_b, blend); #else - sky_fog_color = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY + float roughness_lod = mip_level * MAX_ROUGHNESS_LOD; + vec2 cube_uv = vec3_to_oct_with_border(cube_view, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + sky_fog_color = textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_uv, roughness_lod).rgb; +#endif //USE_RADIANCE_OCTMAP_ARRAY fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective); } @@ -1595,20 +1593,20 @@ void main() { #endif half horizon = min(half(1.0) + dot(ref_vec, indirect_normal), half(1.0)); ref_vec = hvec3(scene_data.radiance_inverse_xform * vec3(ref_vec)); -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - +#ifdef USE_RADIANCE_OCTMAP_ARRAY float lod; - half blend = half(modf(float(sqrt(roughness) * half(MAX_ROUGHNESS_LOD)), lod)); + half blend = half(modf(float(sqrt(roughness) * MAX_ROUGHNESS_LOD), lod)); - hvec3 indirect_sample_a = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(vec3(ref_vec), float(lod))).rgb); - hvec3 indirect_sample_b = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(vec3(ref_vec), float(lod) + 1.0)).rgb); + float ref_lod = vec3_to_oct_lod(dFdx(ref_vec), dFdy(ref_vec), scene_data_block.data.radiance_pixel_size); + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + hvec3 indirect_sample_a = hvec3(textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_uv, float(lod)), ref_lod).rgb); + hvec3 indirect_sample_b = hvec3(textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_uv, float(lod) + 1.0), ref_lod).rgb); indirect_specular_light = mix(indirect_sample_a, indirect_sample_b, blend); - -#else // USE_RADIANCE_CUBEMAP_ARRAY - float lod = sqrt(roughness) * half(MAX_ROUGHNESS_LOD); - indirect_specular_light = hvec3(textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_vec), lod).rgb); - -#endif //USE_RADIANCE_CUBEMAP_ARRAY +#else // USE_RADIANCE_OCTMAP_ARRAY + float lod = sqrt(roughness) * MAX_ROUGHNESS_LOD; + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + indirect_specular_light = hvec3(textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_uv, lod).rgb); +#endif //USE_RADIANCE_OCTMAP_ARRAY indirect_specular_light *= REFLECTION_MULTIPLIER; indirect_specular_light *= half(scene_data.IBL_exposure_normalization); indirect_specular_light *= horizon * horizon; @@ -1626,14 +1624,18 @@ void main() { if (sc_scene_use_ambient_cubemap()) { vec3 ambient_dir = scene_data.radiance_inverse_xform * indirect_normal; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - hvec3 cubemap_ambient = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb); +#ifdef USE_RADIANCE_OCTMAP_ARRAY + float ambient_lod = vec3_to_oct_lod(dFdx(ambient_dir), dFdy(ambient_dir), scene_data_block.data.radiance_pixel_size); + vec2 ambient_uv = vec3_to_oct_with_border(ambient_dir, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + hvec3 octmap_ambient = hvec3(textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ambient_uv, MAX_ROUGHNESS_LOD), ambient_lod).rgb); #else - hvec3 cubemap_ambient = hvec3(textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb); -#endif //USE_RADIANCE_CUBEMAP_ARRAY - cubemap_ambient *= REFLECTION_MULTIPLIER; - cubemap_ambient *= half(scene_data.IBL_exposure_normalization); - ambient_light = mix(ambient_light, cubemap_ambient * half(scene_data.ambient_light_color_energy.a), half(scene_data.ambient_color_sky_mix)); + float roughness_lod = MAX_ROUGHNESS_LOD; + vec2 ambient_uv = vec3_to_oct_with_border(ambient_dir, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + hvec3 octmap_ambient = hvec3(textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_uv, roughness_lod).rgb); +#endif //USE_RADIANCE_OCTMAP_ARRAY + octmap_ambient *= REFLECTION_MULTIPLIER; + octmap_ambient *= half(scene_data.IBL_exposure_normalization); + ambient_light = mix(ambient_light, octmap_ambient * half(scene_data.ambient_light_color_energy.a), half(scene_data.ambient_color_sky_mix)); } } #endif // !USE_LIGHTMAP @@ -1656,18 +1658,19 @@ void main() { half horizon = min(half(1.0) + dot(ref_vec, indirect_normal), half(1.0)); ref_vec = hvec3(scene_data.radiance_inverse_xform * vec3(ref_vec)); float roughness_lod = mix(0.001, 0.1, sqrt(float(clearcoat_roughness))) * MAX_ROUGHNESS_LOD; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - +#ifdef USE_RADIANCE_OCTMAP_ARRAY float lod; half blend = half(modf(roughness_lod, lod)); - hvec3 clearcoat_sample_a = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb); - hvec3 clearcoat_sample_b = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb); + + float ref_lod = vec3_to_oct_lod(dFdx(ref_vec), dFdy(ref_vec), scene_data_block.data.radiance_pixel_size); + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + hvec3 clearcoat_sample_a = hvec3(textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_uv, lod), ref_lod).rgb); + hvec3 clearcoat_sample_b = hvec3(textureLod(sampler2DArray(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_uv, lod + 1), ref_lod).rgb); hvec3 clearcoat_light = mix(clearcoat_sample_a, clearcoat_sample_b, blend); - #else - hvec3 clearcoat_light = hvec3(textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ref_vec), roughness_lod).rgb); - -#endif //USE_RADIANCE_CUBEMAP_ARRAY + vec2 ref_uv = vec3_to_oct_with_border(ref_vec, vec2(scene_data_block.data.radiance_border_size, 1.0 - scene_data_block.data.radiance_border_size * 2.0)); + hvec3 clearcoat_light = hvec3(textureLod(sampler2D(radiance_octmap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_uv, roughness_lod).rgb); +#endif //USE_RADIANCE_OCTMAP_ARRAY indirect_specular_light += clearcoat_light * horizon * horizon * Fc * half(scene_data.ambient_light_color_energy.a); } #endif // LIGHT_CLEARCOAT_USED diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index a2eeb339291..ad6de0579ff 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -2,6 +2,7 @@ #define MAX_VIEWS 2 #include "../decal_data_inc.glsl" +#include "../oct_inc.glsl" #include "../scene_data_inc.glsl" #if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) @@ -351,17 +352,17 @@ layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer } instances; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY +#ifdef USE_RADIANCE_OCTMAP_ARRAY -layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; +layout(set = 1, binding = 2) uniform texture2DArray radiance_octmap; #else -layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; +layout(set = 1, binding = 2) uniform texture2D radiance_octmap; #endif -layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 3) uniform texture2DArray reflection_atlas; layout(set = 1, binding = 4) uniform texture2D shadow_atlas; diff --git a/servers/rendering/renderer_rd/shaders/oct_inc.glsl b/servers/rendering/renderer_rd/shaders/oct_inc.glsl new file mode 100644 index 00000000000..63e0f1b368a --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/oct_inc.glsl @@ -0,0 +1,51 @@ + +vec3 oct_to_vec3(vec2 e) { + vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); + float t = max(-v.z, 0.0); + v.xy += t * -sign(v.xy); + return normalize(v); +} + +// border_size: 1.0 - padding_in_uv_space * 2.0. +vec3 oct_to_vec3_with_border(vec2 uv, float border_size) { + // Convert into [-1,1] space and add border which extends beyond [-1,1]. + uv = (uv - 0.5) * (2.0 / border_size); + // Calculate octahedral mirroring for values outside of [-1,1]. + // Inspired by Timothy Lottes' code here: https://gpuopen.com/learn/fetching-from-cubes-and-octahedrons/ + vec2 mask = step(vec2(1.0), abs(uv)); + uv = 2.0 * clamp(uv, -1.0, 1.0) - uv; + uv = mix(uv, -uv, mask.yx); + return oct_to_vec3(uv); +} + +vec2 oct_wrap(vec2 v) { + vec2 signVal; + signVal.x = v.x >= 0.0 ? 1.0 : -1.0; + signVal.y = v.y >= 0.0 ? 1.0 : -1.0; + return (1.0 - abs(v.yx)) * signVal; +} + +vec2 vec3_to_oct(vec3 n) { + // Reference: https://twitter.com/Stubbesaurus/status/937994790553227264 + n /= (abs(n.x) + abs(n.y) + abs(n.z)); + n.xy = (n.z >= 0.0) ? n.xy : oct_wrap(n.xy); + n.xy = n.xy * 0.5 + 0.5; + return n.xy; +} + +// border_size.x: padding_in_uv_space +// border_size.y: 1.0 - padding_in_uv_space * 2.0 +vec2 vec3_to_oct_with_border(vec3 n, vec2 border_size) { + vec2 uv = vec3_to_oct(n); + return uv * border_size.y + border_size.x; +} + +float vec3_to_oct_lod(vec3 n_ddx, vec3 n_ddy, float pixel_size) { + // Approximate UV space derivatives by a factor of 0.5 because + // vec3_to_oct maps from [-1,1] to [0,1]. + float pixel_size_sqr = 4.0 * pixel_size * pixel_size; + float ddx = dot(n_ddx, n_ddx) / pixel_size_sqr; + float ddy = dot(n_ddy, n_ddy) / pixel_size_sqr; + float dd_sqr = max(ddx, ddy); + return 0.25 * log2(dd_sqr + 1e-6f); +} diff --git a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl index c2ddb64f181..0561cfa7657 100644 --- a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl @@ -42,6 +42,10 @@ struct SceneData { vec2 shadow_atlas_pixel_size; vec2 directional_shadow_pixel_size; + float radiance_pixel_size; + float radiance_border_size; + vec2 reflection_atlas_border_size; + uint directional_light_count; float dual_paraboloid_side; float z_far; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 726fdfcdf03..bebd20895c8 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -937,6 +937,7 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal blend = pow(blend_axes.x * blend_axes.y * blend_axes.z, half(2.0)); } + vec2 border_size = scene_data_block.data.reflection_atlas_border_size; if (reflections.data[ref_index].intensity > 0.0 && reflection_accum.a < half(1.0)) { // compute reflection vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; @@ -957,7 +958,9 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal hvec4 reflection; half reflection_blend = max(half(0.0), blend - reflection_accum.a); - reflection.rgb = hvec3(textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb) * REFLECTION_MULTIPLIER; + float roughness_lod = sqrt(roughness) * MAX_ROUGHNESS_LOD; + vec2 reflection_uv = vec3_to_oct_with_border(local_ref_vec, border_size); + reflection.rgb = hvec3(textureLod(sampler2DArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(reflection_uv, reflections.data[ref_index].index), roughness_lod).rgb) * REFLECTION_MULTIPLIER; reflection.rgb *= half(reflections.data[ref_index].exposure_normalization); reflection.a = reflection_blend; @@ -980,7 +983,9 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal hvec4 ambient_out; half ambient_blend = max(half(0.0), blend - ambient_accum.a); - ambient_out.rgb = hvec3(textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb); + float roughness_lod = MAX_ROUGHNESS_LOD; + vec2 ambient_uv = vec3_to_oct_with_border(local_amb_vec, border_size); + ambient_out.rgb = hvec3(textureLod(sampler2DArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(ambient_uv, reflections.data[ref_index].index), roughness_lod).rgb); ambient_out.rgb *= half(reflections.data[ref_index].exposure_normalization); ambient_out.a = ambient_blend; ambient_out.rgb *= ambient_out.a; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index d76755c97c6..cc44e5081e1 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -1452,7 +1452,6 @@ void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { rpi->rendering = false; rpi->dirty = true; rpi->processing_layer = 1; - rpi->processing_side = 0; } rpi->atlas_index = -1; @@ -1518,20 +1517,41 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ _reflection_atlas_clear(atlas); } + const int required_real_time_mipmaps = 7; + if (atlas->reflection.is_null()) { + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_V_MSG(copy_effects, false, "Effects haven't been initialized"); + int mipmaps = MIN(RendererSceneRenderRD::get_singleton()->get_sky()->roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1); - mipmaps = update_always ? 8 : mipmaps; // always use 8 mipmaps with real time filtering + mipmaps = update_always ? required_real_time_mipmaps : mipmaps; + + // Double size to approximate texel density of cubemaps + add border for proper filtering/mipmapping. + uint32_t padding_pixels = (1 << (mipmaps - 1)); + atlas->reflection_texture_size = atlas->size * 2 + padding_pixels * 2; + atlas->uv_border_size = float(padding_pixels) / float(atlas->reflection_texture_size); + + bool use_storage = !copy_effects->get_raster_effects().has_flag(CopyEffects::RASTER_EFFECT_OCTMAP); { - //reflection atlas was unused, create: RD::TextureFormat tf; - tf.array_layers = 6 * atlas->count; + tf.array_layers = atlas->count; tf.format = get_reflection_probe_color_format(); - tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; tf.mipmaps = mipmaps; + tf.width = atlas->reflection_texture_size; + tf.height = atlas->reflection_texture_size; + tf.usage_bits = get_reflection_probe_color_usage_bits(use_storage); + atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + { + RD::TextureFormat tf; + tf.array_layers = 6; + tf.format = get_reflection_probe_color_format(); + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.width = atlas->size; tf.height = atlas->size; - tf.usage_bits = get_reflection_probe_color_usage_bits(); - atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView()); + tf.usage_bits = get_reflection_probe_color_usage_bits(use_storage); + atlas->color_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); } { RD::TextureFormat tf; @@ -1543,15 +1563,17 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ } atlas->reflections.resize(atlas->count); for (int i = 0; i < atlas->count; i++) { - atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, update_always, RendererSceneRenderRD::get_singleton()->get_sky()->roughness_layers, RendererSceneRenderRD::get_singleton()->_render_buffers_get_preferred_color_format()); - for (int j = 0; j < 6; j++) { - atlas->reflections.write[i].fbs[j] = RendererSceneRenderRD::get_singleton()->reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer); - } + atlas->reflections.write[i].data.update_reflection_data(atlas->reflection_texture_size, mipmaps, false, atlas->reflection, i, update_always, RendererSceneRenderRD::get_singleton()->get_sky()->roughness_layers, RendererSceneRenderRD::get_singleton()->_render_buffers_get_preferred_color_format(), atlas->uv_border_size); } - Vector fb; - fb.push_back(atlas->depth_buffer); - atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb); + for (int i = 0; i < 6; i++) { + atlas->color_views[i] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), atlas->color_buffer, i, 0); + atlas->color_fbs[i] = RendererSceneRenderRD::get_singleton()->reflection_probe_create_framebuffer(atlas->color_views[i], atlas->depth_buffer); + } + + Vector fbs; + fbs.push_back(atlas->depth_buffer); + atlas->depth_fb = RD::get_singleton()->framebuffer_create(fbs); atlas->render_buffers->configure_for_reflections(Size2i(atlas->size, atlas->size)); atlas->update_always = update_always; @@ -1587,13 +1609,29 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ rpi->rendering = true; rpi->dirty = false; rpi->processing_layer = 1; - rpi->processing_side = 0; RD::get_singleton()->draw_command_end_label(); return true; } +bool LightStorage::reflection_probe_instance_end_render(RID p_instance, RID p_reflection_atlas) { + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_V_MSG(copy_effects, false, "Effects haven't been initialized"); + + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas); + ERR_FAIL_NULL_V(atlas, false); + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_NULL_V(rpi, false); + + RD::get_singleton()->draw_command_begin_label("Convert reflection probe to octahedral"); + copy_effects->copy_cubemap_to_octmap(atlas->color_buffer, atlas->reflections.write[rpi->atlas_index].data.layers[0].mipmaps[0].framebuffer, atlas->uv_border_size); + RD::get_singleton()->draw_command_end_label(); + + return true; +} + Ref LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) { ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas); ERR_FAIL_NULL_V(atlas, Ref()); @@ -1617,35 +1655,17 @@ bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) { // Using real time reflections, all roughness is done in one step atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(false); rpi->rendering = false; - rpi->processing_side = 0; rpi->processing_layer = 1; return true; } - if (rpi->processing_layer > 1) { - atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, 10, rpi->processing_layer, RendererSceneRenderRD::get_singleton()->get_sky()->sky_ggx_samples_quality); - rpi->processing_layer++; - if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) { - rpi->rendering = false; - rpi->processing_side = 0; - rpi->processing_layer = 1; - return true; - } - return false; + atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, rpi->processing_layer, RendererSceneRenderRD::get_singleton()->get_sky()->sky_ggx_samples_quality); - } else { - atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, rpi->processing_side, rpi->processing_layer, RendererSceneRenderRD::get_singleton()->get_sky()->sky_ggx_samples_quality); - } - - rpi->processing_side++; - if (rpi->processing_side == 6) { - rpi->processing_side = 0; - rpi->processing_layer++; - if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) { - rpi->rendering = false; - rpi->processing_layer = 1; - return true; - } + rpi->processing_layer++; + if (rpi->processing_layer == (int)atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) { + rpi->rendering = false; + rpi->processing_layer = 1; + return true; } return false; @@ -1669,7 +1689,7 @@ RID LightStorage::reflection_probe_instance_get_framebuffer(RID p_instance, int ERR_FAIL_NULL_V(atlas, RID()); ERR_FAIL_COND_V_MSG(rpi->atlas_index < 0, RID(), "Reflection probe atlas index invalid. Maximum amount of reflection probes in use (" + itos(atlas->count) + ") may have been exceeded, reflections will not display properly. Consider increasing Rendering > Reflections > Reflection Atlas > Reflection Count in the Project Settings."); - return atlas->reflections[rpi->atlas_index].fbs[p_index]; + return atlas->color_fbs[p_index]; } RID LightStorage::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { @@ -1818,8 +1838,8 @@ RD::DataFormat LightStorage::get_reflection_probe_color_format() { return RendererSceneRenderRD::get_singleton()->_render_buffers_get_preferred_color_format(); } -uint32_t LightStorage::get_reflection_probe_color_usage_bits() { - return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); +uint32_t LightStorage::get_reflection_probe_color_usage_bits(bool p_storage) { + return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (p_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); } RD::DataFormat LightStorage::get_reflection_probe_depth_format() { diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index 3d8380fe84a..6603ad7ac9f 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -245,16 +245,20 @@ private: struct ReflectionAtlas { int count = 0; int size = 0; + int reflection_texture_size = 0; + float uv_border_size = 0.0; bool update_always = false; RID reflection; + RID color_buffer; + RID color_views[6]; + RID color_fbs[6]; RID depth_buffer; RID depth_fb; struct Reflection { RID owner; RendererRD::SkyRD::ReflectionData data; - RID fbs[6]; }; Vector reflections; @@ -278,7 +282,6 @@ private: bool dirty = true; bool rendering = false; int processing_layer = 1; - int processing_side = 0; uint64_t last_pass = 0; uint32_t cull_mask = 0; @@ -893,6 +896,18 @@ public: return atlas->reflection; } + _FORCE_INLINE_ int reflection_atlas_get_texture_size(RID p_ref_atlas) { + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas); + ERR_FAIL_NULL_V(atlas, 0); + return atlas->reflection_texture_size; + } + + _FORCE_INLINE_ float reflection_atlas_get_border_size(RID p_ref_atlas) { + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas); + ERR_FAIL_NULL_V(atlas, 0.0); + return atlas->uv_border_size; + } + /* REFLECTION PROBE INSTANCE */ bool owns_reflection_probe_instance(RID p_rid) { return reflection_probe_instance_owner.owns(p_rid); } @@ -905,6 +920,7 @@ public: virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; + virtual bool reflection_probe_instance_end_render(RID p_instance, RID p_reflection_atlas) override; virtual Ref reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override; virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override; @@ -968,7 +984,7 @@ public: RID get_reflection_probe_buffer() { return reflection_buffer; } void update_reflection_probe_buffer(RenderDataRD *p_render_data, const PagedArray &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment); static RD::DataFormat get_reflection_probe_color_format(); - static uint32_t get_reflection_probe_color_usage_bits(); + static uint32_t get_reflection_probe_color_usage_bits(bool p_storage); static RD::DataFormat get_reflection_probe_depth_format(); static uint32_t get_reflection_probe_depth_usage_bits(); diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp index 33945dbd749..5bc1480904e 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp @@ -140,6 +140,12 @@ void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p ubo.directional_shadow_pixel_size[0] = directional_shadow_pixel_size.x; ubo.directional_shadow_pixel_size[1] = directional_shadow_pixel_size.y; + ubo.radiance_pixel_size = radiance_pixel_size; + ubo.radiance_border_size = radiance_border_size; + + ubo.reflection_atlas_border_size[0] = reflection_atlas_border_size.x; + ubo.reflection_atlas_border_size[1] = reflection_atlas_border_size.y; + ubo.time = time; ubo.directional_light_count = directional_light_count; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h index 78fea1a66be..0f59cceccdd 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h @@ -80,6 +80,10 @@ public: Size2 shadow_atlas_pixel_size; Size2 directional_shadow_pixel_size; + float radiance_pixel_size; + float radiance_border_size; + Size2 reflection_atlas_border_size; + float time; float time_step; @@ -139,6 +143,10 @@ private: float shadow_atlas_pixel_size[2]; float directional_shadow_pixel_size[2]; + float radiance_pixel_size; + float radiance_border_size; + float reflection_atlas_border_size[2]; + uint32_t directional_light_count; float dual_paraboloid_side; float z_far; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index c73fb6ffda5..8bcddc1b3a7 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -3573,7 +3573,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int return true; } - if (p_step >= 0 && p_step < 6) { + if (p_step == 0) { static const Vector3 view_normals[6] = { Vector3(+1, 0, 0), Vector3(-1, 0, 0), @@ -3596,44 +3596,34 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int float max_distance = RSG::light_storage->reflection_probe_get_origin_max_distance(p_instance->base); float atlas_size = RSG::light_storage->reflection_atlas_get_size(scenario->reflection_atlas); float mesh_lod_threshold = RSG::light_storage->reflection_probe_get_mesh_lod_threshold(p_instance->base) / atlas_size; - - Vector3 edge = view_normals[p_step] * probe_size / 2; - float distance = Math::abs(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit - - max_distance = MAX(max_distance, distance); - - //render cubemap side - Projection cm; - cm.set_perspective(90, 1, 0.01, max_distance); - - Transform3D local_view; - local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); - - Transform3D xform = p_instance->transform * local_view; - - RID shadow_atlas; - bool use_shadows = RSG::light_storage->reflection_probe_renders_shadows(p_instance->base); - if (use_shadows) { - shadow_atlas = scenario->reflection_probe_shadow_atlas; - } - - RID environment; - if (scenario->environment.is_valid()) { - environment = scenario->environment; - } else { - environment = scenario->fallback_environment; - } - - RENDER_TIMESTAMP("Render ReflectionProbe, Step " + itos(p_step)); - RendererSceneRender::CameraData camera_data; - camera_data.set_camera(xform, cm, false, false, false); - + RID shadow_atlas = use_shadows ? scenario->reflection_probe_shadow_atlas : RID(); + RID environment = scenario->environment.is_valid() ? scenario->environment : scenario->fallback_environment; Ref render_buffers = RSG::light_storage->reflection_probe_atlas_get_render_buffers(scenario->reflection_atlas); - _render_scene(&camera_data, render_buffers, environment, RID(), RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows); + for (uint32_t face = 0; face < 6; face++) { + // Compute distance from origin offset to the actual view distance limit. + Vector3 edge = view_normals[face] * probe_size / 2; + float distance = Math::abs(view_normals[face].dot(edge) - view_normals[face].dot(origin_offset)); + max_distance = MAX(max_distance, distance); + // Render cubemap side. + Projection cm; + cm.set_perspective(90, 1, 0.01, max_distance); + + Transform3D local_view; + local_view.set_look_at(origin_offset, origin_offset + view_normals[face], view_up[face]); + + RendererSceneRender::CameraData camera_data; + Transform3D xform = p_instance->transform * local_view; + camera_data.set_camera(xform, cm, false, false, false); + + RENDER_TIMESTAMP("Render ReflectionProbe, Face " + itos(face)); + _render_scene(&camera_data, render_buffers, environment, RID(), RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, face, mesh_lod_threshold, use_shadows); + } + + RSG::light_storage->reflection_probe_instance_end_render(reflection_probe->instance, scenario->reflection_atlas); } else { - //do roughness postprocess step until it believes it's done + // Do roughness postprocess step until it believes it's done. RENDER_TIMESTAMP("Post-Process ReflectionProbe, Step " + itos(p_step)); return RSG::light_storage->reflection_probe_instance_postprocess_step(reflection_probe->instance); } diff --git a/servers/rendering/rendering_server.cpp b/servers/rendering/rendering_server.cpp index 62f13bfc975..be54c48b79f 100644 --- a/servers/rendering/rendering_server.cpp +++ b/servers/rendering/rendering_server.cpp @@ -3723,7 +3723,7 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug", false); GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true); - GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/roughness_layers", PROPERTY_HINT_RANGE, "1,32,1"), 8); // Assumes a 256x256 cubemap + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/roughness_layers", PROPERTY_HINT_RANGE, "1,32,1"), 7); GLOBAL_DEF_RST("rendering/reflections/sky_reflections/texture_array_reflections", true); GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false); GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/ggx_samples", PROPERTY_HINT_RANGE, "0,256,1"), 32); diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index 89936b74054..956e6324499 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -151,6 +151,7 @@ public: virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0; + virtual bool reflection_probe_instance_end_render(RID p_instance, RID p_reflection_atlas) = 0; virtual Ref reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) = 0; virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;