summaryrefslogtreecommitdiff
path: root/servers/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering')
-rw-r--r--servers/rendering/rasterizer.h12
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp65
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.h18
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp814
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h122
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp1997
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h306
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp9
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.h70
-rw-r--r--servers/rendering/rasterizer_rd/shaders/SCsub2
-rw-r--r--servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl95
-rw-r--r--servers/rendering/rasterizer_rd/shaders/gi.glsl2
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl88
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl146
-rw-r--r--servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl12
-rw-r--r--servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl105
-rw-r--r--servers/rendering/rasterizer_rd/shaders/sky.glsl81
-rw-r--r--servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl530
-rw-r--r--servers/rendering/rendering_device_binds.cpp2
-rw-r--r--servers/rendering/rendering_device_binds.h2
-rw-r--r--servers/rendering/rendering_server_raster.h10
-rw-r--r--servers/rendering/rendering_server_scene.cpp12
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h11
-rw-r--r--servers/rendering/shader_language.cpp14
-rw-r--r--servers/rendering/shader_types.cpp1
25 files changed, 3279 insertions, 1247 deletions
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
index 348fc423bb..e1282fdf71 100644
--- a/servers/rendering/rasterizer.h
+++ b/servers/rendering/rasterizer.h
@@ -86,7 +86,13 @@ public:
virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0;
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
- virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0;
+
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
+
+ virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
+ virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
+ virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0;
+ virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0;
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0;
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0;
@@ -104,9 +110,7 @@ public:
virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
- virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0;
- virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0;
- virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0;
+ virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density) = 0;
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
index 3f594ab264..b3279f041f 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
@@ -508,7 +508,7 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_ro
}
if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) {
- //blurr
+ //blur
RD::get_singleton()->compute_list_add_barrier(compute_list);
@@ -1171,7 +1171,7 @@ void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_des
RD::get_singleton()->compute_list_end();
}
-void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
+void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
SkyPushConstant sky_push_constant;
zeromem(&sky_push_constant, sizeof(SkyPushConstant));
@@ -1198,7 +1198,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
}
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_lights, 3);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_fog, 3);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -1229,6 +1229,50 @@ void RasterizerEffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_rou
RD::get_singleton()->compute_list_end();
}
+void RasterizerEffectsRD::reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RD::ComputeListID compute_list) {
+ uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, (uint32_t)p_shrink_limit, 0, 0, 0 };
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_REDUCE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_source_shadow, p_dest_shadow), 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8);
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1);
+}
+void RasterizerEffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RenderingServer::EnvVolumetricFogShadowFilter p_filter, RD::ComputeListID compute_list, bool p_vertical, bool p_horizontal) {
+ uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, 0, 0, 0, 0 };
+
+ switch (p_filter) {
+ case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED:
+ case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW: {
+ push_constant[5] = 0;
+ } break;
+ case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM: {
+ push_constant[5] = 9;
+ } break;
+ case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_HIGH: {
+ push_constant[5] = 18;
+ } break;
+ }
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_FILTER]);
+ if (p_vertical) {
+ push_constant[6] = 1;
+ push_constant[7] = 0;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_shadow, p_backing_shadow), 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1);
+ }
+ if (p_vertical && p_horizontal) {
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+ if (p_horizontal) {
+ push_constant[6] = 0;
+ push_constant[7] = 1;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_backing_shadow, p_shadow), 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1);
+ }
+}
RasterizerEffectsRD::RasterizerEffectsRD() {
{ // Initialize copy
Vector<String> copy_modes;
@@ -1560,6 +1604,20 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
}
}
+ {
+ Vector<String> shadow_reduce_modes;
+ shadow_reduce_modes.push_back("\n#define MODE_REDUCE\n");
+ shadow_reduce_modes.push_back("\n#define MODE_FILTER\n");
+
+ shadow_reduce.shader.initialize(shadow_reduce_modes);
+
+ shadow_reduce.shader_version = shadow_reduce.shader.version_create();
+
+ for (int i = 0; i < SHADOW_REDUCE_MAX; i++) {
+ shadow_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(shadow_reduce.shader.version_get_shader(shadow_reduce.shader_version, i));
+ }
+ }
+
RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
@@ -1624,4 +1682,5 @@ RasterizerEffectsRD::~RasterizerEffectsRD() {
ssr_scale.shader.version_free(ssr_scale.shader_version);
sss.shader.version_free(sss.shader_version);
tonemap.shader.version_free(tonemap.shader_version);
+ shadow_reduce.shader.version_free(shadow_reduce.shader_version);
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
index 80849654de..b0964f23e7 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
@@ -46,6 +46,7 @@
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h"
@@ -534,6 +535,18 @@ class RasterizerEffectsRD {
RID pipelines[RESOLVE_MODE_MAX]; //3 quality levels
} resolve;
+ enum ShadowReduceMode {
+ SHADOW_REDUCE_REDUCE,
+ SHADOW_REDUCE_FILTER,
+ SHADOW_REDUCE_MAX
+ };
+
+ struct ShadowReduce {
+ ShadowReduceShaderRD shader;
+ RID shader_version;
+ RID pipelines[2];
+ } shadow_reduce;
+
RID default_sampler;
RID default_mipmap_sampler;
RID index_buffer;
@@ -625,7 +638,7 @@ public:
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
- void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
+ void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
@@ -633,6 +646,9 @@ public:
void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples);
+ void reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RenderingDevice::ComputeListID compute_list);
+ void filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RS::EnvVolumetricFogShadowFilter p_filter, RenderingDevice::ComputeListID compute_list, bool p_vertical = true, bool p_horizontal = true);
+
RasterizerEffectsRD();
~RasterizerEffectsRD();
};
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
index 890ada019f..11abb8f4a8 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -33,69 +33,6 @@
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_server_raster.h"
-static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) {
- p_array[0] = p_mtx.basis.elements[0][0];
- p_array[1] = p_mtx.basis.elements[1][0];
- p_array[2] = p_mtx.basis.elements[2][0];
- p_array[3] = 0;
- p_array[4] = p_mtx.basis.elements[0][1];
- p_array[5] = p_mtx.basis.elements[1][1];
- p_array[6] = p_mtx.basis.elements[2][1];
- p_array[7] = 0;
- p_array[8] = p_mtx.basis.elements[0][2];
- p_array[9] = p_mtx.basis.elements[1][2];
- p_array[10] = p_mtx.basis.elements[2][2];
- p_array[11] = 0;
- p_array[12] = p_mtx.origin.x;
- p_array[13] = p_mtx.origin.y;
- p_array[14] = p_mtx.origin.z;
- p_array[15] = 1;
-}
-
-static _FORCE_INLINE_ void store_basis_3x4(const Basis &p_mtx, float *p_array) {
- p_array[0] = p_mtx.elements[0][0];
- p_array[1] = p_mtx.elements[1][0];
- p_array[2] = p_mtx.elements[2][0];
- p_array[3] = 0;
- p_array[4] = p_mtx.elements[0][1];
- p_array[5] = p_mtx.elements[1][1];
- p_array[6] = p_mtx.elements[2][1];
- p_array[7] = 0;
- p_array[8] = p_mtx.elements[0][2];
- p_array[9] = p_mtx.elements[1][2];
- p_array[10] = p_mtx.elements[2][2];
- p_array[11] = 0;
-}
-
-static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_mtx, float *p_array) {
- p_array[0] = p_mtx.elements[0][0];
- p_array[1] = p_mtx.elements[1][0];
- p_array[2] = p_mtx.elements[2][0];
- p_array[3] = 0;
- p_array[4] = p_mtx.elements[0][1];
- p_array[5] = p_mtx.elements[1][1];
- p_array[6] = p_mtx.elements[2][1];
- p_array[7] = 0;
- p_array[8] = p_mtx.elements[0][2];
- p_array[9] = p_mtx.elements[1][2];
- p_array[10] = p_mtx.elements[2][2];
- p_array[11] = 0;
-}
-
-static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- p_array[i * 4 + j] = p_mtx.matrix[i][j];
- }
- }
-}
-
-static _FORCE_INLINE_ void store_soft_shadow_kernel(const float *p_kernel, float *p_array) {
- for (int i = 0; i < 128; i++) {
- p_array[i] = p_kernel[i];
- }
-}
-
/* SCENE SHADER */
void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
//compile
@@ -845,8 +782,8 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements,
for (int i = 0; i < p_element_count; i++) {
const RenderList::Element *e = p_elements[i];
InstanceData &id = scene_state.instances[i];
- store_transform(e->instance->transform, id.transform);
- store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
+ RasterizerStorageRD::store_transform(e->instance->transform, id.transform);
+ RasterizerStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
id.flags = 0;
id.mask = e->instance->layer_mask;
id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0;
@@ -1171,20 +1108,20 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
CameraMatrix projection = correction * p_cam_projection;
//store camera into ubo
- store_camera(projection, scene_state.ubo.projection_matrix);
- store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
- store_transform(p_cam_transform, scene_state.ubo.camera_matrix);
- store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix);
+ RasterizerStorageRD::store_camera(projection, scene_state.ubo.projection_matrix);
+ RasterizerStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
+ RasterizerStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix);
+ RasterizerStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix);
scene_state.ubo.z_far = p_zfar;
scene_state.ubo.z_near = p_znear;
scene_state.ubo.pancake_shadows = p_pancake_shadows;
- store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
- store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
- store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
- store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
+ RasterizerStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
+ RasterizerStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
+ RasterizerStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
+ RasterizerStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get();
scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get();
@@ -1208,12 +1145,31 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
scene_state.ubo.time = time;
scene_state.ubo.gi_upscale_for_msaa = false;
+ scene_state.ubo.volumetric_fog_enabled = false;
+ scene_state.ubo.fog_enabled = false;
if (p_render_buffers.is_valid()) {
RenderBufferDataHighEnd *render_buffers = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
scene_state.ubo.gi_upscale_for_msaa = true;
}
+
+ if (render_buffers_has_volumetric_fog(p_render_buffers)) {
+ scene_state.ubo.volumetric_fog_enabled = true;
+ float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+ if (fog_end > 0.0) {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0;
+ }
+
+ float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0;
+ }
+ }
}
#if 0
if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) {
@@ -1310,7 +1266,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
Basis sky_transform = environment_get_sky_orientation(p_environment);
sky_transform = sky_transform.inverse() * p_cam_transform.basis;
- store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
+ RasterizerStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
@@ -1328,12 +1284,29 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_environment);
scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_environment);
- Color ao_color = environment_get_ao_color(p_environment);
+ Color ao_color = environment_get_ao_color(p_environment).to_linear();
scene_state.ubo.ao_color[0] = ao_color.r;
scene_state.ubo.ao_color[1] = ao_color.g;
scene_state.ubo.ao_color[2] = ao_color.b;
scene_state.ubo.ao_color[3] = ao_color.a;
+ scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
+ scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
+ scene_state.ubo.fog_height = environment_get_fog_height(p_environment);
+ scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_environment);
+ if (scene_state.ubo.fog_height_density >= 0.0001) {
+ scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density;
+ }
+
+ Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
+ float fog_energy = environment_get_fog_light_energy(p_environment);
+
+ scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+
+ scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
+
} else {
if (p_reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
scene_state.ubo.use_ambient_light = false;
@@ -1394,8 +1367,8 @@ void RasterizerSceneHighEndRD::_add_geometry(InstanceBase *p_instance, uint32_t
material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D);
if (!material || !material->shader_data->valid) {
break;
- _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index, p_using_sdfgi);
}
+ _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index, p_using_sdfgi);
}
}
@@ -1582,66 +1555,6 @@ void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, i
}
}
-void RasterizerSceneHighEndRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) {
- for (int i = 0; i < p_reflection_probe_cull_count; i++) {
- RID rpi = p_reflection_probe_cull_result[i];
-
- if (i >= (int)scene_state.max_reflections) {
- reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set
- continue;
- }
-
- reflection_probe_instance_set_render_index(rpi, i);
-
- RID base_probe = reflection_probe_instance_get_probe(rpi);
-
- ReflectionData &reflection_ubo = scene_state.reflections[i];
-
- Vector3 extents = storage->reflection_probe_get_extents(base_probe);
-
- reflection_ubo.box_extents[0] = extents.x;
- reflection_ubo.box_extents[1] = extents.y;
- reflection_ubo.box_extents[2] = extents.z;
- reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi);
-
- Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe);
-
- reflection_ubo.box_offset[0] = origin_offset.x;
- reflection_ubo.box_offset[1] = origin_offset.y;
- reflection_ubo.box_offset[2] = origin_offset.z;
- reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe);
-
- float intensity = storage->reflection_probe_get_intensity(base_probe);
- bool interior = storage->reflection_probe_is_interior(base_probe);
- bool box_projection = storage->reflection_probe_is_box_projection(base_probe);
-
- reflection_ubo.params[0] = intensity;
- reflection_ubo.params[1] = 0;
- reflection_ubo.params[2] = interior ? 1.0 : 0.0;
- reflection_ubo.params[3] = box_projection ? 1.0 : 0.0;
-
- Color ambient_linear = storage->reflection_probe_get_ambient_color(base_probe).to_linear();
- float interior_ambient_energy = storage->reflection_probe_get_ambient_color_energy(base_probe);
- uint32_t ambient_mode = storage->reflection_probe_get_ambient_mode(base_probe);
- reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy;
- reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
- reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
- reflection_ubo.ambient_mode = ambient_mode;
-
- Transform transform = reflection_probe_instance_get_transform(rpi);
- Transform proj = (p_camera_inverse_transform * transform).inverse();
- store_transform(proj, reflection_ubo.local_matrix);
-
- cluster_builder.add_reflection_probe(transform, extents);
-
- reflection_probe_instance_set_render_pass(rpi, render_pass);
- }
-
- if (p_reflection_probe_cull_count) {
- RD::get_singleton()->buffer_update(scene_state.reflection_buffer, 0, MIN(scene_state.max_reflections, (unsigned int)p_reflection_probe_cull_count) * sizeof(ReflectionData), scene_state.reflections, true);
- }
-}
-
void RasterizerSceneHighEndRD::_setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform) {
uint32_t lightmaps_used = 0;
for (int i = 0; i < p_lightmap_cull_count; i++) {
@@ -1652,7 +1565,7 @@ void RasterizerSceneHighEndRD::_setup_lightmaps(InstanceBase **p_lightmap_cull_r
InstanceBase *lm = p_lightmap_cull_result[i];
Basis to_lm = lm->transform.basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
- store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
+ RasterizerStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
lm->lightmap_cull_index = i;
lightmaps_used++;
}
@@ -1661,480 +1574,7 @@ void RasterizerSceneHighEndRD::_setup_lightmaps(InstanceBase **p_lightmap_cull_r
}
}
-void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows) {
- uint32_t light_count = 0;
- scene_state.ubo.directional_light_count = 0;
- sky_scene_state.directional_light_count = 0;
-
- for (int i = 0; i < p_light_cull_count; i++) {
- RID li = p_light_cull_result[i];
- RID base = light_instance_get_base_light(li);
-
- ERR_CONTINUE(base.is_null());
-
- RS::LightType type = storage->light_get_type(base);
- switch (type) {
- case RS::LIGHT_DIRECTIONAL: {
- if (scene_state.ubo.directional_light_count >= scene_state.max_directional_lights) {
- continue;
- }
-
- DirectionalLightData &light_data = scene_state.directional_lights[scene_state.ubo.directional_light_count];
-
- Transform light_transform = light_instance_get_base_transform(li);
-
- Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
-
- light_data.direction[0] = direction.x;
- light_data.direction[1] = direction.y;
- light_data.direction[2] = direction.z;
-
- float sign = storage->light_is_negative(base) ? -1 : 1;
-
- light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
-
- Color linear_col = storage->light_get_color(base).to_linear();
- light_data.color[0] = linear_col.r;
- light_data.color[1] = linear_col.g;
- light_data.color[2] = linear_col.b;
-
- light_data.specular = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
- light_data.mask = storage->light_get_cull_mask(base);
-
- float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
-
- light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
-
- Color shadow_col = storage->light_get_shadow_color(base).to_linear();
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) {
- light_data.shadow_color1[0] = 1.0;
- light_data.shadow_color1[1] = 0.0;
- light_data.shadow_color1[2] = 0.0;
- light_data.shadow_color1[3] = 1.0;
- light_data.shadow_color2[0] = 0.0;
- light_data.shadow_color2[1] = 1.0;
- light_data.shadow_color2[2] = 0.0;
- light_data.shadow_color2[3] = 1.0;
- light_data.shadow_color3[0] = 0.0;
- light_data.shadow_color3[1] = 0.0;
- light_data.shadow_color3[2] = 1.0;
- light_data.shadow_color3[3] = 1.0;
- light_data.shadow_color4[0] = 1.0;
- light_data.shadow_color4[1] = 1.0;
- light_data.shadow_color4[2] = 0.0;
- light_data.shadow_color4[3] = 1.0;
-
- } else {
- light_data.shadow_color1[0] = shadow_col.r;
- light_data.shadow_color1[1] = shadow_col.g;
- light_data.shadow_color1[2] = shadow_col.b;
- light_data.shadow_color1[3] = 1.0;
- light_data.shadow_color2[0] = shadow_col.r;
- light_data.shadow_color2[1] = shadow_col.g;
- light_data.shadow_color2[2] = shadow_col.b;
- light_data.shadow_color2[3] = 1.0;
- light_data.shadow_color3[0] = shadow_col.r;
- light_data.shadow_color3[1] = shadow_col.g;
- light_data.shadow_color3[2] = shadow_col.b;
- light_data.shadow_color3[3] = 1.0;
- light_data.shadow_color4[0] = shadow_col.r;
- light_data.shadow_color4[1] = shadow_col.g;
- light_data.shadow_color4[2] = shadow_col.b;
- light_data.shadow_color4[3] = 1.0;
- }
-
- light_data.shadow_enabled = p_using_shadows && storage->light_has_shadow(base);
-
- float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
- if (angular_diameter > 0.0) {
- // I know tan(0) is 0, but let's not risk it with numerical precision.
- // technically this will keep expanding until reaching the sun, but all we care
- // is expand until we reach the radius of the near plane (there can't be more occluders than that)
- angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
- } else {
- angular_diameter = 0.0;
- }
-
- if (light_data.shadow_enabled) {
- RS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base);
-
- int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
- light_data.blend_splits = storage->light_directional_get_blend_splits(base);
- for (int j = 0; j < 4; j++) {
- Rect2 atlas_rect = light_instance_get_directional_shadow_atlas_rect(li, j);
- CameraMatrix matrix = light_instance_get_shadow_camera(li, j);
- float split = light_instance_get_directional_shadow_split(li, MIN(limit, j));
-
- CameraMatrix bias;
- bias.set_light_bias();
- CameraMatrix rectm;
- rectm.set_light_atlas_rect(atlas_rect);
-
- Transform modelview = (p_camera_inverse_transform * light_instance_get_shadow_transform(li, j)).inverse();
-
- CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
- light_data.shadow_split_offsets[j] = split;
- float bias_scale = light_instance_get_shadow_bias_scale(li, j);
- light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale;
- light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j);
- light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale;
- light_data.shadow_transmittance_z_scale[j] = light_instance_get_shadow_range(li, j);
- light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j);
- store_camera(shadow_mtx, light_data.shadow_matrices[j]);
-
- Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j);
- uv_scale *= atlas_rect.size; //adapt to atlas size
- switch (j) {
- case 0: {
- light_data.uv_scale1[0] = uv_scale.x;
- light_data.uv_scale1[1] = uv_scale.y;
- } break;
- case 1: {
- light_data.uv_scale2[0] = uv_scale.x;
- light_data.uv_scale2[1] = uv_scale.y;
- } break;
- case 2: {
- light_data.uv_scale3[0] = uv_scale.x;
- light_data.uv_scale3[1] = uv_scale.y;
- } break;
- case 3: {
- light_data.uv_scale4[0] = uv_scale.x;
- light_data.uv_scale4[1] = uv_scale.y;
- } break;
- }
- }
-
- float fade_start = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);
- light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
- light_data.fade_to = -light_data.shadow_split_offsets[3];
-
- light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
- light_data.softshadow_angle = angular_diameter;
-
- if (angular_diameter <= 0.0) {
- light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
- }
- }
-
- // Copy to SkyDirectionalLightData
- if (sky_scene_state.directional_light_count < sky_scene_state.max_directional_lights) {
- SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.directional_light_count];
-
- Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
-
- sky_light_data.direction[0] = world_direction.x;
- sky_light_data.direction[1] = world_direction.y;
- sky_light_data.direction[2] = -world_direction.z;
-
- sky_light_data.energy = light_data.energy / Math_PI;
-
- sky_light_data.color[0] = light_data.color[0];
- sky_light_data.color[1] = light_data.color[1];
- sky_light_data.color[2] = light_data.color[2];
-
- sky_light_data.enabled = true;
- sky_light_data.size = angular_diameter;
- sky_scene_state.directional_light_count++;
- }
-
- scene_state.ubo.directional_light_count++;
- } break;
- case RS::LIGHT_SPOT:
- case RS::LIGHT_OMNI: {
- if (light_count >= scene_state.max_lights) {
- continue;
- }
-
- Transform light_transform = light_instance_get_base_transform(li);
-
- LightData &light_data = scene_state.lights[light_count];
-
- float sign = storage->light_is_negative(base) ? -1 : 1;
- Color linear_col = storage->light_get_color(base).to_linear();
-
- light_data.attenuation_energy[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION));
- light_data.attenuation_energy[1] = Math::make_half_float(sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI);
-
- light_data.color_specular[0] = MIN(uint32_t(linear_col.r * 255), 255);
- light_data.color_specular[1] = MIN(uint32_t(linear_col.g * 255), 255);
- light_data.color_specular[2] = MIN(uint32_t(linear_col.b * 255), 255);
- light_data.color_specular[3] = MIN(uint32_t(storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 255), 255);
-
- float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
- light_data.inv_radius = 1.0 / radius;
-
- Vector3 pos = p_camera_inverse_transform.xform(light_transform.origin);
-
- light_data.position[0] = pos.x;
- light_data.position[1] = pos.y;
- light_data.position[2] = pos.z;
-
- Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
-
- light_data.direction[0] = direction.x;
- light_data.direction[1] = direction.y;
- light_data.direction[2] = direction.z;
-
- float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
-
- light_data.size = size;
-
- light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION));
- float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
- light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle)));
-
- light_data.mask = storage->light_get_cull_mask(base);
-
- light_data.atlas_rect[0] = 0;
- light_data.atlas_rect[1] = 0;
- light_data.atlas_rect[2] = 0;
- light_data.atlas_rect[3] = 0;
-
- RID projector = storage->light_get_projector(base);
-
- if (projector.is_valid()) {
- Rect2 rect = storage->decal_atlas_get_texture_rect(projector);
-
- if (type == RS::LIGHT_SPOT) {
- light_data.projector_rect[0] = rect.position.x;
- light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped
- light_data.projector_rect[2] = rect.size.width;
- light_data.projector_rect[3] = -rect.size.height;
- } else {
- light_data.projector_rect[0] = rect.position.x;
- light_data.projector_rect[1] = rect.position.y;
- light_data.projector_rect[2] = rect.size.width;
- light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half
- }
- } else {
- light_data.projector_rect[0] = 0;
- light_data.projector_rect[1] = 0;
- light_data.projector_rect[2] = 0;
- light_data.projector_rect[3] = 0;
- }
-
- if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
- // fill in the shadow information
-
- Color shadow_color = storage->light_get_shadow_color(base);
-
- light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255);
- light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255);
- light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255);
- light_data.shadow_color_enabled[3] = 255;
-
- if (type == RS::LIGHT_SPOT) {
- light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0);
- float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0;
- shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas);
-
- light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size;
-
- } else { //omni
- light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0;
- float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas);
- light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space
- }
-
- light_data.transmittance_bias = storage->light_get_transmittance_bias(base);
-
- Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas);
-
- light_data.atlas_rect[0] = rect.position.x;
- light_data.atlas_rect[1] = rect.position.y;
- light_data.atlas_rect[2] = rect.size.width;
- light_data.atlas_rect[3] = rect.size.height;
-
- light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
-
- if (type == RS::LIGHT_OMNI) {
- light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
- Transform proj = (p_camera_inverse_transform * light_transform).inverse();
-
- store_transform(proj, light_data.shadow_matrix);
-
- if (size > 0.0) {
- light_data.soft_shadow_size = size;
- } else {
- light_data.soft_shadow_size = 0.0;
- light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
- }
-
- } else if (type == RS::LIGHT_SPOT) {
- Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
- CameraMatrix bias;
- bias.set_light_bias();
-
- CameraMatrix shadow_mtx = bias * light_instance_get_shadow_camera(li, 0) * modelview;
- store_camera(shadow_mtx, light_data.shadow_matrix);
-
- if (size > 0.0) {
- CameraMatrix cm = light_instance_get_shadow_camera(li, 0);
- float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle));
- light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
- } else {
- light_data.soft_shadow_size = 0.0;
- light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
- }
- }
- } else {
- light_data.shadow_color_enabled[3] = 0;
- }
-
- light_instance_set_index(li, light_count);
-
- cluster_builder.add_light(type == RS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
-
- light_count++;
- } break;
- }
-
- light_instance_set_render_pass(li, render_pass);
-
- //update UBO for forward rendering, blit to texture for clustered
- }
-
- if (light_count) {
- RD::get_singleton()->buffer_update(scene_state.light_buffer, 0, sizeof(LightData) * light_count, scene_state.lights, true);
- }
-
- if (scene_state.ubo.directional_light_count) {
- RD::get_singleton()->buffer_update(scene_state.directional_light_buffer, 0, sizeof(DirectionalLightData) * scene_state.ubo.directional_light_count, scene_state.directional_lights, true);
- }
-}
-
-void RasterizerSceneHighEndRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) {
- Transform uv_xform;
- uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
- uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
-
- p_decal_count = MIN((uint32_t)p_decal_count, scene_state.max_decals);
- int idx = 0;
- for (int i = 0; i < p_decal_count; i++) {
- RID di = p_decal_instances[i];
- RID decal = decal_instance_get_base(di);
-
- Transform xform = decal_instance_get_transform(di);
-
- float fade = 1.0;
-
- if (storage->decal_is_distance_fade_enabled(decal)) {
- real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
- float fade_begin = storage->decal_get_distance_fade_begin(decal);
- float fade_length = storage->decal_get_distance_fade_length(decal);
-
- if (distance > fade_begin) {
- if (distance > fade_begin + fade_length) {
- continue; // do not use this decal, its invisible
- }
-
- fade = 1.0 - (distance - fade_begin) / fade_length;
- }
- }
-
- DecalData &dd = scene_state.decals[idx];
-
- Vector3 decal_extents = storage->decal_get_extents(decal);
-
- Transform scale_xform;
- scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z));
- Transform to_decal_xform = (p_camera_inverse_xform * decal_instance_get_transform(di) * scale_xform * uv_xform).affine_inverse();
- store_transform(to_decal_xform, dd.xform);
-
- Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized();
- normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
-
- dd.normal[0] = normal.x;
- dd.normal[1] = normal.y;
- dd.normal[2] = normal.z;
- dd.normal_fade = storage->decal_get_normal_fade(decal);
-
- RID albedo_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ALBEDO);
- RID emission_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_EMISSION);
- if (albedo_tex.is_valid()) {
- Rect2 rect = storage->decal_atlas_get_texture_rect(albedo_tex);
- dd.albedo_rect[0] = rect.position.x;
- dd.albedo_rect[1] = rect.position.y;
- dd.albedo_rect[2] = rect.size.x;
- dd.albedo_rect[3] = rect.size.y;
- } else {
- if (!emission_tex.is_valid()) {
- continue; //no albedo, no emission, no decal.
- }
- dd.albedo_rect[0] = 0;
- dd.albedo_rect[1] = 0;
- dd.albedo_rect[2] = 0;
- dd.albedo_rect[3] = 0;
- }
-
- RID normal_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_NORMAL);
-
- if (normal_tex.is_valid()) {
- Rect2 rect = storage->decal_atlas_get_texture_rect(normal_tex);
- dd.normal_rect[0] = rect.position.x;
- dd.normal_rect[1] = rect.position.y;
- dd.normal_rect[2] = rect.size.x;
- dd.normal_rect[3] = rect.size.y;
-
- Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
- store_basis_3x4(normal_xform, dd.normal_xform);
- } else {
- dd.normal_rect[0] = 0;
- dd.normal_rect[1] = 0;
- dd.normal_rect[2] = 0;
- dd.normal_rect[3] = 0;
- }
-
- RID orm_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ORM);
- if (orm_tex.is_valid()) {
- Rect2 rect = storage->decal_atlas_get_texture_rect(orm_tex);
- dd.orm_rect[0] = rect.position.x;
- dd.orm_rect[1] = rect.position.y;
- dd.orm_rect[2] = rect.size.x;
- dd.orm_rect[3] = rect.size.y;
- } else {
- dd.orm_rect[0] = 0;
- dd.orm_rect[1] = 0;
- dd.orm_rect[2] = 0;
- dd.orm_rect[3] = 0;
- }
-
- if (emission_tex.is_valid()) {
- Rect2 rect = storage->decal_atlas_get_texture_rect(emission_tex);
- dd.emission_rect[0] = rect.position.x;
- dd.emission_rect[1] = rect.position.y;
- dd.emission_rect[2] = rect.size.x;
- dd.emission_rect[3] = rect.size.y;
- } else {
- dd.emission_rect[0] = 0;
- dd.emission_rect[1] = 0;
- dd.emission_rect[2] = 0;
- dd.emission_rect[3] = 0;
- }
-
- Color modulate = storage->decal_get_modulate(decal);
- dd.modulate[0] = modulate.r;
- dd.modulate[1] = modulate.g;
- dd.modulate[2] = modulate.b;
- dd.modulate[3] = modulate.a * fade;
- dd.emission_energy = storage->decal_get_emission_energy(decal) * fade;
- dd.albedo_mix = storage->decal_get_albedo_mix(decal);
- dd.mask = storage->decal_get_cull_mask(decal);
- dd.upper_fade = storage->decal_get_upper_fade(decal);
- dd.lower_fade = storage->decal_get_lower_fade(decal);
-
- cluster_builder.add_decal(xform, decal_extents);
-
- idx++;
- }
-
- if (idx > 0) {
- RD::get_singleton()->buffer_update(scene_state.decal_buffer, 0, sizeof(DecalData) * idx, scene_state.decals, true);
- }
-}
-
-void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) {
+void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) {
RenderBufferDataHighEnd *render_buffer = nullptr;
if (p_render_buffer.is_valid()) {
render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffer);
@@ -2147,19 +1587,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
RENDER_TIMESTAMP("Setup 3D Scene");
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
- p_light_cull_count = 0;
- p_reflection_probe_cull_count = 0;
- p_gi_probe_cull_count = 0;
- }
-
- bool using_shadows = true;
-
if (p_reflection_probe.is_valid()) {
scene_state.ubo.reflection_multiplier = 0.0;
- if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_reflection_probe))) {
- using_shadows = false;
- }
} else {
scene_state.ubo.reflection_multiplier = 1.0;
}
@@ -2169,6 +1598,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
Vector2 vp_he = p_cam_projection.get_viewport_half_extents();
scene_state.ubo.viewport_size[0] = vp_he.x;
scene_state.ubo.viewport_size[1] = vp_he.y;
+ scene_state.ubo.directional_light_count = p_directional_light_count;
Size2 screen_pixel_size;
Size2i screen_size;
@@ -2259,16 +1689,9 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
ERR_FAIL(); //bug?
}
- cluster_builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster
-
- _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
- _setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse());
- _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
_setup_lightmaps(p_lightmap_cull_result, p_lightmap_cull_count, p_cam_transform);
_setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false);
- cluster_builder.bake_cluster(); //bake to cluster
-
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
render_list.clear();
@@ -2284,6 +1707,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
}
RID radiance_uniform_set;
bool draw_sky = false;
+ bool draw_sky_fog_only = false;
Color clear_color;
bool keep_color = false;
@@ -2299,12 +1723,20 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
clear_color.r *= bg_energy;
clear_color.g *= bg_energy;
clear_color.b *= bg_energy;
+ if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
} break;
case RS::ENV_BG_COLOR: {
clear_color = environment_get_bg_color(p_environment);
clear_color.r *= bg_energy;
clear_color.g *= bg_energy;
clear_color.b *= bg_energy;
+ if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
} break;
case RS::ENV_BG_SKY: {
draw_sky = true;
@@ -2321,18 +1753,19 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
}
}
// setup sky if used for ambient, reflections, or background
- if (draw_sky || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ RENDER_TIMESTAMP("Setup Sky");
+ CameraMatrix projection = p_cam_projection;
+ if (p_reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ projection = correction * p_cam_projection;
+ }
+
+ _setup_sky(p_environment, p_render_buffer, projection, p_cam_transform, screen_size);
+
RID sky = environment_get_sky(p_environment);
if (sky.is_valid()) {
- RENDER_TIMESTAMP("Setup Sky");
- CameraMatrix projection = p_cam_projection;
- if (p_reflection_probe.is_valid()) {
- CameraMatrix correction;
- correction.set_depth_correction(true);
- projection = correction * p_cam_projection;
- }
-
- _setup_sky(p_environment, p_cam_transform.origin, screen_size);
_update_sky(p_environment, projection, p_cam_transform);
radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);
} else {
@@ -2367,6 +1800,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
RD::get_singleton()->draw_list_end();
if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ RENDER_TIMESTAMP("Resolve Depth Pre-Pass");
if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) {
static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 };
storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]);
@@ -2400,8 +1834,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
{
- bool will_continue_color = (can_continue_color || draw_sky || debug_giprobes || debug_sdfgi_probes);
- bool will_continue_depth = (can_continue_depth || draw_sky || debug_giprobes || debug_sdfgi_probes);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
//regular forward for now
Vector<Color> c;
@@ -2428,8 +1862,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
if (debug_giprobes) {
//debug giprobes
- bool will_continue_color = (can_continue_color || draw_sky);
- bool will_continue_depth = (can_continue_depth || draw_sky);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
CameraMatrix dc;
dc.set_depth_correction(true);
@@ -2443,8 +1877,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
if (debug_sdfgi_probes) {
//debug giprobes
- bool will_continue_color = (can_continue_color || draw_sky);
- bool will_continue_depth = (can_continue_depth || draw_sky);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
CameraMatrix dc;
dc.set_depth_correction(true);
@@ -2454,7 +1888,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
RD::get_singleton()->draw_list_end();
}
- if (draw_sky) {
+ if (draw_sky || draw_sky_fog_only) {
RENDER_TIMESTAMP("Render Sky");
CameraMatrix projection = p_cam_projection;
@@ -2745,7 +2179,7 @@ void RasterizerSceneHighEndRD::_render_sdfgi(RID p_render_buffers, const Vector3
to_bounds.origin = p_bounds.position;
to_bounds.basis.scale(p_bounds.size);
- store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds);
+ RasterizerStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds);
_setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0);
@@ -2826,22 +2260,22 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 5;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(scene_state.light_buffer);
+ u.ids.push_back(get_positional_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 6;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.reflection_buffer);
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 7;
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.directional_light_buffer);
+ u.ids.push_back(get_directional_light_buffer());
uniforms.push_back(u);
}
{
@@ -2885,7 +2319,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 15;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(scene_state.decal_buffer);
+ u.ids.push_back(get_decal_buffer());
uniforms.push_back(u);
}
@@ -2893,14 +2327,14 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 16;
u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(cluster_builder.get_cluster_texture());
+ u.ids.push_back(get_cluster_builder_texture());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 17;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cluster_builder.get_cluster_indices_buffer());
+ u.ids.push_back(get_cluster_builder_indices_buffer());
uniforms.push_back(u);
}
@@ -3115,7 +2549,22 @@ void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_b
u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers));
uniforms.push_back(u);
}
-
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID vfog = RID();
+ if (p_render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_buffers)) {
+ vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers);
+ if (vfog.is_null()) {
+ vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ }
+ } else {
+ vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ }
+ u.ids.push_back(vfog);
+ uniforms.push_back(u);
+ }
rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
}
}
@@ -3141,37 +2590,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
defines += "\n#define SDFGI_OCT_SIZE " + itos(sdfgi_get_lightprobe_octahedron_size()) + "\n";
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
- uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
-
- { //reflections
- uint32_t reflection_buffer_size;
- if (uniform_max_size < 65536) {
- //Yes, you guessed right, ARM again
- reflection_buffer_size = uniform_max_size;
- } else {
- reflection_buffer_size = 65536;
- }
-
- scene_state.max_reflections = reflection_buffer_size / sizeof(ReflectionData);
- scene_state.reflections = memnew_arr(ReflectionData, scene_state.max_reflections);
- scene_state.reflection_buffer = RD::get_singleton()->uniform_buffer_create(reflection_buffer_size);
- defines += "\n#define MAX_REFLECTION_DATA_STRUCTS " + itos(scene_state.max_reflections) + "\n";
- }
-
- { //lights
- scene_state.max_lights = MIN(1024 * 1024, uniform_max_size) / sizeof(LightData); //1mb of lights
- uint32_t light_buffer_size = scene_state.max_lights * sizeof(LightData);
- scene_state.lights = memnew_arr(LightData, scene_state.max_lights);
- scene_state.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
- //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n";
-
- scene_state.max_directional_lights = 8;
- uint32_t directional_light_buffer_size = scene_state.max_directional_lights * sizeof(DirectionalLightData);
- scene_state.directional_lights = memnew_arr(DirectionalLightData, scene_state.max_directional_lights);
- scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
- defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(scene_state.max_directional_lights) + "\n";
- }
{
//lightmaps
scene_state.max_lightmaps = storage->lightmap_array_get_size();
@@ -3187,13 +2607,6 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
scene_state.lightmap_captures = memnew_arr(LightmapCaptureData, scene_state.max_lightmap_captures);
scene_state.lightmap_capture_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapCaptureData) * scene_state.max_lightmap_captures);
}
- { //decals
- scene_state.max_decals = MIN(1024 * 1024, uniform_max_size) / sizeof(DecalData); //1mb of decals
- uint32_t decal_buffer_size = scene_state.max_decals * sizeof(DecalData);
- scene_state.decals = memnew_arr(DecalData, scene_state.max_decals);
- scene_state.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
- }
-
{
defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
}
@@ -3464,11 +2877,16 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
u.ids.push_back(render_buffers_get_default_gi_probe_buffer());
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ uniforms.push_back(u);
+ }
default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
}
-
- cluster_builder.setup(16, 8, 24);
}
RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() {
@@ -3495,19 +2913,11 @@ RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() {
{
RD::get_singleton()->free(scene_state.uniform_buffer);
RD::get_singleton()->free(scene_state.instance_buffer);
- RD::get_singleton()->free(scene_state.directional_light_buffer);
- RD::get_singleton()->free(scene_state.light_buffer);
RD::get_singleton()->free(scene_state.lightmap_buffer);
RD::get_singleton()->free(scene_state.lightmap_capture_buffer);
- RD::get_singleton()->free(scene_state.reflection_buffer);
- RD::get_singleton()->free(scene_state.decal_buffer);
memdelete_arr(scene_state.instances);
- memdelete_arr(scene_state.directional_lights);
- memdelete_arr(scene_state.lights);
memdelete_arr(scene_state.lightmaps);
memdelete_arr(scene_state.lightmap_captures);
- memdelete_arr(scene_state.reflections);
- memdelete_arr(scene_state.decals);
}
while (sdfgi_framebuffer_size_cache.front()) {
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
index cb03da48c1..1aad9039ff 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
@@ -31,7 +31,6 @@
#ifndef RASTERIZER_SCENE_HIGHEND_RD_H
#define RASTERIZER_SCENE_HIGHEND_RD_H
-#include "servers/rendering/rasterizer_rd/light_cluster_builder.h"
#include "servers/rendering/rasterizer_rd/rasterizer_scene_rd.h"
#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h"
#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h"
@@ -264,92 +263,10 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
void _setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count);
void _update_render_buffers_uniform_set(RID p_render_buffers);
- /* Scene State UBO */
-
- struct ReflectionData { //should always be 128 bytes
- float box_extents[3];
- float index;
- float box_offset[3];
- uint32_t mask;
- float params[4]; // intensity, 0, interior , boxproject
- float ambient[3]; // ambient color,
- uint32_t ambient_mode;
- float local_matrix[16]; // up to here for spot and omni, rest is for directional
- };
-
- struct LightData {
- float position[3];
- float inv_radius;
- float direction[3];
- float size;
- uint16_t attenuation_energy[2]; //16 bits attenuation, then energy
- uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm)
- uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float)
- uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm)
- float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
- float shadow_matrix[16];
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size;
- float soft_shadow_scale;
- uint32_t mask;
- uint32_t pad[2];
- float projector_rect[4];
- };
-
- struct DirectionalLightData {
- float direction[3];
- float energy;
- float color[3];
- float size;
- float specular;
- uint32_t mask;
- float softshadow_angle;
- float soft_shadow_scale;
- uint32_t blend_splits;
- uint32_t shadow_enabled;
- float fade_from;
- float fade_to;
- float shadow_bias[4];
- float shadow_normal_bias[4];
- float shadow_transmittance_bias[4];
- float shadow_transmittance_z_scale[4];
- float shadow_range_begin[4];
- float shadow_split_offsets[4];
- float shadow_matrices[4][16];
- float shadow_color1[4];
- float shadow_color2[4];
- float shadow_color3[4];
- float shadow_color4[4];
- float uv_scale1[2];
- float uv_scale2[2];
- float uv_scale3[2];
- float uv_scale4[2];
- };
-
struct LightmapData {
float normal_xform[12];
};
- struct DecalData {
- float xform[16];
- float inv_extents[3];
- float albedo_mix;
- float albedo_rect[4];
- float normal_rect[4];
- float orm_rect[4];
- float emission_rect[4];
- float modulate[4];
- float emission_energy;
- uint32_t mask;
- float upper_fade;
- float lower_fade;
- float normal_xform[12];
- float normal[3];
- float normal_fade;
- };
-
struct LightmapCaptureData {
float sh[9 * 4];
};
@@ -442,33 +359,31 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
int32_t sdf_size[3];
uint32_t gi_upscale_for_msaa;
+
+ uint32_t volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+ uint32_t volumetric_fog_pad;
+
+ // Fog
+
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
};
UBO ubo;
RID uniform_buffer;
- ReflectionData *reflections;
- uint32_t max_reflections;
- RID reflection_buffer;
- uint32_t max_reflection_probes_per_instance;
-
LightmapData *lightmaps;
uint32_t max_lightmaps;
RID lightmap_buffer;
- DecalData *decals;
- uint32_t max_decals;
- RID decal_buffer;
-
- LightData *lights;
- uint32_t max_lights;
- RID light_buffer;
-
- DirectionalLightData *directional_lights;
- uint32_t max_directional_lights;
- RID directional_light_buffer;
-
LightmapCaptureData *lightmap_captures;
uint32_t max_lightmap_captures;
RID lightmap_capture_buffer;
@@ -635,8 +550,6 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
RID default_vec4_xform_buffer;
RID default_vec4_xform_uniform_set;
- LightClusterBuilder cluster_builder;
-
enum PassMode {
PASS_MODE_COLOR,
PASS_MODE_COLOR_SPECULAR,
@@ -651,9 +564,6 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
};
void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false);
- void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows);
- void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform);
- void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
void _setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform);
void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi = false, bool p_has_opaque_gi = false);
@@ -666,7 +576,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
Map<Size2i, RID> sdfgi_framebuffer_size_cache;
protected:
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color);
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color);
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake);
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index 4ebed78996..34818d2683 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -227,6 +227,7 @@ void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) {
RD::get_singleton()->free(rb->sdfgi->lightprobe_data);
RD::get_singleton()->free(rb->sdfgi->lightprobe_history_scroll);
RD::get_singleton()->free(rb->sdfgi->occlusion_data);
+ RD::get_singleton()->free(rb->sdfgi->ambient_texture);
RD::get_singleton()->free(rb->sdfgi->cascades_ubo);
@@ -238,7 +239,7 @@ void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) {
const Vector3i RasterizerSceneRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF);
void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
- Environent *env = environment_owner.getornull(p_environment);
+ Environment *env = environment_owner.getornull(p_environment);
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
bool needs_sdfgi = env && env->sdfgi_enabled;
@@ -371,6 +372,16 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co
RD::TextureView tv;
tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
sdfgi->lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->lightprobe_data);
+
+ //texture handling ambient data, to integrate with volumetric foc
+ RD::TextureFormat tf_ambient = tf_probes;
+ tf_ambient.array_layers = sdfgi->cascades.size();
+ tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE
+ tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count;
+ tf_ambient.height = sdfgi->probe_axis_count;
+ tf_ambient.type = RD::TEXTURE_TYPE_2D_ARRAY;
+ //lightprobe texture is an octahedral texture
+ sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());
}
sdfgi->cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES);
@@ -925,11 +936,18 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co
if (i < sdfgi->cascades.size() - 1) {
parent_average = sdfgi->cascades[i + 1].lightprobe_average_tex;
} else {
- parent_average = sdfgi->cascades[i - 1].lightprobe_average_tex; //to use something, but it wont be used
+ parent_average = sdfgi->cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used
}
u.ids.push_back(parent_average);
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 14;
+ u.ids.push_back(sdfgi->ambient_texture);
+ uniforms.push_back(u);
+ }
sdfgi->cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 0);
}
@@ -1142,7 +1160,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm
if (rb->sdfgi == nullptr) {
return;
}
- Environent *env = environment_owner.getornull(p_environment);
+ Environment *env = environment_owner.getornull(p_environment);
RENDER_TIMESTAMP(">SDFGI Update Probes");
@@ -1282,6 +1300,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm
push_constant.ray_bias = rb->sdfgi->probe_bias;
push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
push_constant.image_size[1] = rb->sdfgi->probe_axis_count;
+ push_constant.store_ambient_texture = env->volumetric_fog_enabled;
RID sky_uniform_set = sdfgi_shader.integrate_default_sky_uniform_set;
push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_DISABLED;
@@ -1375,12 +1394,102 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm
RENDER_TIMESTAMP("<SDFGI Update Probes");
}
+void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used) {
+ r_gi_probes_used = 0;
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+
+ RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers);
+ GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES];
+
+ bool giprobes_changed = false;
+
+ Transform to_camera;
+ to_camera.origin = p_transform.origin; //only translation, make local
+
+ for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
+ RID texture;
+ if (i < p_gi_probe_cull_count) {
+ GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]);
+
+ if (gipi) {
+ texture = gipi->texture;
+ GI::GIProbeData &gipd = gi_probe_data[i];
+
+ RID base_probe = gipi->probe;
+
+ Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
+
+ gipd.xform[0] = to_cell.basis.elements[0][0];
+ gipd.xform[1] = to_cell.basis.elements[1][0];
+ gipd.xform[2] = to_cell.basis.elements[2][0];
+ gipd.xform[3] = 0;
+ gipd.xform[4] = to_cell.basis.elements[0][1];
+ gipd.xform[5] = to_cell.basis.elements[1][1];
+ gipd.xform[6] = to_cell.basis.elements[2][1];
+ gipd.xform[7] = 0;
+ gipd.xform[8] = to_cell.basis.elements[0][2];
+ gipd.xform[9] = to_cell.basis.elements[1][2];
+ gipd.xform[10] = to_cell.basis.elements[2][2];
+ gipd.xform[11] = 0;
+ gipd.xform[12] = to_cell.origin.x;
+ gipd.xform[13] = to_cell.origin.y;
+ gipd.xform[14] = to_cell.origin.z;
+ gipd.xform[15] = 1;
+
+ Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+
+ gipd.bounds[0] = bounds.x;
+ gipd.bounds[1] = bounds.y;
+ gipd.bounds[2] = bounds.z;
+
+ gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
+ gipd.bias = storage->gi_probe_get_bias(base_probe);
+ gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
+ gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
+ gipd.anisotropy_strength = 0;
+ gipd.ao = storage->gi_probe_get_ao(base_probe);
+ gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
+ gipd.mipmaps = gipi->mipmaps.size();
+ }
+
+ r_gi_probes_used++;
+ }
+
+ if (texture == RID()) {
+ texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ }
+
+ if (texture != rb->giprobe_textures[i]) {
+ giprobes_changed = true;
+ rb->giprobe_textures[i] = texture;
+ }
+ }
+
+ if (giprobes_changed) {
+ RD::get_singleton()->free(rb->gi_uniform_set);
+ rb->gi_uniform_set = RID();
+ if (rb->volumetric_fog) {
+ if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+ }
+ rb->volumetric_fog->uniform_set = RID();
+ rb->volumetric_fog->uniform_set2 = RID();
+ }
+ }
+
+ if (p_gi_probe_cull_count > 0) {
+ RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true);
+ }
+}
+
void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) {
RENDER_TIMESTAMP("Render GI");
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(rb == nullptr);
- Environent *env = environment_owner.getornull(p_environment);
+ Environment *env = environment_owner.getornull(p_environment);
GI::PushConstant push_constant;
@@ -1490,81 +1599,6 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness
RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, true);
}
- {
- RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers);
- GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES];
-
- bool giprobes_changed = false;
-
- Transform to_camera;
- to_camera.origin = p_transform.origin; //only translation, make local
-
- for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
- RID texture;
- if (i < p_gi_probe_cull_count) {
- GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]);
-
- if (gipi) {
- texture = gipi->texture;
- GI::GIProbeData &gipd = gi_probe_data[i];
-
- RID base_probe = gipi->probe;
-
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
-
- gipd.xform[0] = to_cell.basis.elements[0][0];
- gipd.xform[1] = to_cell.basis.elements[1][0];
- gipd.xform[2] = to_cell.basis.elements[2][0];
- gipd.xform[3] = 0;
- gipd.xform[4] = to_cell.basis.elements[0][1];
- gipd.xform[5] = to_cell.basis.elements[1][1];
- gipd.xform[6] = to_cell.basis.elements[2][1];
- gipd.xform[7] = 0;
- gipd.xform[8] = to_cell.basis.elements[0][2];
- gipd.xform[9] = to_cell.basis.elements[1][2];
- gipd.xform[10] = to_cell.basis.elements[2][2];
- gipd.xform[11] = 0;
- gipd.xform[12] = to_cell.origin.x;
- gipd.xform[13] = to_cell.origin.y;
- gipd.xform[14] = to_cell.origin.z;
- gipd.xform[15] = 1;
-
- Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
-
- gipd.bounds[0] = bounds.x;
- gipd.bounds[1] = bounds.y;
- gipd.bounds[2] = bounds.z;
-
- gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
- gipd.bias = storage->gi_probe_get_bias(base_probe);
- gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
- gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
- gipd.anisotropy_strength = 0;
- gipd.ao = storage->gi_probe_get_ao(base_probe);
- gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
- }
- }
-
- if (texture == RID()) {
- texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- }
-
- if (texture != rb->giprobe_textures[i]) {
- giprobes_changed = true;
- rb->giprobe_textures[i] = texture;
- }
- }
-
- if (giprobes_changed) {
- RD::get_singleton()->free(rb->gi_uniform_set);
- rb->gi_uniform_set = RID();
- }
-
- if (p_gi_probe_cull_count > 0) {
- RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true);
- }
- }
-
if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
Vector<RD::Uniform> uniforms;
{
@@ -1881,7 +1915,7 @@ void RasterizerSceneRD::_update_dirty_skys() {
texture_set_dirty = true;
}
- // Create subpass buffers if they havent been created already
+ // Create subpass buffers if they haven't been created already
if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
RD::TextureFormat tformat;
tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
@@ -2032,22 +2066,33 @@ RID RasterizerSceneRD::sky_get_material(RID p_sky) const {
void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
ERR_FAIL_COND(!is_environment(p_environment));
+ SkyMaterialData *material = nullptr;
+
Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
- ERR_FAIL_COND(!sky);
- RID sky_material = sky_get_material(environment_get_sky(p_environment));
+ RID sky_material;
- SkyMaterialData *material = nullptr;
+ RS::EnvironmentBG background = environment_get_background(p_environment);
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(environment_get_sky(p_environment));
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
}
}
- if (!material) {
- sky_material = sky_shader.default_material;
+ if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_scene_state.fog_material;
material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
}
@@ -2087,7 +2132,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
@@ -2100,149 +2145,191 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
+ RID texture_uniform_set;
+ if (sky) {
+ texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
+ } else {
+ texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
+ }
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
-void RasterizerSceneRD::_setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size) {
+void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) {
ERR_FAIL_COND(!is_environment(p_environment));
+ SkyMaterialData *material = nullptr;
+
Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
- ERR_FAIL_COND(!sky);
- RID sky_material = sky_get_material(environment_get_sky(p_environment));
+ RID sky_material;
- SkyMaterialData *material = nullptr;
+ SkyShaderData *shader_data = nullptr;
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
+ RS::EnvironmentBG background = environment_get_background(p_environment);
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(environment_get_sky(p_environment));
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
}
- }
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
- }
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+ }
- ERR_FAIL_COND(!material);
+ ERR_FAIL_COND(!material);
- SkyShaderData *shader_data = material->shader_data;
+ shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_COND(!shader_data);
+ }
- // Invalidate supbass buffers if screen size changes
- if (sky->screen_size != p_screen_size) {
- sky->screen_size = p_screen_size;
- sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
- sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
- if (shader_data->uses_half_res) {
- if (sky->half_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->half_res_pass);
- sky->half_res_pass = RID();
+ if (sky) {
+ // Invalidate supbass buffers if screen size changes
+ if (sky->screen_size != p_screen_size) {
+ sky->screen_size = p_screen_size;
+ sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
+ sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
+ if (shader_data->uses_half_res) {
+ if (sky->half_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->half_res_pass);
+ sky->half_res_pass = RID();
+ }
+ _sky_invalidate(sky);
}
- _sky_invalidate(sky);
- }
- if (shader_data->uses_quarter_res) {
- if (sky->quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->quarter_res_pass);
- sky->quarter_res_pass = RID();
+ if (shader_data->uses_quarter_res) {
+ if (sky->quarter_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->quarter_res_pass);
+ sky->quarter_res_pass = RID();
+ }
+ _sky_invalidate(sky);
}
+ }
+
+ // Create new subpass buffers if necessary
+ if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
+ (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
+ sky->radiance.is_null()) {
_sky_invalidate(sky);
+ _update_dirty_skys();
}
- }
- // Create new subpass buffers if necessary
- if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
- (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
- sky->radiance.is_null()) {
- _sky_invalidate(sky);
- _update_dirty_skys();
- }
+ if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
+ sky->prev_time = time;
+ sky->reflection.dirty = true;
+ RenderingServerRaster::redraw_request();
+ }
- if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
- sky->prev_time = time;
- sky->reflection.dirty = true;
- RenderingServerRaster::redraw_request();
- }
+ if (material != sky->prev_material) {
+ sky->prev_material = material;
+ sky->reflection.dirty = true;
+ }
- if (material != sky->prev_material) {
- sky->prev_material = material;
- sky->reflection.dirty = true;
- }
+ if (material->uniform_set_updated) {
+ material->uniform_set_updated = false;
+ sky->reflection.dirty = true;
+ }
- if (material->uniform_set_updated) {
- material->uniform_set_updated = false;
- sky->reflection.dirty = true;
- }
+ if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_transform.origin;
+ sky->reflection.dirty = true;
+ }
- if (!p_position.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
- sky->prev_position = p_position;
- sky->reflection.dirty = true;
- }
+ if (shader_data->uses_light) {
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
- if (shader_data->uses_light || sky_scene_state.light_uniform_set.is_null()) {
- // Check whether the directional_light_buffer changes
- bool light_data_dirty = false;
-
- if (sky_scene_state.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
- light_data_dirty = true;
- for (uint32_t i = sky_scene_state.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
- sky_scene_state.directional_lights[i].enabled = false;
- }
- }
- if (!light_data_dirty) {
- for (uint32_t i = 0; i < sky_scene_state.directional_light_count; i++) {
- if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
- sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
- sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
- sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
- sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
- sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
- sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
- sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
- sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
- light_data_dirty = true;
- break;
+ if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
+ sky_scene_state.directional_lights[i].enabled = false;
+ }
+ }
+ if (!light_data_dirty) {
+ for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) {
+ if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
+ sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
+ sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
+ sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
+ sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
+ sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
+ sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
+ sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
+ sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
+ light_data_dirty = true;
+ break;
+ }
}
}
+
+ if (light_data_dirty) {
+ RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true);
+
+ RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
+ sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
+ sky_scene_state.directional_lights = temp;
+ sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count;
+ sky->reflection.dirty = true;
+ }
}
+ }
- if (light_data_dirty || sky_scene_state.light_uniform_set.is_null()) {
- RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true);
+ //setup fog variables
+ sky_scene_state.ubo.volumetric_fog_enabled = false;
+ if (p_render_buffers.is_valid()) {
+ if (render_buffers_has_volumetric_fog(p_render_buffers)) {
+ sky_scene_state.ubo.volumetric_fog_enabled = true;
- if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+ float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+ if (fog_end > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
}
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 0;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(sky_scene_state.directional_light_buffer);
- uniforms.push_back(u);
+ float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
}
+ }
- sky_scene_state.light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_LIGHTS);
+ RID fog_uniform_set = render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
- RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
- sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
- sky_scene_state.directional_lights = temp;
- sky_scene_state.last_frame_directional_light_count = sky_scene_state.directional_light_count;
- sky->reflection.dirty = true;
+ if (fog_uniform_set != RID()) {
+ sky_scene_state.fog_uniform_set = fog_uniform_set;
+ } else {
+ sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
}
}
+
+ sky_scene_state.ubo.z_far = p_projection.get_z_far();
+ sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
+ sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
+ Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
+ float fog_energy = environment_get_fog_light_energy(p_environment);
+ sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+ sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
+
+ RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo, true);
}
void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
@@ -2337,7 +2424,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
}
@@ -2355,7 +2442,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_HALF_RES);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
}
@@ -2369,7 +2456,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
@@ -2695,53 +2782,53 @@ RasterizerStorageRD::MaterialData *RasterizerSceneRD::_create_sky_material_func(
}
RID RasterizerSceneRD::environment_create() {
- return environment_owner.make_rid(Environent());
+ return environment_owner.make_rid(Environment());
}
void RasterizerSceneRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->background = p_bg;
}
void RasterizerSceneRD::environment_set_sky(RID p_env, RID p_sky) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky = p_sky;
}
void RasterizerSceneRD::environment_set_sky_custom_fov(RID p_env, float p_scale) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky_custom_fov = p_scale;
}
void RasterizerSceneRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky_orientation = p_orientation;
}
void RasterizerSceneRD::environment_set_bg_color(RID p_env, const Color &p_color) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->bg_color = p_color;
}
void RasterizerSceneRD::environment_set_bg_energy(RID p_env, float p_energy) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->bg_energy = p_energy;
}
void RasterizerSceneRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->canvas_max_layer = p_max_layer;
}
void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->ambient_light = p_color;
env->ambient_source = p_ambient;
@@ -2752,85 +2839,85 @@ void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_
}
RS::EnvironmentBG RasterizerSceneRD::environment_get_background(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX);
return env->background;
}
RID RasterizerSceneRD::environment_get_sky(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RID());
return env->sky;
}
float RasterizerSceneRD::environment_get_sky_custom_fov(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->sky_custom_fov;
}
Basis RasterizerSceneRD::environment_get_sky_orientation(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Basis());
return env->sky_orientation;
}
Color RasterizerSceneRD::environment_get_bg_color(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->bg_color;
}
float RasterizerSceneRD::environment_get_bg_energy(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->bg_energy;
}
int RasterizerSceneRD::environment_get_canvas_max_layer(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->canvas_max_layer;
}
Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->ambient_light;
}
RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_source(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG);
return env->ambient_source;
}
float RasterizerSceneRD::environment_get_ambient_light_energy(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_light_energy;
}
float RasterizerSceneRD::environment_get_ambient_sky_contribution(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_sky_contribution;
}
RS::EnvironmentReflectionSource RasterizerSceneRD::environment_get_reflection_source(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED);
return env->reflection_source;
}
Color RasterizerSceneRD::environment_get_ao_color(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->ao_color;
}
void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->exposure = p_exposure;
env->tone_mapper = p_tone_mapper;
@@ -2846,7 +2933,7 @@ void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMa
}
void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->glow_enabled = p_enable;
env->glow_levels = p_level_flags;
@@ -2865,7 +2952,7 @@ void RasterizerSceneRD::environment_glow_set_use_bicubic_upscale(bool p_enable)
}
void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sdfgi_enabled = p_enable;
@@ -2880,6 +2967,99 @@ void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::Envi
env->sdfgi_y_scale = p_y_scale;
}
+void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->fog_enabled = p_enable;
+ env->fog_light_color = p_light_color;
+ env->fog_light_energy = p_light_energy;
+ env->fog_sun_scatter = p_sun_scatter;
+ env->fog_density = p_density;
+ env->fog_height = p_height;
+ env->fog_height_density = p_height_density;
+}
+
+bool RasterizerSceneRD::environment_is_fog_enabled(RID p_env) const {
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, false);
+
+ return env->fog_enabled;
+}
+Color RasterizerSceneRD::environment_get_fog_light_color(RID p_env) const {
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, Color());
+ return env->fog_light_color;
+}
+float RasterizerSceneRD::environment_get_fog_light_energy(RID p_env) const {
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->fog_light_energy;
+}
+float RasterizerSceneRD::environment_get_fog_sun_scatter(RID p_env) const {
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->fog_sun_scatter;
+}
+float RasterizerSceneRD::environment_get_fog_density(RID p_env) const {
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->fog_density;
+}
+float RasterizerSceneRD::environment_get_fog_height(RID p_env) const {
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+
+ return env->fog_height;
+}
+float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const {
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->fog_height_density;
+}
+
+void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->volumetric_fog_enabled = p_enable;
+ env->volumetric_fog_density = p_density;
+ env->volumetric_fog_light = p_light;
+ env->volumetric_fog_light_energy = p_light_energy;
+ env->volumetric_fog_length = p_length;
+ env->volumetric_fog_detail_spread = p_detail_spread;
+ env->volumetric_fog_shadow_filter = p_shadow_filter;
+ env->volumetric_fog_gi_inject = p_gi_inject;
+}
+
+void RasterizerSceneRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) {
+ volumetric_fog_size = p_size;
+ volumetric_fog_depth = p_depth;
+}
+
+void RasterizerSceneRD::environment_set_volumetric_fog_filter_active(bool p_enable) {
+ volumetric_fog_filter_active = p_enable;
+}
+void RasterizerSceneRD::environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) {
+ p_shrink_size = nearest_power_of_2_templated(p_shrink_size);
+ if (volumetric_fog_directional_shadow_shrink == (uint32_t)p_shrink_size) {
+ return;
+ }
+
+ _clear_shadow_shrink_stages(directional_shadow.shrink_stages);
+}
+void RasterizerSceneRD::environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) {
+ p_shrink_size = nearest_power_of_2_templated(p_shrink_size);
+ if (volumetric_fog_positional_shadow_shrink == (uint32_t)p_shrink_size) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < shadow_atlas_owner.get_rid_count(); i++) {
+ ShadowAtlas *sa = shadow_atlas_owner.get_ptr_by_index(i);
+ _clear_shadow_shrink_stages(sa->shrink_stages);
+ }
+}
+
void RasterizerSceneRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) {
sdfgi_ray_count = p_ray_count;
}
@@ -2889,7 +3069,7 @@ void RasterizerSceneRD::environment_set_sdfgi_frames_to_converge(RS::Environment
}
void RasterizerSceneRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->ssr_enabled = p_enable;
@@ -2908,7 +3088,7 @@ RS::EnvironmentSSRRoughnessQuality RasterizerSceneRD::environment_get_ssr_roughn
}
void RasterizerSceneRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->ssao_enabled = p_enable;
@@ -2926,30 +3106,30 @@ void RasterizerSceneRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality
}
bool RasterizerSceneRD::environment_is_ssao_enabled(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssao_enabled;
}
float RasterizerSceneRD::environment_get_ssao_ao_affect(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssao_ao_channel_affect;
}
float RasterizerSceneRD::environment_get_ssao_light_affect(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssao_direct_light_affect;
}
bool RasterizerSceneRD::environment_is_ssr_enabled(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssr_enabled;
}
bool RasterizerSceneRD::environment_is_sdfgi_enabled(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->sdfgi_enabled;
}
@@ -2959,7 +3139,7 @@ bool RasterizerSceneRD::is_environment(RID p_env) const {
}
Ref<Image> RasterizerSceneRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) {
- Environent *env = environment_owner.getornull(p_env);
+ Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Ref<Image>());
if (env->background == RS::ENV_BG_CAMERA_FEED || env->background == RS::ENV_BG_CANVAS || env->background == RS::ENV_BG_KEEP) {
@@ -3286,6 +3466,7 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) {
if (shadow_atlas->depth.is_valid()) {
RD::get_singleton()->free(shadow_atlas->depth);
shadow_atlas->depth = RID();
+ _clear_shadow_shrink_stages(shadow_atlas->shrink_stages);
}
for (int i = 0; i < 4; i++) {
//clear subdivisions
@@ -3579,6 +3760,7 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) {
if (directional_shadow.depth.is_valid()) {
RD::get_singleton()->free(directional_shadow.depth);
+ _clear_shadow_shrink_stages(directional_shadow.shrink_stages);
directional_shadow.depth = RID();
}
@@ -4903,7 +5085,7 @@ void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffe
return;
}
- Environent *env = environment_owner.getornull(p_environment);
+ Environment *env = environment_owner.getornull(p_environment);
ERR_FAIL_COND(!env);
ERR_FAIL_COND(!env->ssr_enabled);
@@ -4948,9 +5130,11 @@ void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, R
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environent *env = environment_owner.getornull(p_environment);
+ Environment *env = environment_owner.getornull(p_environment);
ERR_FAIL_COND(!env);
+ RENDER_TIMESTAMP("Process SSAO");
+
if (rb->ssao.ao[0].is_valid() && rb->ssao.ao_full.is_valid() != ssao_half_size) {
RD::get_singleton()->free(rb->ssao.depth);
RD::get_singleton()->free(rb->ssao.ao[0]);
@@ -5015,7 +5199,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environent *env = environment_owner.getornull(p_environment);
+ Environment *env = environment_owner.getornull(p_environment);
//glow (if enabled)
CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
@@ -5463,6 +5647,41 @@ RID RasterizerSceneRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_b
return rb->sdfgi->occlusion_texture;
}
+bool RasterizerSceneRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const {
+ const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, false);
+
+ return rb->volumetric_fog != nullptr;
+}
+RID RasterizerSceneRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) {
+ const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID());
+
+ return rb->volumetric_fog->fog_map;
+}
+
+RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) {
+ const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, RID());
+
+ if (!rb->volumetric_fog) {
+ return RID();
+ }
+
+ return rb->volumetric_fog->sky_uniform_set;
+}
+
+float RasterizerSceneRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) {
+ const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
+ return rb->volumetric_fog->length;
+}
+float RasterizerSceneRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) {
+ const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
+ return rb->volumetric_fog->spread;
+}
+
void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
rb->width = p_width;
@@ -5619,6 +5838,1090 @@ RasterizerSceneRD::RenderBufferData *RasterizerSceneRD::render_buffers_get_data(
return rb->data;
}
+void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) {
+ for (int i = 0; i < p_reflection_probe_cull_count; i++) {
+ RID rpi = p_reflection_probe_cull_result[i];
+
+ if (i >= (int)cluster.max_reflections) {
+ reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set
+ continue;
+ }
+
+ reflection_probe_instance_set_render_index(rpi, i);
+
+ RID base_probe = reflection_probe_instance_get_probe(rpi);
+
+ Cluster::ReflectionData &reflection_ubo = cluster.reflections[i];
+
+ Vector3 extents = storage->reflection_probe_get_extents(base_probe);
+
+ reflection_ubo.box_extents[0] = extents.x;
+ reflection_ubo.box_extents[1] = extents.y;
+ reflection_ubo.box_extents[2] = extents.z;
+ reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi);
+
+ Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe);
+
+ reflection_ubo.box_offset[0] = origin_offset.x;
+ reflection_ubo.box_offset[1] = origin_offset.y;
+ reflection_ubo.box_offset[2] = origin_offset.z;
+ reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe);
+
+ float intensity = storage->reflection_probe_get_intensity(base_probe);
+ bool interior = storage->reflection_probe_is_interior(base_probe);
+ bool box_projection = storage->reflection_probe_is_box_projection(base_probe);
+
+ reflection_ubo.params[0] = intensity;
+ reflection_ubo.params[1] = 0;
+ reflection_ubo.params[2] = interior ? 1.0 : 0.0;
+ reflection_ubo.params[3] = box_projection ? 1.0 : 0.0;
+
+ Color ambient_linear = storage->reflection_probe_get_ambient_color(base_probe).to_linear();
+ float interior_ambient_energy = storage->reflection_probe_get_ambient_color_energy(base_probe);
+ uint32_t ambient_mode = storage->reflection_probe_get_ambient_mode(base_probe);
+ reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy;
+ reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
+ reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
+ reflection_ubo.ambient_mode = ambient_mode;
+
+ Transform transform = reflection_probe_instance_get_transform(rpi);
+ Transform proj = (p_camera_inverse_transform * transform).inverse();
+ RasterizerStorageRD::store_transform(proj, reflection_ubo.local_matrix);
+
+ cluster.builder.add_reflection_probe(transform, extents);
+
+ reflection_probe_instance_set_render_pass(rpi, RSG::rasterizer->get_frame_number());
+ }
+
+ if (p_reflection_probe_cull_count) {
+ RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, MIN(cluster.max_reflections, (unsigned int)p_reflection_probe_cull_count) * sizeof(ReflectionData), cluster.reflections, true);
+ }
+}
+
+void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {
+ uint32_t light_count = 0;
+ r_directional_light_count = 0;
+ r_positional_light_count = 0;
+ sky_scene_state.ubo.directional_light_count = 0;
+
+ for (int i = 0; i < p_light_cull_count; i++) {
+ RID li = p_light_cull_result[i];
+ RID base = light_instance_get_base_light(li);
+
+ ERR_CONTINUE(base.is_null());
+
+ RS::LightType type = storage->light_get_type(base);
+ switch (type) {
+ case RS::LIGHT_DIRECTIONAL: {
+ if (r_directional_light_count >= cluster.max_directional_lights) {
+ continue;
+ }
+
+ Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count];
+
+ Transform light_transform = light_instance_get_base_transform(li);
+
+ Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float sign = storage->light_is_negative(base) ? -1 : 1;
+
+ light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
+
+ Color linear_col = storage->light_get_color(base).to_linear();
+ light_data.color[0] = linear_col.r;
+ light_data.color[1] = linear_col.g;
+ light_data.color[2] = linear_col.b;
+
+ light_data.specular = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
+ light_data.mask = storage->light_get_cull_mask(base);
+
+ float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
+
+ Color shadow_col = storage->light_get_shadow_color(base).to_linear();
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) {
+ light_data.shadow_color1[0] = 1.0;
+ light_data.shadow_color1[1] = 0.0;
+ light_data.shadow_color1[2] = 0.0;
+ light_data.shadow_color1[3] = 1.0;
+ light_data.shadow_color2[0] = 0.0;
+ light_data.shadow_color2[1] = 1.0;
+ light_data.shadow_color2[2] = 0.0;
+ light_data.shadow_color2[3] = 1.0;
+ light_data.shadow_color3[0] = 0.0;
+ light_data.shadow_color3[1] = 0.0;
+ light_data.shadow_color3[2] = 1.0;
+ light_data.shadow_color3[3] = 1.0;
+ light_data.shadow_color4[0] = 1.0;
+ light_data.shadow_color4[1] = 1.0;
+ light_data.shadow_color4[2] = 0.0;
+ light_data.shadow_color4[3] = 1.0;
+
+ } else {
+ light_data.shadow_color1[0] = shadow_col.r;
+ light_data.shadow_color1[1] = shadow_col.g;
+ light_data.shadow_color1[2] = shadow_col.b;
+ light_data.shadow_color1[3] = 1.0;
+ light_data.shadow_color2[0] = shadow_col.r;
+ light_data.shadow_color2[1] = shadow_col.g;
+ light_data.shadow_color2[2] = shadow_col.b;
+ light_data.shadow_color2[3] = 1.0;
+ light_data.shadow_color3[0] = shadow_col.r;
+ light_data.shadow_color3[1] = shadow_col.g;
+ light_data.shadow_color3[2] = shadow_col.b;
+ light_data.shadow_color3[3] = 1.0;
+ light_data.shadow_color4[0] = shadow_col.r;
+ light_data.shadow_color4[1] = shadow_col.g;
+ light_data.shadow_color4[2] = shadow_col.b;
+ light_data.shadow_color4[3] = 1.0;
+ }
+
+ light_data.shadow_enabled = p_using_shadows && storage->light_has_shadow(base);
+
+ float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (angular_diameter > 0.0) {
+ // I know tan(0) is 0, but let's not risk it with numerical precision.
+ // technically this will keep expanding until reaching the sun, but all we care
+ // is expand until we reach the radius of the near plane (there can't be more occluders than that)
+ angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ } else {
+ angular_diameter = 0.0;
+ }
+
+ if (light_data.shadow_enabled) {
+ RS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base);
+
+ int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
+ light_data.blend_splits = storage->light_directional_get_blend_splits(base);
+ for (int j = 0; j < 4; j++) {
+ Rect2 atlas_rect = light_instance_get_directional_shadow_atlas_rect(li, j);
+ CameraMatrix matrix = light_instance_get_shadow_camera(li, j);
+ float split = light_instance_get_directional_shadow_split(li, MIN(limit, j));
+
+ CameraMatrix bias;
+ bias.set_light_bias();
+ CameraMatrix rectm;
+ rectm.set_light_atlas_rect(atlas_rect);
+
+ Transform modelview = (p_camera_inverse_transform * light_instance_get_shadow_transform(li, j)).inverse();
+
+ CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
+ light_data.shadow_split_offsets[j] = split;
+ float bias_scale = light_instance_get_shadow_bias_scale(li, j);
+ light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale;
+ light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j);
+ light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale;
+ light_data.shadow_z_range[j] = light_instance_get_shadow_range(li, j);
+ light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j);
+ RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrices[j]);
+
+ Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j);
+ uv_scale *= atlas_rect.size; //adapt to atlas size
+ switch (j) {
+ case 0: {
+ light_data.uv_scale1[0] = uv_scale.x;
+ light_data.uv_scale1[1] = uv_scale.y;
+ } break;
+ case 1: {
+ light_data.uv_scale2[0] = uv_scale.x;
+ light_data.uv_scale2[1] = uv_scale.y;
+ } break;
+ case 2: {
+ light_data.uv_scale3[0] = uv_scale.x;
+ light_data.uv_scale3[1] = uv_scale.y;
+ } break;
+ case 3: {
+ light_data.uv_scale4[0] = uv_scale.x;
+ light_data.uv_scale4[1] = uv_scale.y;
+ } break;
+ }
+ }
+
+ float fade_start = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);
+ light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
+ light_data.fade_to = -light_data.shadow_split_offsets[3];
+ light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);
+
+ light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
+ light_data.softshadow_angle = angular_diameter;
+
+ if (angular_diameter <= 0.0) {
+ light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
+ }
+ }
+
+ // Copy to SkyDirectionalLightData
+ if (r_directional_light_count < sky_scene_state.max_directional_lights) {
+ SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count];
+
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = -world_direction.z;
+
+ sky_light_data.energy = light_data.energy / Math_PI;
+
+ sky_light_data.color[0] = light_data.color[0];
+ sky_light_data.color[1] = light_data.color[1];
+ sky_light_data.color[2] = light_data.color[2];
+
+ sky_light_data.enabled = true;
+ sky_light_data.size = angular_diameter;
+ sky_scene_state.ubo.directional_light_count++;
+ }
+
+ r_directional_light_count++;
+ } break;
+ case RS::LIGHT_SPOT:
+ case RS::LIGHT_OMNI: {
+ if (light_count >= cluster.max_lights) {
+ continue;
+ }
+
+ Transform light_transform = light_instance_get_base_transform(li);
+
+ Cluster::LightData &light_data = cluster.lights[light_count];
+ cluster.lights_instances[light_count] = li;
+
+ float sign = storage->light_is_negative(base) ? -1 : 1;
+ Color linear_col = storage->light_get_color(base).to_linear();
+
+ light_data.attenuation_energy[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION));
+ light_data.attenuation_energy[1] = Math::make_half_float(sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI);
+
+ light_data.color_specular[0] = MIN(uint32_t(linear_col.r * 255), 255);
+ light_data.color_specular[1] = MIN(uint32_t(linear_col.g * 255), 255);
+ light_data.color_specular[2] = MIN(uint32_t(linear_col.b * 255), 255);
+ light_data.color_specular[3] = MIN(uint32_t(storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 255), 255);
+
+ float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
+ light_data.inv_radius = 1.0 / radius;
+
+ Vector3 pos = p_camera_inverse_transform.xform(light_transform.origin);
+
+ light_data.position[0] = pos.x;
+ light_data.position[1] = pos.y;
+ light_data.position[2] = pos.z;
+
+ Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = size;
+
+ light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION));
+ float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
+ light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle)));
+
+ light_data.mask = storage->light_get_cull_mask(base);
+
+ light_data.atlas_rect[0] = 0;
+ light_data.atlas_rect[1] = 0;
+ light_data.atlas_rect[2] = 0;
+ light_data.atlas_rect[3] = 0;
+
+ RID projector = storage->light_get_projector(base);
+
+ if (projector.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(projector);
+
+ if (type == RS::LIGHT_SPOT) {
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = -rect.size.height;
+ } else {
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y;
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half
+ }
+ } else {
+ light_data.projector_rect[0] = 0;
+ light_data.projector_rect[1] = 0;
+ light_data.projector_rect[2] = 0;
+ light_data.projector_rect[3] = 0;
+ }
+
+ if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
+ // fill in the shadow information
+
+ Color shadow_color = storage->light_get_shadow_color(base);
+
+ light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255);
+ light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255);
+ light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255);
+ light_data.shadow_color_enabled[3] = 255;
+
+ if (type == RS::LIGHT_SPOT) {
+ light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0);
+ float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0;
+ shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas);
+
+ light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size;
+
+ } else { //omni
+ light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0;
+ float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas);
+ light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space
+ }
+
+ light_data.transmittance_bias = storage->light_get_transmittance_bias(base);
+
+ Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas);
+
+ light_data.atlas_rect[0] = rect.position.x;
+ light_data.atlas_rect[1] = rect.position.y;
+ light_data.atlas_rect[2] = rect.size.width;
+ light_data.atlas_rect[3] = rect.size.height;
+
+ light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
+ light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);
+
+ if (type == RS::LIGHT_OMNI) {
+ light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
+ Transform proj = (p_camera_inverse_transform * light_transform).inverse();
+
+ RasterizerStorageRD::store_transform(proj, light_data.shadow_matrix);
+
+ if (size > 0.0) {
+ light_data.soft_shadow_size = size;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
+ }
+
+ } else if (type == RS::LIGHT_SPOT) {
+ Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
+ CameraMatrix bias;
+ bias.set_light_bias();
+
+ CameraMatrix shadow_mtx = bias * light_instance_get_shadow_camera(li, 0) * modelview;
+ RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrix);
+
+ if (size > 0.0) {
+ CameraMatrix cm = light_instance_get_shadow_camera(li, 0);
+ float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle));
+ light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
+ }
+ }
+ } else {
+ light_data.shadow_color_enabled[3] = 0;
+ }
+
+ light_instance_set_index(li, light_count);
+
+ cluster.builder.add_light(type == RS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
+
+ light_count++;
+ r_positional_light_count++;
+ } break;
+ }
+
+ light_instance_set_render_pass(li, RSG::rasterizer->get_frame_number());
+
+ //update UBO for forward rendering, blit to texture for clustered
+ }
+
+ if (light_count) {
+ RD::get_singleton()->buffer_update(cluster.light_buffer, 0, sizeof(Cluster::LightData) * light_count, cluster.lights, true);
+ }
+
+ if (r_directional_light_count) {
+ RD::get_singleton()->buffer_update(cluster.directional_light_buffer, 0, sizeof(Cluster::DirectionalLightData) * r_directional_light_count, cluster.directional_lights, true);
+ }
+}
+
+void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) {
+ Transform uv_xform;
+ uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
+ uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
+
+ p_decal_count = MIN((uint32_t)p_decal_count, cluster.max_decals);
+ int idx = 0;
+ for (int i = 0; i < p_decal_count; i++) {
+ RID di = p_decal_instances[i];
+ RID decal = decal_instance_get_base(di);
+
+ Transform xform = decal_instance_get_transform(di);
+
+ float fade = 1.0;
+
+ if (storage->decal_is_distance_fade_enabled(decal)) {
+ real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+ float fade_begin = storage->decal_get_distance_fade_begin(decal);
+ float fade_length = storage->decal_get_distance_fade_length(decal);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ continue; // do not use this decal, its invisible
+ }
+
+ fade = 1.0 - (distance - fade_begin) / fade_length;
+ }
+ }
+
+ Cluster::DecalData &dd = cluster.decals[idx];
+
+ Vector3 decal_extents = storage->decal_get_extents(decal);
+
+ Transform scale_xform;
+ scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z));
+ Transform to_decal_xform = (p_camera_inverse_xform * decal_instance_get_transform(di) * scale_xform * uv_xform).affine_inverse();
+ RasterizerStorageRD::store_transform(to_decal_xform, dd.xform);
+
+ Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized();
+ normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
+
+ dd.normal[0] = normal.x;
+ dd.normal[1] = normal.y;
+ dd.normal[2] = normal.z;
+ dd.normal_fade = storage->decal_get_normal_fade(decal);
+
+ RID albedo_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ALBEDO);
+ RID emission_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_EMISSION);
+ if (albedo_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(albedo_tex);
+ dd.albedo_rect[0] = rect.position.x;
+ dd.albedo_rect[1] = rect.position.y;
+ dd.albedo_rect[2] = rect.size.x;
+ dd.albedo_rect[3] = rect.size.y;
+ } else {
+ if (!emission_tex.is_valid()) {
+ continue; //no albedo, no emission, no decal.
+ }
+ dd.albedo_rect[0] = 0;
+ dd.albedo_rect[1] = 0;
+ dd.albedo_rect[2] = 0;
+ dd.albedo_rect[3] = 0;
+ }
+
+ RID normal_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_NORMAL);
+
+ if (normal_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(normal_tex);
+ dd.normal_rect[0] = rect.position.x;
+ dd.normal_rect[1] = rect.position.y;
+ dd.normal_rect[2] = rect.size.x;
+ dd.normal_rect[3] = rect.size.y;
+
+ Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
+ RasterizerStorageRD::store_basis_3x4(normal_xform, dd.normal_xform);
+ } else {
+ dd.normal_rect[0] = 0;
+ dd.normal_rect[1] = 0;
+ dd.normal_rect[2] = 0;
+ dd.normal_rect[3] = 0;
+ }
+
+ RID orm_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ORM);
+ if (orm_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(orm_tex);
+ dd.orm_rect[0] = rect.position.x;
+ dd.orm_rect[1] = rect.position.y;
+ dd.orm_rect[2] = rect.size.x;
+ dd.orm_rect[3] = rect.size.y;
+ } else {
+ dd.orm_rect[0] = 0;
+ dd.orm_rect[1] = 0;
+ dd.orm_rect[2] = 0;
+ dd.orm_rect[3] = 0;
+ }
+
+ if (emission_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(emission_tex);
+ dd.emission_rect[0] = rect.position.x;
+ dd.emission_rect[1] = rect.position.y;
+ dd.emission_rect[2] = rect.size.x;
+ dd.emission_rect[3] = rect.size.y;
+ } else {
+ dd.emission_rect[0] = 0;
+ dd.emission_rect[1] = 0;
+ dd.emission_rect[2] = 0;
+ dd.emission_rect[3] = 0;
+ }
+
+ Color modulate = storage->decal_get_modulate(decal);
+ dd.modulate[0] = modulate.r;
+ dd.modulate[1] = modulate.g;
+ dd.modulate[2] = modulate.b;
+ dd.modulate[3] = modulate.a * fade;
+ dd.emission_energy = storage->decal_get_emission_energy(decal) * fade;
+ dd.albedo_mix = storage->decal_get_albedo_mix(decal);
+ dd.mask = storage->decal_get_cull_mask(decal);
+ dd.upper_fade = storage->decal_get_upper_fade(decal);
+ dd.lower_fade = storage->decal_get_lower_fade(decal);
+
+ cluster.builder.add_decal(xform, decal_extents);
+
+ idx++;
+ }
+
+ if (idx > 0) {
+ RD::get_singleton()->buffer_update(cluster.decal_buffer, 0, sizeof(Cluster::DecalData) * idx, cluster.decals, true);
+ }
+}
+
+void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) {
+ ERR_FAIL_COND(!rb->volumetric_fog);
+
+ RD::get_singleton()->free(rb->volumetric_fog->light_density_map);
+ RD::get_singleton()->free(rb->volumetric_fog->fog_map);
+
+ if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+ }
+ if (rb->volumetric_fog->uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set2)) {
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+ }
+ if (rb->volumetric_fog->sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->sdfgi_uniform_set);
+ }
+ if (rb->volumetric_fog->sky_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sky_uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->sky_uniform_set);
+ }
+
+ memdelete(rb->volumetric_fog);
+
+ rb->volumetric_fog = nullptr;
+}
+
+void RasterizerSceneRD::_allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size) {
+ //create fog mipmaps
+ uint32_t fog_texture_size = p_target_size;
+ uint32_t base_texture_size = p_base_size;
+
+ ShadowShrinkStage first;
+ first.size = base_texture_size;
+ first.texture = p_base;
+ shrink_stages.push_back(first); //put depth first in case we dont find smaller ones
+
+ while (fog_texture_size < base_texture_size) {
+ base_texture_size = MAX(base_texture_size / 8, fog_texture_size);
+
+ ShadowShrinkStage s;
+ s.size = base_texture_size;
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ tf.width = base_texture_size;
+ tf.height = base_texture_size;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ if (base_texture_size == fog_texture_size) {
+ s.filter_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
+ }
+
+ s.texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ shrink_stages.push_back(s);
+ }
+}
+
+void RasterizerSceneRD::_clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages) {
+ for (int i = 1; i < shrink_stages.size(); i++) {
+ RD::get_singleton()->free(shrink_stages[i].texture);
+ if (shrink_stages[i].filter_texture.is_valid()) {
+ RD::get_singleton()->free(shrink_stages[i].filter_texture);
+ }
+ }
+ shrink_stages.clear();
+}
+
+void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+ Environment *env = environment_owner.getornull(p_environment);
+
+ float ratio = float(rb->width) / float((rb->width + rb->height) / 2);
+ uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio);
+ uint32_t target_height = uint32_t(float(volumetric_fog_size) / ratio);
+
+ if (rb->volumetric_fog) {
+ //validate
+ if (!env || !env->volumetric_fog_enabled || rb->volumetric_fog->width != target_width || rb->volumetric_fog->height != target_height || rb->volumetric_fog->depth != volumetric_fog_depth) {
+ _volumetric_fog_erase(rb);
+ _render_buffers_uniform_set_changed(p_render_buffers);
+ }
+ }
+
+ if (!env || !env->volumetric_fog_enabled) {
+ //no reason to enable or update, bye
+ return;
+ }
+
+ if (env && env->volumetric_fog_enabled && !rb->volumetric_fog) {
+ //required volumetric fog but not existing, create
+ rb->volumetric_fog = memnew(VolumetricFog);
+ rb->volumetric_fog->width = target_width;
+ rb->volumetric_fog->height = target_height;
+ rb->volumetric_fog->depth = volumetric_fog_depth;
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = target_width;
+ tf.height = target_height;
+ tf.depth = volumetric_fog_depth;
+ tf.type = RD::TEXTURE_TYPE_3D;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ _render_buffers_uniform_set_changed(p_render_buffers);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(rb->volumetric_fog->fog_map);
+ uniforms.push_back(u);
+ }
+
+ rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+ }
+
+ //update directional shadow
+
+ if (p_use_directional_shadows) {
+ if (directional_shadow.shrink_stages.empty()) {
+ if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+ //invalidate uniform set, we will need a new one
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+ rb->volumetric_fog->uniform_set = RID();
+ }
+ _allocate_shadow_shrink_stages(directional_shadow.depth, directional_shadow.size, directional_shadow.shrink_stages, volumetric_fog_directional_shadow_shrink);
+ }
+
+ if (directional_shadow.shrink_stages.size() > 1) {
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ for (int i = 1; i < directional_shadow.shrink_stages.size(); i++) {
+ int32_t src_size = directional_shadow.shrink_stages[i - 1].size;
+ int32_t dst_size = directional_shadow.shrink_stages[i].size;
+ Rect2i r(0, 0, src_size, src_size);
+ int32_t shrink_limit = 8 / (src_size / dst_size);
+
+ storage->get_effects()->reduce_shadow(directional_shadow.shrink_stages[i - 1].texture, directional_shadow.shrink_stages[i].texture, Size2i(src_size, src_size), r, shrink_limit, compute_list);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && directional_shadow.shrink_stages[i].filter_texture.is_valid()) {
+ Rect2i rf(0, 0, dst_size, dst_size);
+ storage->get_effects()->filter_shadow(directional_shadow.shrink_stages[i].texture, directional_shadow.shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), rf, env->volumetric_fog_shadow_filter, compute_list);
+ }
+ }
+ RD::get_singleton()->compute_list_end();
+ }
+ }
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+
+ if (shadow_atlas) {
+ //shrink shadows that need to be shrunk
+
+ bool force_shrink_shadows = false;
+
+ if (shadow_atlas->shrink_stages.empty()) {
+ if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+ //invalidate uniform set, we will need a new one
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+ rb->volumetric_fog->uniform_set = RID();
+ }
+ _allocate_shadow_shrink_stages(shadow_atlas->depth, shadow_atlas->size, shadow_atlas->shrink_stages, volumetric_fog_positional_shadow_shrink);
+ force_shrink_shadows = true;
+ }
+
+ if (rb->volumetric_fog->last_shadow_filter != env->volumetric_fog_shadow_filter) {
+ //if shadow filter changed, invalidate caches
+ rb->volumetric_fog->last_shadow_filter = env->volumetric_fog_shadow_filter;
+ force_shrink_shadows = true;
+ }
+
+ cluster.lights_shadow_rect_cache_count = 0;
+
+ for (int i = 0; i < p_positional_light_count; i++) {
+ if (cluster.lights[i].shadow_color_enabled[3] > 127) {
+ RID li = cluster.lights_instances[i];
+
+ ERR_CONTINUE(!shadow_atlas->shadow_owners.has(li));
+
+ uint32_t key = shadow_atlas->shadow_owners[li];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_CONTINUE((int)shadow >= shadow_atlas->quadrants[quadrant].shadows.size());
+
+ ShadowAtlas::Quadrant::Shadow &s = shadow_atlas->quadrants[quadrant].shadows.write[shadow];
+
+ if (!force_shrink_shadows && s.fog_version == s.version) {
+ continue; //do not update, no need
+ }
+
+ s.fog_version = s.version;
+
+ uint32_t quadrant_size = shadow_atlas->size >> 1;
+
+ Rect2i atlas_rect;
+
+ atlas_rect.position.x = (quadrant & 1) * quadrant_size;
+ atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ atlas_rect.size.x = shadow_size;
+ atlas_rect.size.y = shadow_size;
+
+ cluster.lights_shadow_rect_cache[cluster.lights_shadow_rect_cache_count] = atlas_rect;
+
+ cluster.lights_shadow_rect_cache_count++;
+
+ if (cluster.lights_shadow_rect_cache_count == cluster.max_lights) {
+ break; //light limit reached
+ }
+ }
+ }
+
+ if (cluster.lights_shadow_rect_cache_count > 0) {
+ //there are shadows to be shrunk, try to do them in parallel
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ for (int i = 1; i < shadow_atlas->shrink_stages.size(); i++) {
+ int32_t base_size = shadow_atlas->shrink_stages[0].size;
+ int32_t src_size = shadow_atlas->shrink_stages[i - 1].size;
+ int32_t dst_size = shadow_atlas->shrink_stages[i].size;
+
+ uint32_t rect_divisor = base_size / src_size;
+
+ int32_t shrink_limit = 8 / (src_size / dst_size);
+
+ //shrink in parallel for more performance
+ for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) {
+ Rect2i src_rect = cluster.lights_shadow_rect_cache[j];
+
+ src_rect.position /= rect_divisor;
+ src_rect.size /= rect_divisor;
+
+ storage->get_effects()->reduce_shadow(shadow_atlas->shrink_stages[i - 1].texture, shadow_atlas->shrink_stages[i].texture, Size2i(src_size, src_size), src_rect, shrink_limit, compute_list);
+ }
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && shadow_atlas->shrink_stages[i].filter_texture.is_valid()) {
+ uint32_t filter_divisor = base_size / dst_size;
+
+ //filter in parallel for more performance
+ for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) {
+ Rect2i dst_rect = cluster.lights_shadow_rect_cache[j];
+
+ dst_rect.position /= filter_divisor;
+ dst_rect.size /= filter_divisor;
+
+ storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, true, false);
+ }
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) {
+ Rect2i dst_rect = cluster.lights_shadow_rect_cache[j];
+
+ dst_rect.position /= filter_divisor;
+ dst_rect.size /= filter_divisor;
+
+ storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, false, true);
+ }
+ }
+ }
+
+ RD::get_singleton()->compute_list_end();
+ }
+ }
+
+ //update volumetric fog
+
+ if (rb->volumetric_fog->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+ //re create uniform set if needed
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ if (shadow_atlas == nullptr || shadow_atlas->shrink_stages.size() == 0) {
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+ } else {
+ u.ids.push_back(shadow_atlas->shrink_stages[shadow_atlas->shrink_stages.size() - 1].texture);
+ }
+
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ if (directional_shadow.shrink_stages.size() == 0) {
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+ } else {
+ u.ids.push_back(directional_shadow.shrink_stages[directional_shadow.shrink_stages.size() - 1].texture);
+ }
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(get_positional_light_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 4;
+ u.ids.push_back(get_directional_light_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ u.ids.push_back(get_cluster_builder_texture());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 6;
+ u.ids.push_back(get_cluster_builder_indices_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 7;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(rb->volumetric_fog->light_density_map);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 9;
+ u.ids.push_back(rb->volumetric_fog->fog_map);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 11;
+ u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 12;
+ for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
+ u.ids.push_back(rb->giprobe_textures[i]);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 13;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
+
+ SWAP(uniforms.write[7].ids.write[0], uniforms.write[8].ids.write[0]);
+
+ rb->volumetric_fog->uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
+ }
+
+ bool using_sdfgi = env->volumetric_fog_gi_inject > 0.0001 && env->sdfgi_enabled && (rb->sdfgi != nullptr);
+
+ if (using_sdfgi) {
+ if (rb->volumetric_fog->sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(gi.sdfgi_ubo);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ u.ids.push_back(rb->sdfgi->ambient_texture);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(rb->sdfgi->occlusion_texture);
+ uniforms.push_back(u);
+ }
+
+ rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI), 1);
+ }
+ }
+
+ rb->volumetric_fog->length = env->volumetric_fog_length;
+ rb->volumetric_fog->spread = env->volumetric_fog_detail_spread;
+
+ VolumetricFogShader::PushConstant push_constant;
+
+ Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents();
+ Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents();
+ float z_near = p_cam_projection.get_z_near();
+ float z_far = p_cam_projection.get_z_far();
+ float fog_end = env->volumetric_fog_length;
+
+ Vector2 fog_far_size = frustum_near_size.lerp(frustum_far_size, (fog_end - z_near) / (z_far - z_near));
+ Vector2 fog_near_size;
+ if (p_cam_projection.is_orthogonal()) {
+ fog_near_size = fog_far_size;
+ } else {
+ fog_near_size = Vector2();
+ }
+
+ push_constant.fog_frustum_size_begin[0] = fog_near_size.x;
+ push_constant.fog_frustum_size_begin[1] = fog_near_size.y;
+
+ push_constant.fog_frustum_size_end[0] = fog_far_size.x;
+ push_constant.fog_frustum_size_end[1] = fog_far_size.y;
+
+ push_constant.z_near = z_near;
+ push_constant.z_far = z_far;
+
+ push_constant.fog_frustum_end = fog_end;
+
+ push_constant.fog_volume_size[0] = rb->volumetric_fog->width;
+ push_constant.fog_volume_size[1] = rb->volumetric_fog->height;
+ push_constant.fog_volume_size[2] = rb->volumetric_fog->depth;
+
+ push_constant.directional_light_count = p_directional_light_count;
+
+ Color light = env->volumetric_fog_light.to_linear();
+ push_constant.light_energy[0] = light.r * env->volumetric_fog_light_energy;
+ push_constant.light_energy[1] = light.g * env->volumetric_fog_light_energy;
+ push_constant.light_energy[2] = light.b * env->volumetric_fog_light_energy;
+ push_constant.base_density = env->volumetric_fog_density;
+
+ push_constant.detail_spread = env->volumetric_fog_detail_spread;
+ push_constant.gi_inject = env->volumetric_fog_gi_inject;
+
+ push_constant.cam_rotation[0] = p_cam_transform.basis[0][0];
+ push_constant.cam_rotation[1] = p_cam_transform.basis[1][0];
+ push_constant.cam_rotation[2] = p_cam_transform.basis[2][0];
+ push_constant.cam_rotation[3] = 0;
+ push_constant.cam_rotation[4] = p_cam_transform.basis[0][1];
+ push_constant.cam_rotation[5] = p_cam_transform.basis[1][1];
+ push_constant.cam_rotation[6] = p_cam_transform.basis[2][1];
+ push_constant.cam_rotation[7] = 0;
+ push_constant.cam_rotation[8] = p_cam_transform.basis[0][2];
+ push_constant.cam_rotation[9] = p_cam_transform.basis[1][2];
+ push_constant.cam_rotation[10] = p_cam_transform.basis[2][2];
+ push_constant.cam_rotation[11] = 0;
+ push_constant.filter_axis = 0;
+ push_constant.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0;
+
+ /* Vector2 dssize = directional_shadow_get_size();
+ push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x;
+ push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y;
+*/
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ bool use_filter = volumetric_fog_filter_active;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
+ if (using_sdfgi) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1);
+ }
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 4, 4, 4);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (use_filter) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ push_constant.filter_axis = 1;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1, 8, 8, 1);
+
+ RD::get_singleton()->compute_list_end();
+}
+
void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
Color clear_color;
if (p_render_buffers.is_valid()) {
@@ -5637,7 +6940,46 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca
}
}
- _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_decal_cull_result, p_decal_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ p_light_cull_count = 0;
+ p_reflection_probe_cull_count = 0;
+ p_gi_probe_cull_count = 0;
+ }
+
+ cluster.builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster
+
+ bool using_shadows = true;
+
+ if (p_reflection_probe.is_valid()) {
+ if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_reflection_probe))) {
+ using_shadows = false;
+ }
+ } else {
+ //do not render reflections when rendering a reflection probe
+ _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
+ }
+
+ uint32_t directional_light_count = 0;
+ uint32_t positional_light_count = 0;
+ _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count, positional_light_count);
+ _setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse());
+ cluster.builder.bake_cluster(); //bake to cluster
+
+ uint32_t gi_probe_count = 0;
+ _setup_giprobes(p_render_buffers, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count, gi_probe_count);
+
+ if (p_render_buffers.is_valid()) {
+ bool directional_shadows = false;
+ for (uint32_t i = 0; i < directional_light_count; i++) {
+ if (cluster.directional_lights[i].shadow_enabled) {
+ directional_shadows = true;
+ break;
+ }
+ }
+ _update_volumetric_fog(p_render_buffers, p_environment, p_cam_projection, p_cam_transform, p_shadow_atlas, directional_light_count, directional_shadows, positional_light_count, gi_probe_count);
+ }
+
+ _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
if (p_render_buffers.is_valid()) {
RENDER_TIMESTAMP("Tonemap");
@@ -5924,6 +7266,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc
ipush_constant.sky_color[1] = 0;
ipush_constant.sky_color[2] = 0;
ipush_constant.y_mult = rb->sdfgi->y_mult;
+ ipush_constant.store_ambient_texture = false;
ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count;
@@ -5962,7 +7305,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc
uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 };
RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data, true);
- bool half_size = true; //much faster, very little differnce
+ bool half_size = true; //much faster, very little difference
static const int optimized_jf_group_size = 8;
if (half_size) {
@@ -6112,7 +7455,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc
push_constant.occlusion_index = i;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offseted, its one less probe per axis to compute
+ Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offset, it's one less probe per axis to compute
RD::get_singleton()->compute_list_dispatch(compute_list, groups.x, groups.y, groups.z);
}
RD::get_singleton()->compute_list_add_barrier(compute_list);
@@ -6279,6 +7622,9 @@ bool RasterizerSceneRD::free(RID p_rid) {
if (rb->sdfgi) {
_sdfgi_erase(rb);
}
+ if (rb->volumetric_fog) {
+ _volumetric_fog_erase(rb);
+ }
render_buffers_owner.free(p_rid);
} else if (environment_owner.owns(p_rid)) {
//not much to delete, just free it
@@ -6496,6 +7842,30 @@ void RasterizerSceneRD::sdfgi_set_debug_probe_select(const Vector3 &p_position,
RasterizerSceneRD *RasterizerSceneRD::singleton = nullptr;
+RID RasterizerSceneRD::get_cluster_builder_texture() {
+ return cluster.builder.get_cluster_texture();
+}
+
+RID RasterizerSceneRD::get_cluster_builder_indices_buffer() {
+ return cluster.builder.get_cluster_indices_buffer();
+}
+
+RID RasterizerSceneRD::get_reflection_probe_buffer() {
+ return cluster.reflection_buffer;
+}
+RID RasterizerSceneRD::get_positional_light_buffer() {
+ return cluster.light_buffer;
+}
+RID RasterizerSceneRD::get_directional_light_buffer() {
+ return cluster.directional_light_buffer;
+}
+RID RasterizerSceneRD::get_decal_buffer() {
+ return cluster.decal_buffer;
+}
+int RasterizerSceneRD::get_max_directional_lights() const {
+ return cluster.max_directional_lights;
+}
+
RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
storage = p_storage;
singleton = this;
@@ -6627,6 +7997,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
+ actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
@@ -6651,6 +8022,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);
sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
+ sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
+
Vector<RD::Uniform> uniforms;
{
@@ -6682,7 +8055,70 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
uniforms.push_back(u);
}
- sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS);
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ u.ids.push_back(vfog);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+ }
+
+ {
+ // Need defaults for using fog with clear color
+ sky_scene_state.fog_shader = storage->shader_create();
+ storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n");
+ sky_scene_state.fog_material = storage->material_create();
+ storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
}
{
@@ -6802,8 +8238,71 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
}
}
+ //cluster setup
+ uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
+
+ { //reflections
+ uint32_t reflection_buffer_size;
+ if (uniform_max_size < 65536) {
+ //Yes, you guessed right, ARM again
+ reflection_buffer_size = uniform_max_size;
+ } else {
+ reflection_buffer_size = 65536;
+ }
+
+ cluster.max_reflections = reflection_buffer_size / sizeof(Cluster::ReflectionData);
+ cluster.reflections = memnew_arr(Cluster::ReflectionData, cluster.max_reflections);
+ cluster.reflection_buffer = RD::get_singleton()->storage_buffer_create(reflection_buffer_size);
+ }
+
+ { //lights
+ cluster.max_lights = MIN(1024 * 1024, uniform_max_size) / sizeof(Cluster::LightData); //1mb of lights
+ uint32_t light_buffer_size = cluster.max_lights * sizeof(Cluster::LightData);
+ cluster.lights = memnew_arr(Cluster::LightData, cluster.max_lights);
+ cluster.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
+ //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(cluster.max_lights) + "\n";
+ cluster.lights_instances = memnew_arr(RID, cluster.max_lights);
+ cluster.lights_shadow_rect_cache = memnew_arr(Rect2i, cluster.max_lights);
+
+ cluster.max_directional_lights = 8;
+ uint32_t directional_light_buffer_size = cluster.max_directional_lights * sizeof(Cluster::DirectionalLightData);
+ cluster.directional_lights = memnew_arr(Cluster::DirectionalLightData, cluster.max_directional_lights);
+ cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
+ }
+
+ { //decals
+ cluster.max_decals = MIN(1024 * 1024, uniform_max_size) / sizeof(Cluster::DecalData); //1mb of decals
+ uint32_t decal_buffer_size = cluster.max_decals * sizeof(Cluster::DecalData);
+ cluster.decals = memnew_arr(Cluster::DecalData, cluster.max_decals);
+ cluster.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
+ }
+
+ cluster.builder.setup(16, 8, 24);
+
+ {
+ String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
+ Vector<String> volumetric_fog_modes;
+ volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
+ volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n");
+ volumetric_fog_modes.push_back("\n#define MODE_FILTER\n");
+ volumetric_fog_modes.push_back("\n#define MODE_FOG\n");
+ volumetric_fog.shader.initialize(volumetric_fog_modes, defines);
+ volumetric_fog.shader_version = volumetric_fog.shader.version_create();
+ for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) {
+ volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i));
+ }
+ }
default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES);
+ {
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.enable_compare = true;
+ sampler.compare_op = RD::COMPARE_OP_LESS;
+ shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ }
+
camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape"))));
camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter"));
environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"));
@@ -6821,6 +8320,11 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
soft_shadow_kernel = memnew_arr(float, 128);
shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality"))));
directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality"))));
+
+ environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/volumetric_fog/volume_size"), GLOBAL_GET("rendering/volumetric_fog/volume_depth"));
+ environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/volumetric_fog/use_filter"));
+ environment_set_volumetric_fog_directional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/directional_shadow_shrink"));
+ environment_set_volumetric_fog_positional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/positional_shadow_shrink"));
}
RasterizerSceneRD::~RasterizerSceneRD() {
@@ -6831,11 +8335,8 @@ RasterizerSceneRD::~RasterizerSceneRD() {
RD::get_singleton()->free(E->get().cubemap);
}
- if (sky_scene_state.sampler_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.sampler_uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.sampler_uniform_set);
- }
- if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+ if (sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.uniform_set);
}
RD::get_singleton()->free(default_giprobe_buffer);
@@ -6851,16 +8352,38 @@ RasterizerSceneRD::~RasterizerSceneRD() {
sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
+ volumetric_fog.shader.version_free(volumetric_fog.shader_version);
+
memdelete_arr(gi_probe_lights);
SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);
sky_shader.shader.version_free(md->shader_data->version);
RD::get_singleton()->free(sky_scene_state.directional_light_buffer);
+ RD::get_singleton()->free(sky_scene_state.uniform_buffer);
memdelete_arr(sky_scene_state.directional_lights);
memdelete_arr(sky_scene_state.last_frame_directional_lights);
storage->free(sky_shader.default_shader);
storage->free(sky_shader.default_material);
+ storage->free(sky_scene_state.fog_shader);
+ storage->free(sky_scene_state.fog_material);
memdelete_arr(directional_penumbra_shadow_kernel);
memdelete_arr(directional_soft_shadow_kernel);
memdelete_arr(penumbra_shadow_kernel);
memdelete_arr(soft_shadow_kernel);
+
+ {
+ RD::get_singleton()->free(cluster.directional_light_buffer);
+ RD::get_singleton()->free(cluster.light_buffer);
+ RD::get_singleton()->free(cluster.reflection_buffer);
+ RD::get_singleton()->free(cluster.decal_buffer);
+ memdelete_arr(cluster.directional_lights);
+ memdelete_arr(cluster.lights);
+ memdelete_arr(cluster.lights_shadow_rect_cache);
+ memdelete_arr(cluster.lights_instances);
+ memdelete_arr(cluster.reflections);
+ memdelete_arr(cluster.decals);
+ }
+
+ RD::get_singleton()->free(shadow_sampler);
+
+ directional_shadow_atlas_set_size(0);
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index f09f9dde65..f504240f50 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -34,6 +34,7 @@
#include "core/local_vector.h"
#include "core/rid_owner.h"
#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/rasterizer_rd/light_cluster_builder.h"
#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h"
#include "servers/rendering/rasterizer_rd/shaders/gi.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/giprobe.glsl.gen.h"
@@ -44,6 +45,7 @@
#include "servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/sky.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl.gen.h"
#include "servers/rendering/rendering_device.h"
class RasterizerSceneRD : public RasterizerScene {
@@ -61,14 +63,37 @@ protected:
};
struct SkySceneState {
+ struct UBO {
+ uint32_t volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+ uint32_t volumetric_fog_pad;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ uint32_t fog_enabled;
+ float fog_density;
+
+ float z_far;
+ uint32_t directional_light_count;
+ };
+
+ UBO ubo;
+
SkyDirectionalLightData *directional_lights;
SkyDirectionalLightData *last_frame_directional_lights;
uint32_t max_directional_lights;
- uint32_t directional_light_count;
uint32_t last_frame_directional_light_count;
RID directional_light_buffer;
- RID sampler_uniform_set;
- RID light_uniform_set;
+ RID uniform_set;
+ RID uniform_buffer;
+ RID fog_uniform_set;
+ RID default_fog_uniform_set;
+
+ RID fog_shader;
+ RID fog_material;
+ RID fog_only_texture_uniform_set;
} sky_scene_state;
struct RenderBufferData {
@@ -77,7 +102,12 @@ protected:
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0;
+ void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
+ void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform);
+ void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
+ void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used);
+
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0;
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0;
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
@@ -98,7 +128,7 @@ protected:
void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);
void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera);
- void _setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size);
+ void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size);
void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count);
@@ -237,10 +267,10 @@ private:
};
enum SkySet {
- SKY_SET_SAMPLERS,
+ SKY_SET_UNIFORMS,
SKY_SET_MATERIAL,
SKY_SET_TEXTURES,
- SKY_SET_LIGHTS,
+ SKY_SET_FOG,
SKY_SET_MAX
};
@@ -485,6 +515,12 @@ private:
/* SHADOW ATLAS */
+ struct ShadowShrinkStage {
+ RID texture;
+ RID filter_texture;
+ uint32_t size;
+ };
+
struct ShadowAtlas {
enum {
QUADRANT_SHIFT = 27,
@@ -498,10 +534,12 @@ private:
struct Shadow {
RID owner;
uint64_t version;
+ uint64_t fog_version; // used for fog
uint64_t alloc_tick;
Shadow() {
version = 0;
+ fog_version = 0;
alloc_tick = 0;
}
};
@@ -523,6 +561,8 @@ private:
RID fb; //for copying
Map<RID, uint32_t> shadow_owners;
+
+ Vector<ShadowShrinkStage> shrink_stages;
};
RID_Owner<ShadowAtlas> shadow_atlas_owner;
@@ -551,8 +591,14 @@ private:
int light_count = 0;
int size = 0;
int current_light = 0;
+
+ Vector<ShadowShrinkStage> shrink_stages;
+
} directional_shadow;
+ void _allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size);
+ void _clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages);
+
/* SHADOW CUBEMAPS */
struct ShadowCubemap {
@@ -623,7 +669,7 @@ private:
/* ENVIRONMENT */
- struct Environent {
+ struct Environment {
// BG
RS::EnvironmentBG background = RS::ENV_BG_CLEAR_COLOR;
RID sky;
@@ -651,6 +697,26 @@ private:
float auto_exp_scale = 0.5;
uint64_t auto_exposure_version = 0;
+ // Fog
+ bool fog_enabled = false;
+ Color fog_light_color = Color(0.5, 0.6, 0.7);
+ float fog_light_energy = 1.0;
+ float fog_sun_scatter = 0.0;
+ float fog_density = 0.001;
+ float fog_height = 0.0;
+ float fog_height_density = 0.0; //can be negative to invert effect
+
+ /// Volumetric Fog
+ ///
+ bool volumetric_fog_enabled = false;
+ float volumetric_fog_density = 0.01;
+ Color volumetric_fog_light = Color(0, 0, 0);
+ float volumetric_fog_light_energy = 0.0;
+ float volumetric_fog_length = 64.0;
+ float volumetric_fog_detail_spread = 2.0;
+ RS::EnvVolumetricFogShadowFilter volumetric_fog_shadow_filter = RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW;
+ float volumetric_fog_gi_inject = 0.0;
+
/// Glow
bool glow_enabled = false;
@@ -703,7 +769,7 @@ private:
static uint64_t auto_exposure_counter;
- mutable RID_Owner<Environent> environment_owner;
+ mutable RID_Owner<Environment> environment_owner;
/* CAMERA EFFECTS */
@@ -734,6 +800,7 @@ private:
/* RENDER BUFFERS */
struct SDFGI;
+ struct VolumetricFog;
struct RenderBuffers {
enum {
@@ -754,6 +821,7 @@ private:
RID gi_uniform_set;
SDFGI *sdfgi = nullptr;
+ VolumetricFog *volumetric_fog = nullptr;
//built-in textures used for ping pong image processing and blurring
struct Blur {
@@ -880,6 +948,7 @@ private:
RID lightprobe_data;
RID occlusion_texture;
RID occlusion_data;
+ RID ambient_texture; //integrates with volumetric fog
RID lightprobe_history_scroll; //used for scrolling lightprobes
RID lightprobe_average_scroll; //used for scrolling lightprobes
@@ -1072,6 +1141,9 @@ private:
float sky_color[3];
float y_mult;
+
+ uint32_t store_ambient_texture;
+ uint32_t pad[3];
};
SdfgiIntegrateShaderRD integrate;
@@ -1136,7 +1208,7 @@ private:
float anisotropy_strength;
float ao;
float ao_size;
- uint32_t pad[1];
+ uint32_t mipmaps;
};
struct PushConstant {
@@ -1181,6 +1253,186 @@ private:
void _render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection);
void _sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform);
+ /* Cluster */
+
+ struct Cluster {
+ /* Scene State UBO */
+
+ struct ReflectionData { //should always be 128 bytes
+ float box_extents[3];
+ float index;
+ float box_offset[3];
+ uint32_t mask;
+ float params[4]; // intensity, 0, interior , boxproject
+ float ambient[3]; // ambient color,
+ uint32_t ambient_mode;
+ float local_matrix[16]; // up to here for spot and omni, rest is for directional
+ };
+
+ struct LightData {
+ float position[3];
+ float inv_radius;
+ float direction[3];
+ float size;
+ uint16_t attenuation_energy[2]; //16 bits attenuation, then energy
+ uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm)
+ uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float)
+ uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm)
+ float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
+ float shadow_matrix[16];
+ float shadow_bias;
+ float shadow_normal_bias;
+ float transmittance_bias;
+ float soft_shadow_size;
+ float soft_shadow_scale;
+ uint32_t mask;
+ float shadow_volumetric_fog_fade;
+ uint32_t pad;
+ float projector_rect[4];
+ };
+
+ struct DirectionalLightData {
+ float direction[3];
+ float energy;
+ float color[3];
+ float size;
+ float specular;
+ uint32_t mask;
+ float softshadow_angle;
+ float soft_shadow_scale;
+ uint32_t blend_splits;
+ uint32_t shadow_enabled;
+ float fade_from;
+ float fade_to;
+ uint32_t pad[3];
+ float shadow_volumetric_fog_fade;
+ float shadow_bias[4];
+ float shadow_normal_bias[4];
+ float shadow_transmittance_bias[4];
+ float shadow_z_range[4];
+ float shadow_range_begin[4];
+ float shadow_split_offsets[4];
+ float shadow_matrices[4][16];
+ float shadow_color1[4];
+ float shadow_color2[4];
+ float shadow_color3[4];
+ float shadow_color4[4];
+ float uv_scale1[2];
+ float uv_scale2[2];
+ float uv_scale3[2];
+ float uv_scale4[2];
+ };
+
+ struct DecalData {
+ float xform[16];
+ float inv_extents[3];
+ float albedo_mix;
+ float albedo_rect[4];
+ float normal_rect[4];
+ float orm_rect[4];
+ float emission_rect[4];
+ float modulate[4];
+ float emission_energy;
+ uint32_t mask;
+ float upper_fade;
+ float lower_fade;
+ float normal_xform[12];
+ float normal[3];
+ float normal_fade;
+ };
+
+ ReflectionData *reflections;
+ uint32_t max_reflections;
+ RID reflection_buffer;
+ uint32_t max_reflection_probes_per_instance;
+
+ DecalData *decals;
+ uint32_t max_decals;
+ RID decal_buffer;
+
+ LightData *lights;
+ uint32_t max_lights;
+ RID light_buffer;
+ RID *lights_instances;
+ Rect2i *lights_shadow_rect_cache;
+ uint32_t lights_shadow_rect_cache_count = 0;
+
+ DirectionalLightData *directional_lights;
+ uint32_t max_directional_lights;
+ RID directional_light_buffer;
+
+ LightClusterBuilder builder;
+
+ } cluster;
+
+ struct VolumetricFog {
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint32_t depth = 0;
+
+ float length;
+ float spread;
+
+ RID light_density_map;
+ RID fog_map;
+ RID uniform_set;
+ RID uniform_set2;
+ RID sdfgi_uniform_set;
+ RID sky_uniform_set;
+
+ int last_shadow_filter = -1;
+ };
+
+ enum {
+ VOLUMETRIC_FOG_SHADER_DENSITY,
+ VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI,
+ VOLUMETRIC_FOG_SHADER_FILTER,
+ VOLUMETRIC_FOG_SHADER_FOG,
+ VOLUMETRIC_FOG_SHADER_MAX,
+ };
+
+ struct VolumetricFogShader {
+ struct PushConstant {
+ float fog_frustum_size_begin[2];
+ float fog_frustum_size_end[2];
+
+ float fog_frustum_end;
+ float z_near;
+ float z_far;
+ uint32_t filter_axis;
+
+ int32_t fog_volume_size[3];
+ uint32_t directional_light_count;
+
+ float light_energy[3];
+ float base_density;
+
+ float detail_spread;
+ float gi_inject;
+ uint32_t max_gi_probes;
+ uint32_t pad;
+
+ float cam_rotation[12];
+ };
+
+ VolumetricFogShaderRD shader;
+
+ RID shader_version;
+ RID pipelines[VOLUMETRIC_FOG_SHADER_MAX];
+
+ } volumetric_fog;
+
+ uint32_t volumetric_fog_depth = 128;
+ uint32_t volumetric_fog_size = 128;
+ bool volumetric_fog_filter_active = false;
+ uint32_t volumetric_fog_directional_shadow_shrink = 512;
+ uint32_t volumetric_fog_positional_shadow_shrink = 512;
+
+ void _volumetric_fog_erase(RenderBuffers *rb);
+ void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count);
+
+ RID shadow_sampler;
+
uint64_t scene_pass = 0;
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
@@ -1279,7 +1531,21 @@ public:
void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);
void environment_glow_set_use_bicubic_upscale(bool p_enable);
- void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {}
+ void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density);
+ bool environment_is_fog_enabled(RID p_env) const;
+ Color environment_get_fog_light_color(RID p_env) const;
+ float environment_get_fog_light_energy(RID p_env) const;
+ float environment_get_fog_sun_scatter(RID p_env) const;
+ float environment_get_fog_density(RID p_env) const;
+ float environment_get_fog_height(RID p_env) const;
+ float environment_get_fog_height_density(RID p_env) const;
+
+ void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter);
+
+ virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth);
+ virtual void environment_set_volumetric_fog_filter_active(bool p_enable);
+ virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size);
+ virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size);
void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance);
void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
@@ -1300,10 +1566,6 @@ public:
void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {}
- void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {}
- void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {}
- void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {}
-
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size);
virtual RID camera_effects_create();
@@ -1597,6 +1859,12 @@ public:
float render_buffers_get_sdfgi_energy(RID p_render_buffers) const;
RID render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const;
+ bool render_buffers_has_volumetric_fog(RID p_render_buffers) const;
+ RID render_buffers_get_volumetric_fog_texture(RID p_render_buffers);
+ RID render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers);
+ float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
+ float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
+
void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
@@ -1655,6 +1923,14 @@ public:
virtual void set_time(double p_time, double p_step);
+ RID get_cluster_builder_texture();
+ RID get_cluster_builder_indices_buffer();
+ RID get_reflection_probe_buffer();
+ RID get_positional_light_buffer();
+ RID get_directional_light_buffer();
+ RID get_decal_buffer();
+ int get_max_directional_lights() const;
+
void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir);
RasterizerSceneRD(RasterizerStorageRD *p_storage);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index 8f3e2c25f9..f3ba57e733 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -899,10 +899,10 @@ Ref<Image> RasterizerStorageRD::texture_3d_slice_get(RID p_texture, int p_depth,
void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
Texture *tex = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!tex);
- ERR_FAIL_COND(tex->proxy_to.is_valid()); //cant replace proxy
+ ERR_FAIL_COND(tex->proxy_to.is_valid()); //can't replace proxy
Texture *by_tex = texture_owner.getornull(p_by_texture);
ERR_FAIL_COND(!by_tex);
- ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //cant replace proxy
+ ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //can't replace proxy
if (tex == by_tex) {
return;
@@ -3290,6 +3290,7 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0;
light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;
light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
+ light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 1.0;
return light_owner.make_rid(light);
}
@@ -5276,7 +5277,7 @@ void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::Glob
if (p_type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
//is texture
- global_variables.must_update_texture_materials = true; //normally ther are no
+ global_variables.must_update_texture_materials = true; //normally there are none
} else {
gv.buffer_elements = 1;
if (p_type == RS::GLOBAL_VAR_TYPE_COLOR || p_type == RS::GLOBAL_VAR_TYPE_MAT2) {
@@ -5299,7 +5300,7 @@ void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::Glob
_global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value);
_global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
- global_variables.must_update_buffer_materials = true; //normally ther are no
+ global_variables.must_update_buffer_materials = true; //normally there are none
}
global_variables.variables[p_name] = gv;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
index b1146f1386..6e5923953b 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -40,6 +40,69 @@
class RasterizerStorageRD : public RasterizerStorage {
public:
+ static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.basis.elements[0][0];
+ p_array[1] = p_mtx.basis.elements[1][0];
+ p_array[2] = p_mtx.basis.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.basis.elements[0][1];
+ p_array[5] = p_mtx.basis.elements[1][1];
+ p_array[6] = p_mtx.basis.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.basis.elements[0][2];
+ p_array[9] = p_mtx.basis.elements[1][2];
+ p_array[10] = p_mtx.basis.elements[2][2];
+ p_array[11] = 0;
+ p_array[12] = p_mtx.origin.x;
+ p_array[13] = p_mtx.origin.y;
+ p_array[14] = p_mtx.origin.z;
+ p_array[15] = 1;
+ }
+
+ static _FORCE_INLINE_ void store_basis_3x4(const Basis &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.elements[0][0];
+ p_array[1] = p_mtx.elements[1][0];
+ p_array[2] = p_mtx.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.elements[0][1];
+ p_array[5] = p_mtx.elements[1][1];
+ p_array[6] = p_mtx.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.elements[0][2];
+ p_array[9] = p_mtx.elements[1][2];
+ p_array[10] = p_mtx.elements[2][2];
+ p_array[11] = 0;
+ }
+
+ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.elements[0][0];
+ p_array[1] = p_mtx.elements[1][0];
+ p_array[2] = p_mtx.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.elements[0][1];
+ p_array[5] = p_mtx.elements[1][1];
+ p_array[6] = p_mtx.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.elements[0][2];
+ p_array[9] = p_mtx.elements[1][2];
+ p_array[10] = p_mtx.elements[2][2];
+ p_array[11] = 0;
+ }
+
+ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ }
+ }
+ }
+
+ static _FORCE_INLINE_ void store_soft_shadow_kernel(const float *p_kernel, float *p_array) {
+ for (int i = 0; i < 128; i++) {
+ p_array[i] = p_kernel[i];
+ }
+ }
+
enum ShaderType {
SHADER_TYPE_2D,
SHADER_TYPE_3D,
@@ -1121,6 +1184,13 @@ public:
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
}
+ _FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const {
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, 0.0);
+
+ return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE];
+ }
+
RS::LightBakeMode light_get_bake_mode(RID p_light);
uint32_t light_get_max_sdfgi_cascade(RID p_light);
uint64_t light_get_version(RID p_light) const;
diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub
index 67f4edc626..3aa863be98 100644
--- a/servers/rendering/rasterizer_rd/shaders/SCsub
+++ b/servers/rendering/rasterizer_rd/shaders/SCsub
@@ -35,3 +35,5 @@ if "RD_GLSL" in env["BUILDERS"]:
env.RD_GLSL("sdfgi_direct_light.glsl")
env.RD_GLSL("sdfgi_debug.glsl")
env.RD_GLSL("sdfgi_debug_probes.glsl")
+ env.RD_GLSL("volumetric_fog.glsl")
+ env.RD_GLSL("shadow_reduce.glsl")
diff --git a/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl b/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl
new file mode 100644
index 0000000000..e723468dd8
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl
@@ -0,0 +1,95 @@
+
+#define CLUSTER_COUNTER_SHIFT 20
+#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
+#define CLUSTER_COUNTER_MASK 0xfff
+
+struct LightData { //this structure needs to be as packed as possible
+ vec3 position;
+ float inv_radius;
+ vec3 direction;
+ float size;
+ uint attenuation_energy; //attenuation
+ uint color_specular; //rgb color, a specular (8 bit unorm)
+ uint cone_attenuation_angle; // attenuation and angle, (16bit float)
+ uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
+ vec4 atlas_rect; // rect in the shadow atlas
+ mat4 shadow_matrix;
+ float shadow_bias;
+ float shadow_normal_bias;
+ float transmittance_bias;
+ float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
+ float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
+ uint mask;
+ float shadow_volumetric_fog_fade;
+ uint pad;
+ vec4 projector_rect; //projector rect in srgb decal atlas
+};
+
+#define REFLECTION_AMBIENT_DISABLED 0
+#define REFLECTION_AMBIENT_ENVIRONMENT 1
+#define REFLECTION_AMBIENT_COLOR 2
+
+struct ReflectionData {
+ vec3 box_extents;
+ float index;
+ vec3 box_offset;
+ uint mask;
+ vec4 params; // intensity, 0, interior , boxproject
+ vec3 ambient; // ambient color
+ uint ambient_mode;
+ mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ // notes: for ambientblend, use distance to edge to blend between already existing global environment
+};
+
+struct DirectionalLightData {
+ vec3 direction;
+ float energy;
+ vec3 color;
+ float size;
+ float specular;
+ uint mask;
+ float softshadow_angle;
+ float soft_shadow_scale;
+ bool blend_splits;
+ bool shadow_enabled;
+ float fade_from;
+ float fade_to;
+ uvec3 pad;
+ float shadow_volumetric_fog_fade;
+ vec4 shadow_bias;
+ vec4 shadow_normal_bias;
+ vec4 shadow_transmittance_bias;
+ vec4 shadow_z_range;
+ vec4 shadow_range_begin;
+ vec4 shadow_split_offsets;
+ mat4 shadow_matrix1;
+ mat4 shadow_matrix2;
+ mat4 shadow_matrix3;
+ mat4 shadow_matrix4;
+ vec4 shadow_color1;
+ vec4 shadow_color2;
+ vec4 shadow_color3;
+ vec4 shadow_color4;
+ vec2 uv_scale1;
+ vec2 uv_scale2;
+ vec2 uv_scale3;
+ vec2 uv_scale4;
+};
+
+struct DecalData {
+ mat4 xform; //to decal transform
+ vec3 inv_extents;
+ float albedo_mix;
+ vec4 albedo_rect;
+ vec4 normal_rect;
+ vec4 orm_rect;
+ vec4 emission_rect;
+ vec4 modulate;
+ float emission_energy;
+ uint mask;
+ float upper_fade;
+ float lower_fade;
+ mat3x4 normal_xform;
+ vec3 normal;
+ float normal_fade;
+};
diff --git a/servers/rendering/rasterizer_rd/shaders/gi.glsl b/servers/rendering/rasterizer_rd/shaders/gi.glsl
index a1939f75ad..8011dadc72 100644
--- a/servers/rendering/rasterizer_rd/shaders/gi.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/gi.glsl
@@ -80,7 +80,7 @@ struct GIProbeData {
float anisotropy_strength;
float ambient_occlusion;
float ambient_occlusion_size;
- uint pad2;
+ uint mipmaps;
};
layout(set = 0, binding = 16, std140) uniform GIProbes {
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
index d6a56b2543..5993e68317 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -1237,7 +1237,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
//reconstruct depth
- shadow_z / lights.data[idx].inv_radius;
+ shadow_z /= lights.data[idx].inv_radius;
//distance to light plane
float z = dot(spot_dir, -light_rel_vec);
transmittance_z = z - shadow_z;
@@ -1601,6 +1601,51 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#ifndef MODE_RENDER_DEPTH
+
+vec4 volumetric_fog_process(vec2 screen_uv, float z) {
+ vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length);
+ if (fog_pos.z < 0.0) {
+ return vec4(0.0);
+ } else if (fog_pos.z < 1.0) {
+ fog_pos.z = pow(fog_pos.z, scene_data.volumetric_fog_detail_spread);
+ }
+
+ return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
+}
+
+vec4 fog_process(vec3 vertex) {
+ vec3 fog_color = scene_data.fog_light_color;
+
+ if (scene_data.fog_sun_scatter > 0.001) {
+ vec4 sun_scatter = vec4(0.0);
+ float sun_total = 0.0;
+ vec3 view = normalize(vertex);
+
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy;
+ float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0);
+ fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ }
+ }
+
+ float fog_amount = 1.0 - exp(vertex.z * scene_data.fog_density);
+
+ if (abs(scene_data.fog_height_density) > 0.001) {
+ float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;
+
+ float y_dist = scene_data.fog_height - y;
+
+ float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0);
+
+ fog_amount = max(vfog_amount, fog_amount);
+ }
+
+ return vec4(fog_color, fog_amount);
+}
+
+#endif
+
void main() {
#ifdef MODE_DUAL_PARABOLOID
@@ -2187,8 +2232,8 @@ FRAGMENT_SHADER_CODE
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x;
+ shadow_z *= directional_lights.data[i].shadow_z_range.x;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x;
transmittance_z = z - shadow_z;
}
@@ -2219,8 +2264,8 @@ FRAGMENT_SHADER_CODE
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y;
+ shadow_z *= directional_lights.data[i].shadow_z_range.y;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y;
transmittance_z = z - shadow_z;
}
@@ -2251,8 +2296,8 @@ FRAGMENT_SHADER_CODE
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z;
+ shadow_z *= directional_lights.data[i].shadow_z_range.z;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z;
transmittance_z = z - shadow_z;
}
@@ -2285,8 +2330,8 @@ FRAGMENT_SHADER_CODE
trans_coord /= trans_coord.w;
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
- shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w;
- float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w;
+ shadow_z *= directional_lights.data[i].shadow_z_range.w;
+ float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w;
transmittance_z = z - shadow_z;
}
@@ -2662,8 +2707,6 @@ FRAGMENT_SHADER_CODE
diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point
ambient_light *= 1.0 - metallic;
- //fog
-
#ifdef MODE_MULTIPLE_RENDER_TARGETS
#ifdef MODE_UNSHADED
@@ -2679,6 +2722,18 @@ FRAGMENT_SHADER_CODE
specular_buffer = vec4(specular_light, metallic);
#endif
+ if (scene_data.volumetric_fog_enabled) {
+ vec4 fog = volumetric_fog_process(screen_uv, -vertex.z);
+ diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a);
+ specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a);
+ }
+
+ if (scene_data.fog_enabled) {
+ vec4 fog = fog_process(vertex);
+ diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a);
+ specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a);
+ }
+
#else //MODE_MULTIPLE_RENDER_TARGETS
#ifdef MODE_UNSHADED
@@ -2686,9 +2741,18 @@ FRAGMENT_SHADER_CODE
#else
frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
//frag_color = vec4(1.0);
-
#endif //USE_NO_SHADING
+ if (scene_data.volumetric_fog_enabled) {
+ vec4 fog = volumetric_fog_process(screen_uv, -vertex.z);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ }
+
+ if (scene_data.fog_enabled) {
+ vec4 fog = fog_process(vertex);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ }
+
#endif //MODE_MULTIPLE_RENDER_TARGETS
#endif //MODE_RENDER_DEPTH
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
index 1244599097..66bfefbe89 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
@@ -3,6 +3,8 @@
#define MAX_GI_PROBES 8
+#include "cluster_data_inc.glsl"
+
layout(push_constant, binding = 0, std430) uniform DrawCall {
uint instance_index;
uint pad; //16 bits minimum size
@@ -94,40 +96,18 @@ layout(set = 0, binding = 3, std140) uniform SceneData {
ivec3 sdf_size;
bool gi_upscale_for_msaa;
-#if 0
- vec4 ambient_light_color;
- vec4 bg_color;
-
- vec4 fog_color_enabled;
- vec4 fog_sun_color_amount;
-
- float ambient_energy;
- float bg_energy;
-#endif
-
-#if 0
- vec2 shadow_atlas_pixel_size;
- vec2 directional_shadow_pixel_size;
+ bool volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+ uint volumetric_fog_pad;
- float z_far;
-
- float subsurface_scatter_width;
- float ambient_occlusion_affect_light;
- float ambient_occlusion_affect_ao_channel;
- float opaque_prepass_threshold;
-
- bool fog_depth_enabled;
- float fog_depth_begin;
- float fog_depth_end;
+ bool fog_enabled;
float fog_density;
- float fog_depth_curve;
- bool fog_transmit_enabled;
- float fog_transmit_curve;
- bool fog_height_enabled;
- float fog_height_min;
- float fog_height_max;
- float fog_height_curve;
-#endif
+ float fog_height;
+ float fog_height_density;
+
+ vec3 fog_light_color;
+ float fog_sun_scatter;
}
scene_data;
@@ -163,86 +143,16 @@ layout(set = 0, binding = 4, std430) restrict readonly buffer Instances {
}
instances;
-struct LightData { //this structure needs to be as packed as possible
- vec3 position;
- float inv_radius;
- vec3 direction;
- float size;
- uint attenuation_energy; //attenuation
- uint color_specular; //rgb color, a specular (8 bit unorm)
- uint cone_attenuation_angle; // attenuation and angle, (16bit float)
- uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
- vec4 atlas_rect; // rect in the shadow atlas
- mat4 shadow_matrix;
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
- float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
- uint mask;
- uint pad[2];
- vec4 projector_rect; //projector rect in srgb decal atlas
-};
-
layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
LightData data[];
}
lights;
-#define REFLECTION_AMBIENT_DISABLED 0
-#define REFLECTION_AMBIENT_ENVIRONMENT 1
-#define REFLECTION_AMBIENT_COLOR 2
-
-struct ReflectionData {
- vec3 box_extents;
- float index;
- vec3 box_offset;
- uint mask;
- vec4 params; // intensity, 0, interior , boxproject
- vec3 ambient; // ambient color
- uint ambient_mode;
- mat4 local_matrix; // up to here for spot and omni, rest is for directional
- // notes: for ambientblend, use distance to edge to blend between already existing global environment
-};
-
-layout(set = 0, binding = 6, std140) uniform ReflectionProbeData {
- ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
+layout(set = 0, binding = 6) buffer restrict readonly ReflectionProbeData {
+ ReflectionData data[];
}
reflections;
-struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
- float size;
- float specular;
- uint mask;
- float softshadow_angle;
- float soft_shadow_scale;
- bool blend_splits;
- bool shadow_enabled;
- float fade_from;
- float fade_to;
- vec4 shadow_bias;
- vec4 shadow_normal_bias;
- vec4 shadow_transmittance_bias;
- vec4 shadow_transmittance_z_scale;
- vec4 shadow_range_begin;
- vec4 shadow_split_offsets;
- mat4 shadow_matrix1;
- mat4 shadow_matrix2;
- mat4 shadow_matrix3;
- mat4 shadow_matrix4;
- vec4 shadow_color1;
- vec4 shadow_color2;
- vec4 shadow_color3;
- vec4 shadow_color4;
- vec2 uv_scale1;
- vec2 uv_scale2;
- vec2 uv_scale3;
- vec2 uv_scale4;
-};
-
layout(set = 0, binding = 7, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
@@ -271,31 +181,9 @@ layout(set = 0, binding = 12, std140) restrict readonly buffer LightmapCaptures
}
lightmap_captures;
-#define CLUSTER_COUNTER_SHIFT 20
-#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
-#define CLUSTER_COUNTER_MASK 0xfff
-
layout(set = 0, binding = 13) uniform texture2D decal_atlas;
layout(set = 0, binding = 14) uniform texture2D decal_atlas_srgb;
-struct DecalData {
- mat4 xform; //to decal transform
- vec3 inv_extents;
- float albedo_mix;
- vec4 albedo_rect;
- vec4 normal_rect;
- vec4 orm_rect;
- vec4 emission_rect;
- vec4 modulate;
- float emission_energy;
- uint mask;
- float upper_fade;
- float lower_fade;
- mat3x4 normal_xform;
- vec3 normal;
- float normal_fade;
-};
-
layout(set = 0, binding = 15, std430) restrict readonly buffer Decals {
DecalData data[];
}
@@ -394,9 +282,7 @@ layout(set = 3, binding = 2) uniform texture2D normal_roughness_buffer;
layout(set = 3, binding = 4) uniform texture2D ao_buffer;
layout(set = 3, binding = 5) uniform texture2D ambient_buffer;
layout(set = 3, binding = 6) uniform texture2D reflection_buffer;
-
layout(set = 3, binding = 7) uniform texture2DArray sdfgi_lightprobe_texture;
-
layout(set = 3, binding = 8) uniform texture3D sdfgi_occlusion_cascades;
struct GIProbeData {
@@ -412,7 +298,7 @@ struct GIProbeData {
float anisotropy_strength;
float ambient_occlusion;
float ambient_occlusion_size;
- uint pad2;
+ uint mipmaps;
};
layout(set = 3, binding = 9, std140) uniform GIProbes {
@@ -420,6 +306,8 @@ layout(set = 3, binding = 9, std140) uniform GIProbes {
}
gi_probes;
+layout(set = 3, binding = 10) uniform texture3D volumetric_fog_texture;
+
#endif
/* Set 4 Skeleton & Instancing (Multimesh) */
diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl
index e4779aafaf..1ec471d204 100644
--- a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl
@@ -37,6 +37,8 @@ layout(rgba32i, set = 0, binding = 12) uniform restrict iimage2D lightprobe_aver
layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_average_parent_texture;
+layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture;
+
layout(set = 1, binding = 0) uniform textureCube sky_irradiance;
layout(set = 1, binding = 1) uniform sampler linear_sampler_mipmaps;
@@ -68,6 +70,9 @@ layout(push_constant, binding = 0, std430) uniform Params {
vec3 sky_color;
float y_mult;
+
+ bool store_ambient_texture;
+ uint pad[3];
}
params;
@@ -319,6 +324,13 @@ void main() {
imageStore(lightprobe_history_texture, prev_pos, ivalue);
imageStore(lightprobe_average_texture, average_pos, average);
+
+ if (params.store_ambient_texture && i == 0) {
+ ivec3 ambient_pos = ivec3(pos, int(params.cascade));
+ vec4 ambient_light = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS);
+ ambient_light *= 0.88622; // SHL0
+ imageStore(lightprobe_ambient_texture, ambient_pos, ambient_light);
+ }
}
#endif // MODE PROCESS
diff --git a/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl b/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl
new file mode 100644
index 0000000000..29443ae7db
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl
@@ -0,0 +1,105 @@
+#[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;
+
+#ifdef MODE_REDUCE
+
+shared float tmp_data[BLOCK_SIZE * BLOCK_SIZE];
+const uint swizzle_table[BLOCK_SIZE] = uint[](0, 4, 2, 6, 1, 5, 3, 7);
+const uint unswizzle_table[BLOCK_SIZE] = uint[](0, 0, 0, 1, 0, 2, 1, 3);
+
+#endif
+
+layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D source_depth;
+layout(r32f, set = 0, binding = 1) uniform restrict writeonly image2D dst_depth;
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ ivec2 source_size;
+ ivec2 source_offset;
+ uint min_size;
+ uint gaussian_kernel_version;
+ ivec2 filter_dir;
+}
+params;
+
+void main() {
+#ifdef MODE_REDUCE
+
+ uvec2 pos = gl_LocalInvocationID.xy;
+
+ ivec2 image_offset = params.source_offset;
+ ivec2 image_pos = image_offset + ivec2(gl_GlobalInvocationID.xy);
+ uint dst_t = swizzle_table[pos.y] * BLOCK_SIZE + swizzle_table[pos.x];
+ tmp_data[dst_t] = imageLoad(source_depth, min(image_pos, params.source_size - ivec2(1))).r;
+ ivec2 image_size = params.source_size;
+
+ uint t = pos.y * BLOCK_SIZE + pos.x;
+
+ //neighbours
+ uint size = BLOCK_SIZE;
+
+ do {
+ groupMemoryBarrier();
+ barrier();
+
+ size >>= 1;
+ image_size >>= 1;
+ image_offset >>= 1;
+
+ if (all(lessThan(pos, uvec2(size)))) {
+ uint nx = t + size;
+ uint ny = t + (BLOCK_SIZE * size);
+ uint nxy = ny + size;
+
+ tmp_data[t] += tmp_data[nx];
+ tmp_data[t] += tmp_data[ny];
+ tmp_data[t] += tmp_data[nxy];
+ tmp_data[t] /= 4.0;
+ }
+
+ } while (size > params.min_size);
+
+ if (all(lessThan(pos, uvec2(size)))) {
+ image_pos = ivec2(unswizzle_table[size + pos.x], unswizzle_table[size + pos.y]);
+ image_pos += image_offset + ivec2(gl_WorkGroupID.xy) * int(size);
+
+ image_size = max(ivec2(1), image_size); //in case image size became 0
+
+ if (all(lessThan(image_pos, uvec2(image_size)))) {
+ imageStore(dst_depth, image_pos, vec4(tmp_data[t]));
+ }
+ }
+#endif
+
+#ifdef MODE_FILTER
+
+ ivec2 image_pos = params.source_offset + ivec2(gl_GlobalInvocationID.xy);
+ if (any(greaterThanEqual(image_pos, params.source_size))) {
+ return;
+ }
+
+ ivec2 clamp_min = ivec2(params.source_offset);
+ ivec2 clamp_max = ivec2(params.source_size) - 1;
+
+ //gaussian kernel, size 9, sigma 4
+ const int kernel_size = 9;
+ const float gaussian_kernel[kernel_size * 3] = float[](
+ 0.000229, 0.005977, 0.060598, 0.241732, 0.382928, 0.241732, 0.060598, 0.005977, 0.000229,
+ 0.028532, 0.067234, 0.124009, 0.179044, 0.20236, 0.179044, 0.124009, 0.067234, 0.028532,
+ 0.081812, 0.101701, 0.118804, 0.130417, 0.134535, 0.130417, 0.118804, 0.101701, 0.081812);
+ float accum = 0.0;
+ for (int i = 0; i < kernel_size; i++) {
+ ivec2 ofs = clamp(image_pos + params.filter_dir * (i - kernel_size / 2), clamp_min, clamp_max);
+ accum += imageLoad(source_depth, ofs).r * gaussian_kernel[params.gaussian_kernel_version + i];
+ }
+
+ imageStore(dst_depth, image_pos, vec4(accum));
+
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl
index 9c59be6841..7b6de6a555 100644
--- a/servers/rendering/rasterizer_rd/shaders/sky.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl
@@ -58,6 +58,35 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData
}
global_variables;
+layout(set = 0, binding = 2, std140) uniform SceneData {
+ bool volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+ uint volumetric_fog_pad;
+
+ vec3 fog_light_color;
+ float fog_sun_scatter;
+
+ bool fog_enabled;
+ float fog_density;
+
+ float z_far;
+ uint directional_light_count;
+}
+scene_data;
+
+struct DirectionalLightData {
+ vec4 direction_energy;
+ vec4 color_size;
+ bool enabled;
+};
+
+layout(set = 0, binding = 3, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+
+directional_lights;
+
#ifdef USE_MATERIAL_UNIFORMS
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
/* clang-format off */
@@ -77,6 +106,8 @@ layout(set = 2, binding = 1) uniform texture2D half_res;
layout(set = 2, binding = 2) uniform texture2D quarter_res;
#endif
+layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture;
+
#ifdef USE_CUBEMAP_PASS
#define AT_CUBEMAP_PASS true
#else
@@ -95,18 +126,6 @@ layout(set = 2, binding = 2) uniform texture2D quarter_res;
#define AT_QUARTER_RES_PASS false
#endif
-struct DirectionalLightData {
- vec4 direction_energy;
- vec4 color_size;
- bool enabled;
-};
-
-layout(set = 3, binding = 0, std140) uniform DirectionalLights {
- DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
-}
-
-directional_lights;
-
/* clang-format off */
FRAGMENT_SHADER_GLOBALS
@@ -115,6 +134,30 @@ FRAGMENT_SHADER_GLOBALS
layout(location = 0) out vec4 frag_color;
+vec4 volumetric_fog_process(vec2 screen_uv) {
+ vec3 fog_pos = vec3(screen_uv, 1.0);
+
+ return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
+}
+
+vec4 fog_process(vec3 view) {
+ vec3 fog_color = scene_data.fog_light_color;
+
+ if (scene_data.fog_sun_scatter > 0.001) {
+ vec4 sun_scatter = vec4(0.0);
+ float sun_total = 0.0;
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ vec3 light_color = directional_lights.data[i].color_size.xyz * directional_lights.data[i].direction_energy.w;
+ float light_amount = pow(max(dot(view, directional_lights.data[i].direction_energy.xyz), 0.0), 8.0);
+ fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ }
+ }
+
+ float fog_amount = clamp(1.0 - exp(-scene_data.z_far * scene_data.fog_density), 0.0, 1.0);
+
+ return vec4(fog_color, fog_amount);
+}
+
void main() {
vec3 cube_normal;
cube_normal.z = -1.0;
@@ -178,6 +221,20 @@ FRAGMENT_SHADER_CODE
frag_color.rgb = color * params.position_multiplier.w;
frag_color.a = alpha;
+#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
+
+ if (scene_data.volumetric_fog_enabled) {
+ vec4 fog = volumetric_fog_process(uv);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ }
+
+ if (scene_data.fog_enabled) {
+ vec4 fog = fog_process(cube_normal);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ }
+
+#endif // DISABLE_FOG
+
// Blending is disabled for Sky, so alpha doesn't blend
// alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
diff --git a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl
new file mode 100644
index 0000000000..cb19fb0b69
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl
@@ -0,0 +1,530 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+#if defined(MODE_FOG) || defined(MODE_FILTER)
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+#endif
+
+#if defined(MODE_DENSITY)
+
+layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
+
+#endif
+
+#include "cluster_data_inc.glsl"
+
+#define M_PI 3.14159265359
+
+layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
+layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
+
+layout(set = 0, binding = 3, std430) restrict readonly buffer Lights {
+ LightData data[];
+}
+lights;
+
+layout(set = 0, binding = 4, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+layout(set = 0, binding = 5) uniform utexture3D cluster_texture;
+
+layout(set = 0, binding = 6, std430) restrict readonly buffer ClusterData {
+ uint indices[];
+}
+cluster_data;
+
+layout(set = 0, binding = 7) uniform sampler linear_sampler;
+
+#ifdef MODE_DENSITY
+layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
+#endif
+
+#ifdef MODE_FOG
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
+#endif
+
+#ifdef MODE_FILTER
+layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
+layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
+#endif
+
+layout(set = 0, binding = 10) uniform sampler shadow_sampler;
+
+#define MAX_GI_PROBES 8
+
+struct GIProbeData {
+ mat4 xform;
+ vec3 bounds;
+ float dynamic_range;
+
+ float bias;
+ float normal_bias;
+ bool blend_ambient;
+ uint texture_slot;
+
+ float anisotropy_strength;
+ float ambient_occlusion;
+ float ambient_occlusion_size;
+ uint mipmaps;
+};
+
+layout(set = 0, binding = 11, std140) uniform GIProbes {
+ GIProbeData data[MAX_GI_PROBES];
+}
+gi_probes;
+
+layout(set = 0, binding = 12) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+
+layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
+
+#ifdef ENABLE_SDFGI
+
+// SDFGI Integration on set 1
+#define SDFGI_MAX_CASCADES 8
+
+struct SDFGIProbeCascadeData {
+ vec3 position;
+ float to_probe;
+ ivec3 probe_world_offset;
+ float to_cell; // 1/bounds * grid_size
+};
+
+layout(set = 1, binding = 0, std140) uniform SDFGI {
+ vec3 grid_size;
+ uint max_cascades;
+
+ bool use_occlusion;
+ int probe_axis_size;
+ float probe_to_uvw;
+ float normal_bias;
+
+ vec3 lightprobe_tex_pixel_size;
+ float energy;
+
+ vec3 lightprobe_uv_offset;
+ float y_mult;
+
+ vec3 occlusion_clamp;
+ uint pad3;
+
+ vec3 occlusion_renormalize;
+ uint pad4;
+
+ vec3 cascade_probe_size;
+ uint pad5;
+
+ SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
+}
+sdfgi;
+
+layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
+
+layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
+
+#endif //SDFGI
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ vec2 fog_frustum_size_begin;
+ vec2 fog_frustum_size_end;
+
+ float fog_frustum_end;
+ float z_near;
+ float z_far;
+ int filter_axis;
+
+ ivec3 fog_volume_size;
+ uint directional_light_count;
+
+ vec3 light_color;
+ float base_density;
+
+ float detail_spread;
+ float gi_inject;
+ uint max_gi_probes;
+ uint pad;
+
+ mat3x4 cam_rotation;
+}
+params;
+
+float get_depth_at_pos(float cell_depth_size, int z) {
+ float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
+ d = pow(d, params.detail_spread);
+ return params.fog_frustum_end * d;
+}
+
+vec3 hash3f(uvec3 x) {
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = (x >> 16) ^ x;
+ return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
+}
+
+void main() {
+ vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
+
+#ifdef MODE_DENSITY
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+
+ vec3 posf = vec3(pos);
+
+ //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
+
+ vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
+ fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
+
+ vec3 view_pos;
+ view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
+ view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
+ view_pos.y = -view_pos.y;
+
+ vec3 total_light = params.light_color;
+
+ float total_density = params.base_density;
+ float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
+ //compute directional lights
+
+ for (uint i = 0; i < params.directional_light_count; i++) {
+ vec3 shadow_attenuation = vec3(1.0);
+
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -view_pos.z;
+
+ vec4 pssm_coord;
+ vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
+ vec3 light_dir = directional_lights.data[i].direction;
+ vec4 v = vec4(view_pos, 1.0);
+ float z_range;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.x;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.y;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.z;
+
+ } else {
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.w;
+ }
+
+ float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
+ float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
+
+ /*
+ //float shadow = textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord);
+ float shadow = 0.0;
+ for(float xi=-1;xi<=1;xi++) {
+ for(float yi=-1;yi<=1;yi++) {
+ vec2 ofs = vec2(xi,yi) * 1.5 * params.directional_shadow_pixel_size;
+ shadow += textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord + vec4(ofs,0.0,0.0));
+ }
+
+ }
+
+ shadow /= 3.0 * 3.0;
+
+*/
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
+
+ shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
+ }
+
+ total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy / M_PI;
+ }
+
+ //compute lights from cluster
+
+ vec3 cluster_pos;
+ cluster_pos.xy = fog_unit_pos.xy;
+ cluster_pos.z = clamp((abs(view_pos.z) - params.z_near) / (params.z_far - params.z_near), 0.0, 1.0);
+
+ uvec4 cluster_cell = texture(usampler3D(cluster_texture, linear_sampler), cluster_pos);
+
+ uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT;
+ uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK;
+
+ for (uint i = 0; i < omni_light_count; i++) {
+ uint light_index = cluster_data.indices[omni_light_pointer + i];
+
+ vec3 light_pos = lights.data[i].position;
+ float d = distance(lights.data[i].position, view_pos) * lights.data[i].inv_radius;
+ vec3 shadow_attenuation = vec3(1.0);
+
+ if (d < 1.0) {
+ vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy);
+ vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular);
+
+ float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x);
+
+ vec3 light = attenuation_energy.y * color_specular.rgb / M_PI;
+
+ vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled);
+
+ if (shadow_color_enabled.a > 0.5) {
+ //has shadow
+ vec4 v = vec4(view_pos, 1.0);
+
+ vec4 splane = (lights.data[i].shadow_matrix * v);
+ float shadow_len = length(splane.xyz); //need to remember shadow len from here
+
+ splane.xyz = normalize(splane.xyz);
+ vec4 clamp_rect = lights.data[i].atlas_rect;
+
+ if (splane.z >= 0.0) {
+ splane.z += 1.0;
+
+ clamp_rect.y += clamp_rect.w;
+
+ } else {
+ splane.z = 1.0 - splane.z;
+ }
+
+ splane.xy /= splane.z;
+
+ splane.xy = splane.xy * 0.5 + 0.5;
+ splane.z = shadow_len * lights.data[i].inv_radius;
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ splane.w = 1.0; //needed? i think it should be 1 already
+
+ float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
+ float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade);
+
+ shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
+ }
+ total_light += light * attenuation * shadow_attenuation;
+ }
+ }
+
+ uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT;
+ uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK;
+
+ for (uint i = 0; i < spot_light_count; i++) {
+ uint light_index = cluster_data.indices[spot_light_pointer + i];
+
+ vec3 light_pos = lights.data[i].position;
+ vec3 light_rel_vec = lights.data[i].position - view_pos;
+ float d = length(light_rel_vec) * lights.data[i].inv_radius;
+ vec3 shadow_attenuation = vec3(1.0);
+
+ if (d < 1.0) {
+ vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy);
+ vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular);
+
+ float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x);
+
+ vec3 spot_dir = lights.data[i].direction;
+ vec2 spot_att_angle = unpackHalf2x16(lights.data[i].cone_attenuation_angle);
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y));
+ attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x);
+
+ vec3 light = attenuation_energy.y * color_specular.rgb / M_PI;
+
+ vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled);
+
+ if (shadow_color_enabled.a > 0.5) {
+ //has shadow
+ vec4 v = vec4(view_pos, 1.0);
+
+ vec4 splane = (lights.data[i].shadow_matrix * v);
+ splane /= splane.w;
+
+ float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
+ float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade);
+
+ shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
+ }
+
+ total_light += light * attenuation * shadow_attenuation;
+ }
+ }
+
+ vec3 world_pos = mat3(params.cam_rotation) * view_pos;
+
+ for (uint i = 0; i < params.max_gi_probes; i++) {
+ vec3 position = (gi_probes.data[i].xform * vec4(world_pos, 1.0)).xyz;
+
+ //this causes corrupted pixels, i have no idea why..
+ if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, gi_probes.data[i].bounds))))) {
+ position /= gi_probes.data[i].bounds;
+
+ vec4 light = vec4(0.0);
+ for (uint j = 0; j < gi_probes.data[i].mipmaps; j++) {
+ vec4 slight = textureLod(sampler3D(gi_probe_textures[i], linear_sampler_with_mipmaps), position, float(j));
+ float a = (1.0 - light.a);
+ light += a * slight;
+ }
+
+ light.rgb *= gi_probes.data[i].dynamic_range * params.gi_inject;
+
+ total_light += light.rgb;
+ }
+ }
+
+ //sdfgi
+#ifdef ENABLE_SDFGI
+
+ {
+ float blend = -1.0;
+ vec3 ambient_total = vec3(0.0);
+
+ for (uint i = 0; i < sdfgi.max_cascades; i++) {
+ vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
+
+ if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
+ continue; //skip cascade
+ }
+
+ vec3 base_pos = floor(cascade_pos);
+ ivec3 probe_base_pos = ivec3(base_pos);
+
+ vec4 ambient_accum = vec4(0.0);
+
+ ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
+ tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
+
+ for (uint j = 0; j < 8; j++) {
+ ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
+ ivec3 probe_posi = probe_base_pos;
+ probe_posi += offset;
+
+ // Compute weight
+
+ vec3 probe_pos = vec3(probe_posi);
+ vec3 probe_to_pos = cascade_pos - probe_pos;
+
+ vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
+ float weight = trilinear.x * trilinear.y * trilinear.z;
+
+ // Compute lightprobe occlusion
+
+ if (sdfgi.use_occlusion) {
+ ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
+ vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
+
+ vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
+ occ_pos.z += float(i);
+ if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
+ occ_pos.x += 1.0;
+ }
+
+ occ_pos *= sdfgi.occlusion_renormalize;
+ float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
+
+ weight *= max(occlusion, 0.01);
+ }
+
+ // Compute ambient texture position
+
+ ivec3 uvw = tex_pos;
+ uvw.xy += offset.xy;
+ uvw.x += offset.z * sdfgi.probe_axis_size;
+
+ vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
+
+ ambient_accum.rgb += ambient * weight;
+ ambient_accum.a += weight;
+ }
+
+ if (ambient_accum.a > 0) {
+ ambient_accum.rgb /= ambient_accum.a;
+ }
+ ambient_total = ambient_accum.rgb;
+ break;
+ }
+
+ total_light += ambient_total * params.gi_inject;
+ }
+
+#endif
+
+ imageStore(density_map, pos, vec4(total_light, total_density));
+#endif
+
+#ifdef MODE_FOG
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
+
+ if (any(greaterThanEqual(pos, params.fog_volume_size))) {
+ return; //do not compute
+ }
+
+ vec4 fog_accum = vec4(0.0);
+ float prev_z = 0.0;
+
+ float t = 1.0;
+
+ for (int i = 0; i < params.fog_volume_size.z; i++) {
+ //compute fog position
+ ivec3 fog_pos = pos + ivec3(0, 0, i);
+ //get fog value
+ vec4 fog = imageLoad(density_map, fog_pos);
+
+ //get depth at cell pos
+ float z = get_depth_at_pos(fog_cell_size.z, i);
+ //get distance from previos pos
+ float d = abs(prev_z - z);
+ //compute exinction based on beer's
+ float extinction = t * exp(-d * fog.a);
+ //compute alpha based on different of extinctions
+ float alpha = t - extinction;
+ //update extinction
+ t = extinction;
+
+ fog_accum += vec4(fog.rgb * alpha, alpha);
+ prev_z = z;
+
+ vec4 fog_value;
+
+ if (fog_accum.a > 0.0) {
+ fog_value = vec4(fog_accum.rgb / fog_accum.a, 1.0 - t);
+ } else {
+ fog_value = vec4(0.0);
+ }
+
+ imageStore(fog_map, fog_pos, fog_value);
+ }
+
+#endif
+
+#ifdef MODE_FILTER
+
+ ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
+
+ const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
+
+ const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
+ ivec3 offset = filter_dir[params.filter_axis];
+
+ vec4 accum = vec4(0.0);
+ for (int i = -3; i <= 3; i++) {
+ accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
+ }
+
+ imageStore(dest_map, pos, accum);
+
+#endif
+}
diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp
index 0400cebfdc..af9ecef0dd 100644
--- a/servers/rendering/rendering_device_binds.cpp
+++ b/servers/rendering/rendering_device_binds.cpp
@@ -135,7 +135,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String
//process include
String include = line.replace("#include", "").strip_edges();
if (!include.begins_with("\"") || !include.ends_with("\"")) {
- base_error = "Malformed #include syntax, expected #include \"<path>\", found instad: " + include;
+ base_error = "Malformed #include syntax, expected #include \"<path>\", found instead: " + include;
break;
}
include = include.substr(1, include.length() - 2).strip_edges();
diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h
index 319c6d9fde..66c6a1c3a9 100644
--- a/servers/rendering/rendering_device_binds.h
+++ b/servers/rendering/rendering_device_binds.h
@@ -620,7 +620,7 @@ protected:
RD_BIND(Variant::INT, RDPipelineColorBlendState, logic_op);
RD_BIND(Variant::COLOR, RDPipelineColorBlendState, blend_constant);
- ClassDB::bind_method(D_METHOD("set_attachments", "atachments"), &RDPipelineColorBlendState::set_attachments);
+ ClassDB::bind_method(D_METHOD("set_attachments", "attachments"), &RDPipelineColorBlendState::set_attachments);
ClassDB::bind_method(D_METHOD("get_attachments"), &RDPipelineColorBlendState::get_attachments);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "attachments", PROPERTY_HINT_ARRAY_TYPE, "RDPipelineColorBlendStateAttachment"), "set_attachments", "get_attachments");
}
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
index 706912b353..b4eac8cd76 100644
--- a/servers/rendering/rendering_server_raster.h
+++ b/servers/rendering/rendering_server_raster.h
@@ -562,9 +562,13 @@ public:
BIND6(environment_set_adjustment, RID, bool, float, float, float, RID)
- BIND5(environment_set_fog, RID, bool, const Color &, const Color &, float)
- BIND7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
- BIND5(environment_set_fog_height, RID, bool, float, float, float)
+ BIND8(environment_set_fog, RID, bool, const Color &, float, float, float, float, float)
+ BIND9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter)
+
+ BIND2(environment_set_volumetric_fog_volume_size, int, int)
+ BIND1(environment_set_volumetric_fog_filter_active, bool)
+ BIND1(environment_set_volumetric_fog_directional_shadow_shrink_size, int)
+ BIND1(environment_set_volumetric_fog_positional_shadow_shrink_size, int)
BIND11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float)
BIND1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount)
diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp
index 75a5834791..2024f5b983 100644
--- a/servers/rendering/rendering_server_scene.cpp
+++ b/servers/rendering/rendering_server_scene.cpp
@@ -370,8 +370,8 @@ void RenderingServerScene::instance_set_base(RID p_instance, RID p_base) {
case RS::INSTANCE_LIGHT: {
InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
- if (RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
- instance->scenario->dynamic_lights.erase(light->instance);
+ if (scenario && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
+ scenario->dynamic_lights.erase(light->instance);
}
#ifdef DEBUG_ENABLED
@@ -379,8 +379,8 @@ void RenderingServerScene::instance_set_base(RID p_instance, RID p_base) {
ERR_PRINT("BUG, indexing did not unpair geometries from light.");
}
#endif
- if (instance->scenario && light->D) {
- instance->scenario->directional_lights.erase(light->D);
+ if (scenario && light->D) {
+ scenario->directional_lights.erase(light->D);
light->D = nullptr;
}
RSG::scene_render->free(light->instance);
@@ -986,13 +986,13 @@ void RenderingServerScene::_update_instance(Instance *p_instance) {
RS::LightBakeMode bake_mode = RSG::storage->light_get_bake_mode(p_instance->base);
if (RSG::storage->light_get_type(p_instance->base) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode) {
- if (light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
+ if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
p_instance->scenario->dynamic_lights.erase(light->instance);
}
light->bake_mode = bake_mode;
- if (light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
+ if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
p_instance->scenario->dynamic_lights.push_back(light->instance);
}
}
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index 60a694eed5..fb5c161c8a 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -479,9 +479,14 @@ public:
FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID)
- FUNC5(environment_set_fog, RID, bool, const Color &, const Color &, float)
- FUNC7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
- FUNC5(environment_set_fog_height, RID, bool, float, float, float)
+ FUNC8(environment_set_fog, RID, bool, const Color &, float, float, float, float, float)
+
+ FUNC9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter)
+
+ FUNC2(environment_set_volumetric_fog_volume_size, int, int)
+ FUNC1(environment_set_volumetric_fog_filter_active, bool)
+ FUNC1(environment_set_volumetric_fog_directional_shadow_shrink_size, int)
+ FUNC1(environment_set_volumetric_fog_positional_shadow_shrink_size, int)
FUNC3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index b903951400..d6acad83f7 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -645,7 +645,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
if (hexa_found) {
tk.constant = (double)str.hex_to_int(true);
} else {
- tk.constant = str.to_double();
+ tk.constant = str.to_float();
}
tk.line = tk_line;
@@ -1137,13 +1137,13 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} else if (na == TYPE_FLOAT && nb == TYPE_VEC4) {
valid = true;
ret_type = TYPE_VEC4;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT2) {
+ } else if (na == TYPE_FLOAT && nb == TYPE_MAT2) {
valid = true;
ret_type = TYPE_MAT2;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT3) {
+ } else if (na == TYPE_FLOAT && nb == TYPE_MAT3) {
valid = true;
ret_type = TYPE_MAT3;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT4) {
+ } else if (na == TYPE_FLOAT && nb == TYPE_MAT4) {
valid = true;
ret_type = TYPE_MAT4;
} else if (p_op->op == OP_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
@@ -1313,13 +1313,13 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} else if (na == TYPE_VEC4 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_VEC4;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT2 && nb == TYPE_VEC2) {
+ } else if (na == TYPE_MAT2 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_MAT2;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT3 && nb == TYPE_VEC3) {
+ } else if (na == TYPE_MAT3 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_MAT3;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT4 && nb == TYPE_VEC4) {
+ } else if (na == TYPE_MAT4 && nb == TYPE_FLOAT) {
valid = true;
ret_type = TYPE_MAT4;
} else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 06cb6171a5..76aeb5989c 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -328,6 +328,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
+ shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog");
shader_types.insert("spatial");
shader_types.insert("canvas_item");