From bad5c659a42cf31e9004280dfa61838be1f6280a Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Tue, 19 Jul 2022 14:17:58 +1000 Subject: Move Sky(RD) into environment Move Fog logic from render scene render to fog --- servers/rendering/renderer_rd/environment/fog.cpp | 1061 +++++++++++ servers/rendering/renderer_rd/environment/fog.h | 246 +++ servers/rendering/renderer_rd/environment/gi.cpp | 4 +- servers/rendering/renderer_rd/environment/gi.h | 6 +- servers/rendering/renderer_rd/environment/sky.cpp | 1926 ++++++++++++++++++++ servers/rendering/renderer_rd/environment/sky.h | 325 ++++ .../renderer_rd/renderer_scene_render_rd.cpp | 1083 +---------- .../renderer_rd/renderer_scene_render_rd.h | 231 +-- .../renderer_rd/renderer_scene_sky_rd.cpp | 1924 ------------------- .../rendering/renderer_rd/renderer_scene_sky_rd.h | 321 ---- .../renderer_rd/shaders/environment/sky.glsl | 253 +++ .../shaders/environment/volumetric_fog.glsl | 309 ++++ .../environment/volumetric_fog_process.glsl | 782 ++++++++ servers/rendering/renderer_rd/shaders/sky.glsl | 253 --- .../renderer_rd/shaders/volumetric_fog.glsl | 309 ---- .../shaders/volumetric_fog_process.glsl | 782 -------- 16 files changed, 4960 insertions(+), 4855 deletions(-) create mode 100644 servers/rendering/renderer_rd/environment/sky.cpp create mode 100644 servers/rendering/renderer_rd/environment/sky.h delete mode 100644 servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp delete mode 100644 servers/rendering/renderer_rd/renderer_scene_sky_rd.h create mode 100644 servers/rendering/renderer_rd/shaders/environment/sky.glsl create mode 100644 servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl create mode 100644 servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl delete mode 100644 servers/rendering/renderer_rd/shaders/sky.glsl delete mode 100644 servers/rendering/renderer_rd/shaders/volumetric_fog.glsl delete mode 100644 servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 2a6c96480e..63c227e89b 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -30,6 +30,11 @@ #include "fog.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" +#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" +#include "servers/rendering/rendering_server_default.h" + using namespace RendererRD; Fog *Fog::singleton = nullptr; @@ -126,3 +131,1059 @@ Vector3 Fog::fog_volume_get_extents(RID p_fog_volume) const { ERR_FAIL_COND_V(!fog_volume, Vector3()); return fog_volume->extents; } + +//////////////////////////////////////////////////////////////////////////////// +// Fog material + +bool Fog::FogMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + uniform_set_updated = true; + + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL); +} + +Fog::FogMaterialData::~FogMaterialData() { + free_parameters_uniform_set(uniform_set); +} + +RendererRD::ShaderData *Fog::_create_fog_shader_func() { + FogShaderData *shader_data = memnew(FogShaderData); + return shader_data; +} + +RendererRD::ShaderData *Fog::_create_fog_shader_funcs() { + return Fog::get_singleton()->_create_fog_shader_func(); +}; + +RendererRD::MaterialData *Fog::_create_fog_material_func(FogShaderData *p_shader) { + FogMaterialData *material_data = memnew(FogMaterialData); + material_data->shader_data = p_shader; + //update will happen later anyway so do nothing. + return material_data; +} + +RendererRD::MaterialData *Fog::_create_fog_material_funcs(RendererRD::ShaderData *p_shader) { + return Fog::get_singleton()->_create_fog_material_func(static_cast(p_shader)); +}; + +//////////////////////////////////////////////////////////////////////////////// +// FOG VOLUMES INSTANCE + +RID Fog::fog_volume_instance_create(RID p_fog_volume) { + FogVolumeInstance fvi; + fvi.volume = p_fog_volume; + return fog_volume_instance_owner.make_rid(fvi); +} + +void Fog::fog_instance_free(RID p_rid) { + fog_volume_instance_owner.free(p_rid); +} + +//////////////////////////////////////////////////////////////////////////////// +// Volumetric Fog Shader + +void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_layers, bool p_is_using_radiance_cubemap_array) { + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + + { + // Initialize local fog shader + Vector volumetric_fog_modes; + volumetric_fog_modes.push_back(""); + volumetric_fog.shader.initialize(volumetric_fog_modes); + + material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_FOG, _create_fog_shader_funcs); + material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_FOG, _create_fog_material_funcs); + volumetric_fog.volume_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::VolumeUBO)); + } + + { + ShaderCompiler::DefaultIdentifierActions actions; + + actions.renames["TIME"] = "scene_params.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); + actions.renames["WORLD_POSITION"] = "world.xyz"; + actions.renames["OBJECT_POSITION"] = "params.position"; + actions.renames["UVW"] = "uvw"; + actions.renames["EXTENTS"] = "params.extents"; + actions.renames["ALBEDO"] = "albedo"; + actions.renames["DENSITY"] = "density"; + actions.renames["EMISSION"] = "emission"; + actions.renames["SDF"] = "sdf"; + + actions.usage_defines["SDF"] = "#define SDF_USED\n"; + actions.usage_defines["DENSITY"] = "#define DENSITY_USED\n"; + actions.usage_defines["ALBEDO"] = "#define ALBEDO_USED\n"; + actions.usage_defines["EMISSION"] = "#define EMISSION_USED\n"; + + actions.sampler_array_name = "material_samplers"; + actions.base_texture_binding_index = 1; + actions.texture_layout_set = VolumetricFogShader::FogSet::FOG_SET_MATERIAL; + actions.base_uniform_string = "material."; + + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; + actions.default_repeat = ShaderLanguage::REPEAT_DISABLE; + actions.global_buffer_array_variable = "global_variables.data"; + + volumetric_fog.compiler.initialize(actions); + } + + { + // default material and shader for fog shader + volumetric_fog.default_shader = material_storage->shader_allocate(); + material_storage->shader_initialize(volumetric_fog.default_shader); + material_storage->shader_set_code(volumetric_fog.default_shader, R"( +// Default fog shader. + +shader_type fog; + +void fog() { +DENSITY = 1.0; +ALBEDO = vec3(1.0); +} +)"); + volumetric_fog.default_material = material_storage->material_allocate(); + material_storage->material_initialize(volumetric_fog.default_material); + material_storage->material_set_shader(volumetric_fog.default_material, volumetric_fog.default_shader); + + FogMaterialData *md = static_cast(material_storage->material_get_data(volumetric_fog.default_material, RendererRD::SHADER_TYPE_FOG)); + volumetric_fog.default_shader_rd = volumetric_fog.shader.version_get_shader(md->shader_data->version, 0); + + Vector uniforms; + + { + Vector ids; + ids.resize(12); + RID *ids_ptr = ids.ptrw(); + ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + + RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 1, ids); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.append_id(RendererRD::MaterialStorage::get_singleton()->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + + volumetric_fog.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_BASE); + } + { + String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(p_max_directional_lights) + "\n"; + defines += "\n#define MAX_SKY_LOD " + itos(p_roughness_layers - 1) + ".0\n"; + if (p_is_using_radiance_cubemap_array) { + defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + } + Vector 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_modes.push_back("\n#define MODE_COPY\n"); + + volumetric_fog.process_shader.initialize(volumetric_fog_modes, defines); + volumetric_fog.process_shader_version = volumetric_fog.process_shader.version_create(); + for (int i = 0; i < VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_MAX; i++) { + volumetric_fog.process_pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, i)); + } + volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO)); + } +} + +void Fog::free_fog_shader() { + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + + volumetric_fog.process_shader.version_free(volumetric_fog.process_shader_version); + RD::get_singleton()->free(volumetric_fog.volume_ubo); + RD::get_singleton()->free(volumetric_fog.params_ubo); + material_storage->shader_free(volumetric_fog.default_shader); + material_storage->material_free(volumetric_fog.default_material); +} + +void Fog::FogShaderData::set_path_hint(const String &p_path) { + path = p_path; +} + +void Fog::FogShaderData::set_code(const String &p_code) { + //compile + + code = p_code; + valid = false; + ubo_size = 0; + uniforms.clear(); + + if (code.is_empty()) { + return; //just invalid, but no error + } + + ShaderCompiler::GeneratedCode gen_code; + ShaderCompiler::IdentifierActions actions; + actions.entry_point_stages["fog"] = ShaderCompiler::STAGE_COMPUTE; + + uses_time = false; + + actions.usage_flag_pointers["TIME"] = &uses_time; + + actions.uniforms = &uniforms; + + Fog *fog_singleton = Fog::get_singleton(); + + Error err = fog_singleton->volumetric_fog.compiler.compile(RS::SHADER_FOG, code, &actions, path, gen_code); + ERR_FAIL_COND_MSG(err != OK, "Fog shader compilation failed."); + + if (version.is_null()) { + version = fog_singleton->volumetric_fog.shader.version_create(); + } + + fog_singleton->volumetric_fog.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_COMPUTE], gen_code.defines); + ERR_FAIL_COND(!fog_singleton->volumetric_fog.shader.version_is_valid(version)); + + ubo_size = gen_code.uniform_total_size; + ubo_offsets = gen_code.uniform_offsets; + texture_uniforms = gen_code.texture_uniforms; + + pipeline = RD::get_singleton()->compute_pipeline_create(fog_singleton->volumetric_fog.shader.version_get_shader(version, 0)); + + valid = true; +} + +void Fog::FogShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { + if (!p_texture.is_valid()) { + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } + } else { + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = HashMap(); + } + default_texture_params[p_name][p_index] = p_texture; + } +} + +void Fog::FogShaderData::get_param_list(List *p_param_list) const { + RBMap order; + + for (const KeyValue &E : uniforms) { + if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + if (E.value.texture_order >= 0) { + order[E.value.texture_order + 100000] = E.key; + } else { + order[E.value.order] = E.key; + } + } + + for (const KeyValue &E : order) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); + pi.name = E.value; + p_param_list->push_back(pi); + } +} + +void Fog::FogShaderData::get_instance_param_list(List *p_param_list) const { + for (const KeyValue &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RendererMaterialStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E.value); + p.info.name = E.key; //supply name + p.index = E.value.instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); + p_param_list->push_back(p); + } +} + +bool Fog::FogShaderData::is_param_texture(const StringName &p_param) const { + if (!uniforms.has(p_param)) { + return false; + } + + return uniforms[p_param].texture_order >= 0; +} + +bool Fog::FogShaderData::is_animated() const { + return false; +} + +bool Fog::FogShaderData::casts_shadows() const { + return false; +} + +Variant Fog::FogShaderData::get_default_parameter(const StringName &p_parameter) const { + if (uniforms.has(p_parameter)) { + ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; + Vector default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); + } + return Variant(); +} + +RS::ShaderNativeSourceCode Fog::FogShaderData::get_native_source_code() const { + Fog *fog_singleton = Fog::get_singleton(); + + return fog_singleton->volumetric_fog.shader.version_get_native_source_code(version); +} + +Fog::FogShaderData::~FogShaderData() { + Fog *fog_singleton = Fog::get_singleton(); + ERR_FAIL_COND(!fog_singleton); + //pipeline variants will clear themselves if shader is gone + if (version.is_valid()) { + fog_singleton->volumetric_fog.shader.version_free(version); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Volumetric Fog + +Fog::VolumetricFog::VolumetricFog(const Vector3i &fog_size, RID p_sky_shader) { + width = fog_size.x; + height = fog_size.y; + depth = fog_size.z; + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = fog_size.x; + tf.height = fog_size.y; + tf.depth = fog_size.z; + tf.texture_type = RD::TEXTURE_TYPE_3D; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + + light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(light_density_map, "Fog light-density map"); + + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + + prev_light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(prev_light_density_map, "Fog previous light-density map"); + RD::get_singleton()->texture_clear(prev_light_density_map, Color(0, 0, 0, 0), 0, 1, 0, 1); + + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(fog_map, "Fog map"); + +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + Vector dm; + dm.resize(fog_size.x * fog_size.y * fog_size.z * 4); + dm.fill(0); + + density_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); + RD::get_singleton()->set_resource_name(density_map, "Fog density map"); + light_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); + RD::get_singleton()->set_resource_name(light_map, "Fog light map"); + emissive_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); + RD::get_singleton()->set_resource_name(emissive_map, "Fog emissive map"); +#else + tf.format = RD::DATA_FORMAT_R32_UINT; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(density_map, "Fog density map"); + RD::get_singleton()->texture_clear(density_map, Color(0, 0, 0, 0), 0, 1, 0, 1); + light_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(light_map, "Fog light map"); + RD::get_singleton()->texture_clear(light_map, Color(0, 0, 0, 0), 0, 1, 0, 1); + emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(emissive_map, "Fog emissive map"); + RD::get_singleton()->texture_clear(emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1); +#endif + + Vector uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.append_id(fog_map); + uniforms.push_back(u); + } + + sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_sky_shader, RendererRD::SkyRD::SKY_SET_FOG); +} + +Fog::VolumetricFog::~VolumetricFog() { + RD::get_singleton()->free(prev_light_density_map); + RD::get_singleton()->free(light_density_map); + RD::get_singleton()->free(fog_map); + RD::get_singleton()->free(density_map); + RD::get_singleton()->free(light_map); + RD::get_singleton()->free(emissive_map); + + if (fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(fog_uniform_set)) { + RD::get_singleton()->free(fog_uniform_set); + } + if (process_uniform_set_density.is_valid() && RD::get_singleton()->uniform_set_is_valid(process_uniform_set_density)) { + RD::get_singleton()->free(process_uniform_set_density); + } + if (process_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(process_uniform_set)) { + RD::get_singleton()->free(process_uniform_set); + } + if (process_uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(process_uniform_set2)) { + RD::get_singleton()->free(process_uniform_set2); + } + if (sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_uniform_set)) { + RD::get_singleton()->free(sdfgi_uniform_set); + } + if (sky_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_uniform_set)) { + RD::get_singleton()->free(sky_uniform_set); + } +} + +Vector3i Fog::_point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform) { + Vector3 view_position = p_cam_transform.affine_inverse().xform(p_point); + view_position.z = MIN(view_position.z, -0.01); // Clamp to the front of camera + Vector3 fog_position = Vector3(0, 0, 0); + + view_position.y = -view_position.y; + fog_position.z = -view_position.z / fog_end; + fog_position.x = (view_position.x / (2 * (fog_near_size.x * (1.0 - fog_position.z) + fog_far_size.x * fog_position.z))) + 0.5; + fog_position.y = (view_position.y / (2 * (fog_near_size.y * (1.0 - fog_position.z) + fog_far_size.y * fog_position.z))) + 0.5; + fog_position.z = Math::pow(float(fog_position.z), float(1.0 / volumetric_fog_detail_spread)); + fog_position = fog_position * fog_size - Vector3(0.5, 0.5, 0.5); + + fog_position.x = CLAMP(fog_position.x, 0.0, fog_size.x); + fog_position.y = CLAMP(fog_position.y, 0.0, fog_size.y); + fog_position.z = CLAMP(fog_position.z, 0.0, fog_size.z); + + return Vector3i(fog_position); +} + +void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes) { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + + RENDER_TIMESTAMP("> Volumetric Fog"); + RD::get_singleton()->draw_command_begin_label("Volumetric Fog"); + + if (p_fog_volumes.size() > 0) { + RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog Volumes"); + + RENDER_TIMESTAMP("Render FogVolumes"); + + VolumetricFogShader::VolumeUBO params; + + 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 = p_settings.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(); + } + + params.fog_frustum_size_begin[0] = fog_near_size.x; + params.fog_frustum_size_begin[1] = fog_near_size.y; + + params.fog_frustum_size_end[0] = fog_far_size.x; + params.fog_frustum_size_end[1] = fog_far_size.y; + + params.fog_frustum_end = fog_end; + params.z_near = z_near; + params.z_far = z_far; + params.time = p_settings.time; + + params.fog_volume_size[0] = p_settings.vfog->width; + params.fog_volume_size[1] = p_settings.vfog->height; + params.fog_volume_size[2] = p_settings.vfog->depth; + + params.use_temporal_reprojection = p_settings.env->volumetric_fog_temporal_reprojection; + params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES; + params.detail_spread = p_settings.env->volumetric_fog_detail_spread; + params.temporal_blend = p_settings.env->volumetric_fog_temporal_reprojection_amount; + + Transform3D to_prev_cam_view = p_prev_cam_inv_transform * p_cam_transform; + RendererRD::MaterialStorage::store_transform(to_prev_cam_view, params.to_prev_view); + RendererRD::MaterialStorage::store_transform(p_cam_transform, params.transform); + + RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); + + if (p_settings.vfog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_settings.vfog->fog_uniform_set)) { + Vector uniforms; + + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 1; + u.append_id(p_settings.vfog->emissive_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 2; + u.append_id(volumetric_fog.volume_ubo); + uniforms.push_back(u); + } + + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 3; + u.append_id(p_settings.vfog->density_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 4; + u.append_id(p_settings.vfog->light_map); + uniforms.push_back(u); + } + + p_settings.vfog->fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS); + } + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + bool any_uses_time = false; + + for (int i = 0; i < (int)p_fog_volumes.size(); i++) { + FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]); + ERR_FAIL_COND(!fog_volume_instance); + RID fog_volume = fog_volume_instance->volume; + + RID fog_material = RendererRD::Fog::get_singleton()->fog_volume_get_material(fog_volume); + + FogMaterialData *material = nullptr; + + if (fog_material.is_valid()) { + material = static_cast(material_storage->material_get_data(fog_material, RendererRD::SHADER_TYPE_FOG)); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + fog_material = volumetric_fog.default_material; + material = static_cast(material_storage->material_get_data(fog_material, RendererRD::SHADER_TYPE_FOG)); + } + + ERR_FAIL_COND(!material); + + FogShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + any_uses_time |= shader_data->uses_time; + + Vector3i min = Vector3i(); + Vector3i max = Vector3i(); + Vector3i kernel_size = Vector3i(); + + Vector3 position = fog_volume_instance->transform.get_origin(); + RS::FogVolumeShape volume_type = RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume); + Vector3 extents = RendererRD::Fog::get_singleton()->fog_volume_get_extents(fog_volume); + + if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) { + // Local fog volume. + Vector3i points[8]; + Vector3 fog_size = Vector3(p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth); + points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, p_settings.env->volumetric_fog_detail_spread, fog_size, p_cam_transform); + + min = Vector3i(int32_t(p_settings.vfog->width) - 1, int32_t(p_settings.vfog->height) - 1, int32_t(p_settings.vfog->depth) - 1); + max = Vector3i(1, 1, 1); + + for (int j = 0; j < 8; j++) { + min = Vector3i(MIN(min.x, points[j].x), MIN(min.y, points[j].y), MIN(min.z, points[j].z)); + max = Vector3i(MAX(max.x, points[j].x), MAX(max.y, points[j].y), MAX(max.z, points[j].z)); + } + + kernel_size = max - min; + } else { + // Volume type global runs on all cells + extents = Vector3(p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth); + min = Vector3i(0, 0, 0); + kernel_size = Vector3i(int32_t(p_settings.vfog->width), int32_t(p_settings.vfog->height), int32_t(p_settings.vfog->depth)); + } + + if (kernel_size.x == 0 || kernel_size.y == 0 || kernel_size.z == 0) { + continue; + } + + VolumetricFogShader::FogPushConstant push_constant; + push_constant.position[0] = position.x; + push_constant.position[1] = position.y; + push_constant.position[2] = position.z; + push_constant.extents[0] = extents.x; + push_constant.extents[1] = extents.y; + push_constant.extents[2] = extents.z; + push_constant.corner[0] = min.x; + push_constant.corner[1] = min.y; + push_constant.corner[2] = min.z; + push_constant.shape = uint32_t(RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume)); + RendererRD::MaterialStorage::store_transform(fog_volume_instance->transform.affine_inverse(), push_constant.transform); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::FogPushConstant)); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, volumetric_fog.base_uniform_set, VolumetricFogShader::FogSet::FOG_SET_BASE); + if (material->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material->uniform_set)) { // Material may not have a uniform set. + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, material->uniform_set, VolumetricFogShader::FogSet::FOG_SET_MATERIAL); + } + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, kernel_size.x, kernel_size.y, kernel_size.z); + } + if (any_uses_time || p_settings.env->volumetric_fog_temporal_reprojection) { + RenderingServerDefault::redraw_request(); + } + + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->compute_list_end(); + } + + if (p_settings.vfog->process_uniform_set_density.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_settings.vfog->process_uniform_set_density)) { + //re create uniform set if needed + Vector uniforms; + Vector copy_uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1; + if (p_settings.shadow_atlas_depth.is_null()) { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK)); + } else { + u.append_id(p_settings.shadow_atlas_depth); + } + + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; + if (p_settings.directional_shadow_depth.is_valid()) { + u.append_id(p_settings.directional_shadow_depth); + } else { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK)); + } + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 3; + u.append_id(p_settings.omni_light_buffer); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 4; + u.append_id(p_settings.spot_light_buffer); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 5; + u.append_id(p_settings.directional_light_buffer); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 6; + u.append_id(p_settings.cluster_builder->get_cluster_buffer()); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 7; + u.append_id(material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 8; + u.append_id(p_settings.vfog->light_density_map); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 9; + u.append_id(p_settings.vfog->fog_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 9; + u.append_id(p_settings.vfog->prev_light_density_map); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 10; + u.append_id(p_settings.shadow_sampler); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 11; + u.append_id(p_settings.voxel_gl_buffer); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 12; + for (int i = 0; i < RendererRD::GI::MAX_VOXEL_GI_INSTANCES; i++) { + u.append_id(p_settings.rbgi->voxel_gi_textures[i]); + } + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 13; + u.append_id(material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 14; + u.append_id(volumetric_fog.params_ubo); + uniforms.push_back(u); + copy_uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 15; + u.append_id(p_settings.vfog->prev_light_density_map); + uniforms.push_back(u); + } + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 16; + u.append_id(p_settings.vfog->density_map); + uniforms.push_back(u); + } + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 17; + u.append_id(p_settings.vfog->light_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 18; + u.append_id(p_settings.vfog->emissive_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 19; + RID radiance_texture = texture_storage->texture_rd_get_default(p_settings.is_using_radiance_cubemap_array ? RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RID sky_texture = p_settings.env->sky.is_valid() ? p_settings.sky->sky_get_radiance_texture_rd(p_settings.env->sky) : RID(); + u.append_id(sky_texture.is_valid() ? sky_texture : radiance_texture); + uniforms.push_back(u); + } + + p_settings.vfog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0); + + p_settings.vfog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0); + + RID aux7 = uniforms.write[7].get_id(0); + RID aux8 = uniforms.write[8].get_id(0); + + uniforms.write[7].set_id(0, aux8); + uniforms.write[8].set_id(0, aux7); + + p_settings.vfog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0); + + uniforms.remove_at(8); + uniforms.write[7].set_id(0, aux7); + p_settings.vfog->process_uniform_set_density = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0); + } + + bool using_sdfgi = p_settings.env->volumetric_fog_gi_inject > 0.0001 && p_settings.env->sdfgi_enabled && (p_settings.sdfgi != nullptr); + + if (using_sdfgi) { + if (p_settings.vfog->sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_settings.vfog->sdfgi_uniform_set)) { + Vector uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.append_id(p_settings.gi->sdfgi_ubo); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1; + u.append_id(p_settings.sdfgi->ambient_texture); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; + u.append_id(p_settings.sdfgi->occlusion_texture); + uniforms.push_back(u); + } + + p_settings.vfog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI), 1); + } + } + + p_settings.vfog->length = p_settings.env->volumetric_fog_length; + p_settings.vfog->spread = p_settings.env->volumetric_fog_detail_spread; + + VolumetricFogShader::ParamsUBO params; + + 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 = p_settings.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(); + } + + params.fog_frustum_size_begin[0] = fog_near_size.x; + params.fog_frustum_size_begin[1] = fog_near_size.y; + + params.fog_frustum_size_end[0] = fog_far_size.x; + params.fog_frustum_size_end[1] = fog_far_size.y; + + params.ambient_inject = p_settings.env->volumetric_fog_ambient_inject * p_settings.env->ambient_light_energy; + params.z_far = z_far; + + params.fog_frustum_end = fog_end; + + Color ambient_color = p_settings.env->ambient_light.srgb_to_linear(); + params.ambient_color[0] = ambient_color.r; + params.ambient_color[1] = ambient_color.g; + params.ambient_color[2] = ambient_color.b; + params.sky_contribution = p_settings.env->ambient_sky_contribution; + + params.fog_volume_size[0] = p_settings.vfog->width; + params.fog_volume_size[1] = p_settings.vfog->height; + params.fog_volume_size[2] = p_settings.vfog->depth; + + params.directional_light_count = p_directional_light_count; + + Color emission = p_settings.env->volumetric_fog_emission.srgb_to_linear(); + params.base_emission[0] = emission.r * p_settings.env->volumetric_fog_emission_energy; + params.base_emission[1] = emission.g * p_settings.env->volumetric_fog_emission_energy; + params.base_emission[2] = emission.b * p_settings.env->volumetric_fog_emission_energy; + params.base_density = p_settings.env->volumetric_fog_density; + + Color base_scattering = p_settings.env->volumetric_fog_scattering.srgb_to_linear(); + params.base_scattering[0] = base_scattering.r; + params.base_scattering[1] = base_scattering.g; + params.base_scattering[2] = base_scattering.b; + params.phase_g = p_settings.env->volumetric_fog_anisotropy; + + params.detail_spread = p_settings.env->volumetric_fog_detail_spread; + params.gi_inject = p_settings.env->volumetric_fog_gi_inject; + + params.cam_rotation[0] = p_cam_transform.basis[0][0]; + params.cam_rotation[1] = p_cam_transform.basis[1][0]; + params.cam_rotation[2] = p_cam_transform.basis[2][0]; + params.cam_rotation[3] = 0; + params.cam_rotation[4] = p_cam_transform.basis[0][1]; + params.cam_rotation[5] = p_cam_transform.basis[1][1]; + params.cam_rotation[6] = p_cam_transform.basis[2][1]; + params.cam_rotation[7] = 0; + params.cam_rotation[8] = p_cam_transform.basis[0][2]; + params.cam_rotation[9] = p_cam_transform.basis[1][2]; + params.cam_rotation[10] = p_cam_transform.basis[2][2]; + params.cam_rotation[11] = 0; + params.filter_axis = 0; + params.max_voxel_gi_instances = p_settings.env->volumetric_fog_gi_inject > 0.001 ? p_voxel_gi_count : 0; + params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES; + + Transform3D to_prev_cam_view = p_prev_cam_inv_transform * p_cam_transform; + RendererRD::MaterialStorage::store_transform(to_prev_cam_view, params.to_prev_view); + + params.use_temporal_reprojection = p_settings.env->volumetric_fog_temporal_reprojection; + params.temporal_blend = p_settings.env->volumetric_fog_temporal_reprojection_amount; + + { + uint32_t cluster_size = p_settings.cluster_builder->get_cluster_size(); + params.cluster_shift = get_shift_from_power_of_2(cluster_size); + + uint32_t cluster_screen_width = (p_settings.rb_size.x - 1) / cluster_size + 1; + uint32_t cluster_screen_height = (p_settings.rb_size.y - 1) / cluster_size + 1; + params.max_cluster_element_count_div_32 = p_settings.max_cluster_elements / 32; + params.cluster_type_size = cluster_screen_width * cluster_screen_height * (params.max_cluster_element_count_div_32 + 32); + params.cluster_width = cluster_screen_width; + + params.screen_size[0] = p_settings.rb_size.x; + params.screen_size[1] = p_settings.rb_size.y; + } + + Basis sky_transform = p_settings.env->sky_orientation; + sky_transform = sky_transform.inverse() * p_cam_transform.basis; + RendererRD::MaterialStorage::store_transform_3x3(sky_transform, params.radiance_inverse_xform); + + RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog"); + + RENDER_TIMESTAMP("Render Fog"); + RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set_density, 0); + + if (using_sdfgi) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->sdfgi_uniform_set, 1); + } + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + // Copy fog to history buffer + if (p_settings.env->volumetric_fog_temporal_reprojection) { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->copy_uniform_set, 0); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth); + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + RD::get_singleton()->draw_command_end_label(); + + if (p_settings.volumetric_fog_filter_active) { + RD::get_singleton()->draw_command_begin_label("Filter Fog"); + + RENDER_TIMESTAMP("Filter Fog"); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set, 0); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth); + + RD::get_singleton()->compute_list_end(); + //need restart for buffer update + + params.filter_axis = 1; + RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms); + + compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set2, 0); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); + } + + RENDER_TIMESTAMP("Integrate Fog"); + RD::get_singleton()->draw_command_begin_label("Integrate Fog"); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set, 0); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, 1); + + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER); + + RENDER_TIMESTAMP("< Volumetric Fog"); + RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->draw_command_end_label(); +} diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h index 24a3fa798c..61a5d80d20 100644 --- a/servers/rendering/renderer_rd/environment/fog.h +++ b/servers/rendering/renderer_rd/environment/fog.h @@ -34,12 +34,19 @@ #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "servers/rendering/environment/renderer_fog.h" +#include "servers/rendering/renderer_rd/cluster_builder_rd.h" +#include "servers/rendering/renderer_rd/environment/gi.h" +#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" +#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl.gen.h" #include "servers/rendering/storage/utilities.h" namespace RendererRD { class Fog : public RendererFog { public: + /* FOG VOLUMES */ + struct FogVolume { RID material; Vector3 extents = Vector3(1, 1, 1); @@ -49,10 +56,179 @@ public: Dependency dependency; }; + struct FogVolumeInstance { + RID volume; + Transform3D transform; + bool active = false; + }; + private: static Fog *singleton; mutable RID_Owner fog_volume_owner; + mutable RID_Owner fog_volume_instance_owner; + + /* Volumetric Fog */ + struct VolumetricFogShader { + enum FogSet { + FOG_SET_BASE, + FOG_SET_UNIFORMS, + FOG_SET_MATERIAL, + FOG_SET_MAX, + }; + + struct FogPushConstant { + float position[3]; + float pad; + + float extents[3]; + float pad2; + + int32_t corner[3]; + uint32_t shape; + + float transform[16]; + }; + + struct VolumeUBO { + float fog_frustum_size_begin[2]; + float fog_frustum_size_end[2]; + + float fog_frustum_end; + float z_near; + float z_far; + float time; + + int32_t fog_volume_size[3]; + uint32_t directional_light_count; + + uint32_t use_temporal_reprojection; + uint32_t temporal_frame; + float detail_spread; + float temporal_blend; + + float to_prev_view[16]; + float transform[16]; + }; + + ShaderCompiler compiler; + VolumetricFogShaderRD shader; + RID volume_ubo; + + RID default_shader; + RID default_material; + RID default_shader_rd; + + RID base_uniform_set; + + RID params_ubo; + + enum { + VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY, + VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI, + VOLUMETRIC_FOG_PROCESS_SHADER_FILTER, + VOLUMETRIC_FOG_PROCESS_SHADER_FOG, + VOLUMETRIC_FOG_PROCESS_SHADER_COPY, + VOLUMETRIC_FOG_PROCESS_SHADER_MAX, + }; + + struct ParamsUBO { + float fog_frustum_size_begin[2]; + float fog_frustum_size_end[2]; + + float fog_frustum_end; + float ambient_inject; + float z_far; + uint32_t filter_axis; + + float ambient_color[3]; + float sky_contribution; + + int32_t fog_volume_size[3]; + uint32_t directional_light_count; + + float base_emission[3]; + float base_density; + + float base_scattering[3]; + float phase_g; + + float detail_spread; + float gi_inject; + uint32_t max_voxel_gi_instances; + uint32_t cluster_type_size; + + float screen_size[2]; + uint32_t cluster_shift; + uint32_t cluster_width; + + uint32_t max_cluster_element_count_div_32; + uint32_t use_temporal_reprojection; + uint32_t temporal_frame; + float temporal_blend; + + float cam_rotation[12]; + float to_prev_view[16]; + float radiance_inverse_xform[12]; + }; + + VolumetricFogProcessShaderRD process_shader; + + RID process_shader_version; + RID process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX]; + + } volumetric_fog; + + Vector3i _point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform); + + struct FogShaderData : public RendererRD::ShaderData { + bool valid = false; + RID version; + + RID pipeline; + HashMap uniforms; + Vector texture_uniforms; + + Vector ubo_offsets; + uint32_t ubo_size = 0; + + String path; + String code; + HashMap> default_texture_params; + + bool uses_time = false; + + virtual void set_path_hint(const String &p_hint); + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); + virtual void get_param_list(List *p_param_list) const; + virtual void get_instance_param_list(List *p_param_list) const; + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + + FogShaderData() {} + virtual ~FogShaderData(); + }; + + struct FogMaterialData : public RendererRD::MaterialData { + FogShaderData *shader_data = nullptr; + RID uniform_set; + bool uniform_set_updated; + + virtual void set_render_priority(int p_priority) {} + virtual void set_next_pass(RID p_pass) {} + virtual bool update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~FogMaterialData(); + }; + + RendererRD::ShaderData *_create_fog_shader_func(); + static RendererRD::ShaderData *_create_fog_shader_funcs(); + + RendererRD::MaterialData *_create_fog_material_func(FogShaderData *p_shader); + static RendererRD::MaterialData *_create_fog_material_funcs(RendererRD::ShaderData *p_shader); public: static Fog *get_singleton() { return singleton; } @@ -76,6 +252,76 @@ public: RID fog_volume_get_material(RID p_fog_volume) const; virtual AABB fog_volume_get_aabb(RID p_fog_volume) const override; Vector3 fog_volume_get_extents(RID p_fog_volume) const; + + /* FOG VOLUMES INSTANCE */ + + FogVolumeInstance *get_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.get_or_null(p_rid); }; + bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); }; + + RID fog_volume_instance_create(RID p_fog_volume); + void fog_instance_free(RID p_rid); + + /* Volumetric FOG */ + struct VolumetricFog { + enum { + MAX_TEMPORAL_FRAMES = 16 + }; + + uint32_t width = 0; + uint32_t height = 0; + uint32_t depth = 0; + + float length; + float spread; + + RID light_density_map; + RID prev_light_density_map; + RID fog_map; + RID density_map; + RID light_map; + RID emissive_map; + + RID fog_uniform_set; + RID copy_uniform_set; + RID process_uniform_set_density; + RID process_uniform_set; + RID process_uniform_set2; + RID sdfgi_uniform_set; + RID sky_uniform_set; + + int last_shadow_filter = -1; + + VolumetricFog(const Vector3i &fog_size, RID p_sky_shader); + ~VolumetricFog(); + }; + + void init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_layers, bool p_is_using_radiance_cubemap_array); + void free_fog_shader(); + + struct VolumetricFogSettings { + Vector2i rb_size; + double time; + bool is_using_radiance_cubemap_array; + uint32_t max_cluster_elements; + bool volumetric_fog_filter_active; + RID shadow_sampler; + RID voxel_gl_buffer; + RID shadow_atlas_depth; + RID omni_light_buffer; + RID spot_light_buffer; + RID directional_shadow_depth; + RID directional_light_buffer; + + // Objects related to our render buffer + VolumetricFog *vfog; + ClusterBuilderRD *cluster_builder; + GI *gi; + GI::SDFGI *sdfgi; + GI::RenderBuffersGI *rbgi; + RendererSceneEnvironmentRD *env; + SkyRD *sky; + }; + void volumetric_fog_update(const VolumetricFogSettings &p_settings, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes); }; } // namespace RendererRD diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index c37284f72a..cb3de07c31 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -1268,7 +1268,7 @@ void GI::SDFGI::update_light() { RD::get_singleton()->draw_command_end_label(); } -void GI::SDFGI::update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky) { +void GI::SDFGI::update_probes(RendererSceneEnvironmentRD *p_env, SkyRD::Sky *p_sky) { RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes"); SDFGIShader::IntegratePushConstant push_constant; @@ -3233,7 +3233,7 @@ GI::~GI() { singleton = nullptr; } -void GI::init(RendererSceneSkyRD *p_sky) { +void GI::init(SkyRD *p_sky) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h index 517fa86ce3..f4e32a8dd0 100644 --- a/servers/rendering/renderer_rd/environment/gi.h +++ b/servers/rendering/renderer_rd/environment/gi.h @@ -35,8 +35,8 @@ #include "core/templates/rid_owner.h" #include "servers/rendering/environment/renderer_gi.h" #include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/environment/sky.h" #include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" -#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" #include "servers/rendering/renderer_rd/shaders/environment/gi.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl.gen.h" @@ -618,7 +618,7 @@ public: void erase(); void update(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position); void update_light(); - void update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky); + void update_probes(RendererSceneEnvironmentRD *p_env, RendererRD::SkyRD::Sky *p_sky); void store_probes(); int get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const; void update_cascades(); @@ -769,7 +769,7 @@ public: GI(); ~GI(); - void init(RendererSceneSkyRD *p_sky); + void init(RendererRD::SkyRD *p_sky); void free(); SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size); diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp new file mode 100644 index 0000000000..0851e754ea --- /dev/null +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -0,0 +1,1926 @@ +/*************************************************************************/ +/* sky.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "sky.h" +#include "core/config/project_settings.h" +#include "core/math/math_defs.h" +#include "servers/rendering/renderer_rd/effects/copy_effects.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" +#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" +#include "servers/rendering/rendering_server_default.h" +#include "servers/rendering/rendering_server_globals.h" + +using namespace RendererRD; + +//////////////////////////////////////////////////////////////////////////////// +// SKY SHADER + +void SkyRD::SkyShaderData::set_path_hint(const String &p_path) { + path = p_path; +} + +void SkyRD::SkyShaderData::set_code(const String &p_code) { + //compile + + code = p_code; + valid = false; + ubo_size = 0; + uniforms.clear(); + + if (code.is_empty()) { + return; //just invalid, but no error + } + + ShaderCompiler::GeneratedCode gen_code; + ShaderCompiler::IdentifierActions actions; + actions.entry_point_stages["sky"] = ShaderCompiler::STAGE_FRAGMENT; + + uses_time = false; + uses_half_res = false; + uses_quarter_res = false; + uses_position = false; + uses_light = false; + + actions.render_mode_flags["use_half_res_pass"] = &uses_half_res; + actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res; + + actions.usage_flag_pointers["TIME"] = &uses_time; + actions.usage_flag_pointers["POSITION"] = &uses_position; + actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light; + actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light; + actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light; + actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light; + actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light; + actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light; + actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light; + actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light; + actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light; + actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light; + actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light; + actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light; + actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light; + actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light; + actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light; + actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light; + + actions.uniforms = &uniforms; + + // !BAS! Contemplate making `SkyShader sky` accessible from this struct or even part of this struct. + RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); + + Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code); + ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); + + if (version.is_null()) { + version = scene_singleton->sky.sky_shader.shader.version_create(); + } + +#if 0 + print_line("**compiling shader:"); + print_line("**defines:\n"); + for (int i = 0; i < gen_code.defines.size(); i++) { + print_line(gen_code.defines[i]); + } + print_line("\n**uniforms:\n" + gen_code.uniforms); + // print_line("\n**vertex_globals:\n" + gen_code.vertex_global); + // print_line("\n**vertex_code:\n" + gen_code.vertex); + print_line("\n**fragment_globals:\n" + gen_code.fragment_global); + print_line("\n**fragment_code:\n" + gen_code.fragment); + print_line("\n**light_code:\n" + gen_code.light); +#endif + + scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); + ERR_FAIL_COND(!scene_singleton->sky.sky_shader.shader.version_is_valid(version)); + + ubo_size = gen_code.uniform_total_size; + ubo_offsets = gen_code.uniform_offsets; + texture_uniforms = gen_code.texture_uniforms; + + //update pipelines + + for (int i = 0; i < SKY_VERSION_MAX; i++) { + RD::PipelineDepthStencilState depth_stencil_state; + depth_stencil_state.enable_depth_test = true; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + + if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) { + RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); + pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0); + } else { + pipelines[i].clear(); + } + } + + valid = true; +} + +void SkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { + if (!p_texture.is_valid()) { + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } + } else { + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = HashMap(); + } + default_texture_params[p_name][p_index] = p_texture; + } +} + +void SkyRD::SkyShaderData::get_param_list(List *p_param_list) const { + HashMap order; + + for (const KeyValue &E : uniforms) { + if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + if (E.value.texture_order >= 0) { + order[E.value.texture_order + 100000] = E.key; + } else { + order[E.value.order] = E.key; + } + } + + for (const KeyValue &E : order) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); + pi.name = E.value; + p_param_list->push_back(pi); + } +} + +void SkyRD::SkyShaderData::get_instance_param_list(List *p_param_list) const { + for (const KeyValue &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RendererMaterialStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E.value); + p.info.name = E.key; //supply name + p.index = E.value.instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); + p_param_list->push_back(p); + } +} + +bool SkyRD::SkyShaderData::is_param_texture(const StringName &p_param) const { + if (!uniforms.has(p_param)) { + return false; + } + + return uniforms[p_param].texture_order >= 0; +} + +bool SkyRD::SkyShaderData::is_animated() const { + return false; +} + +bool SkyRD::SkyShaderData::casts_shadows() const { + return false; +} + +Variant SkyRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const { + if (uniforms.has(p_parameter)) { + ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; + Vector default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); + } + return Variant(); +} + +RS::ShaderNativeSourceCode SkyRD::SkyShaderData::get_native_source_code() const { + RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); + + return scene_singleton->sky.sky_shader.shader.version_get_native_source_code(version); +} + +SkyRD::SkyShaderData::~SkyShaderData() { + RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); + ERR_FAIL_COND(!scene_singleton); + //pipeline variants will clear themselves if shader is gone + if (version.is_valid()) { + scene_singleton->sky.sky_shader.shader.version_free(version); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Sky material + +bool SkyRD::SkyMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); + + uniform_set_updated = true; + + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); +} + +SkyRD::SkyMaterialData::~SkyMaterialData() { + free_parameters_uniform_set(uniform_set); +} + +//////////////////////////////////////////////////////////////////////////////// +// Render sky + +static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) { + p_array[0] = p_basis.rows[0][0]; + p_array[1] = p_basis.rows[1][0]; + p_array[2] = p_basis.rows[2][0]; + p_array[3] = 0; + p_array[4] = p_basis.rows[0][1]; + p_array[5] = p_basis.rows[1][1]; + p_array[6] = p_basis.rows[2][1]; + p_array[7] = 0; + p_array[8] = p_basis.rows[0][2]; + p_array[9] = p_basis.rows[1][2]; + p_array[10] = p_basis.rows[2][2]; + p_array[11] = 0; +} + +void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier) { + SkyPushConstant sky_push_constant; + + memset(&sky_push_constant, 0, sizeof(SkyPushConstant)); + + for (uint32_t v = 0; v < p_view_count; v++) { + // We only need key components of our projection matrix + sky_push_constant.projections[v][0] = p_projections[v].matrix[2][0]; + sky_push_constant.projections[v][1] = p_projections[v].matrix[0][0]; + sky_push_constant.projections[v][2] = p_projections[v].matrix[2][1]; + sky_push_constant.projections[v][3] = p_projections[v].matrix[1][1]; + } + sky_push_constant.position[0] = p_position.x; + sky_push_constant.position[1] = p_position.y; + sky_push_constant.position[2] = p_position.z; + sky_push_constant.multiplier = p_multiplier; + sky_push_constant.time = p_time; + sky_push_constant.luminance_multiplier = p_luminance_multiplier; + store_transform_3x3(p_orientation, sky_push_constant.orientation); + + RenderingDevice::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_fb); + + RD::DrawListID draw_list = p_list; + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format, false, RD::get_singleton()->draw_list_get_current_pass())); + + // Update uniform sets. + { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0); + if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set. + 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); + // Fog uniform set can be invalidated before drawing, so validate at draw time + if (sky_scene_state.fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_uniform_set)) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3); + } else { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.default_fog_uniform_set, 3); + } + } + + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); +} + +//////////////////////////////////////////////////////////////////////////////// +// ReflectionData + +void SkyRD::ReflectionData::clear_reflection_data() { + layers.clear(); + radiance_base_cubemap = RID(); + if (downsampled_radiance_cubemap.is_valid()) { + RD::get_singleton()->free(downsampled_radiance_cubemap); + } + downsampled_radiance_cubemap = RID(); + downsampled_layer.mipmaps.clear(); + coefficient_buffer = RID(); +} + +void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format) { + //recreate radiance and all data + + int mipmaps = p_mipmaps; + uint32_t w = p_size, h = p_size; + + EffectsRD *effects = RendererCompositorRD::singleton->get_effects(); + ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); + bool prefer_raster_effects = effects->get_prefer_raster_effects(); + + if (p_use_array) { + int num_layers = p_low_quality ? 8 : p_roughness_layers; + + for (int i = 0; i < num_layers; i++) { + ReflectionData::Layer layer; + uint32_t mmw = w; + uint32_t mmh = h; + layer.mipmaps.resize(mipmaps); + layer.views.resize(mipmaps); + for (int j = 0; j < mipmaps; j++) { + ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; + mm.size.width = mmw; + mm.size.height = mmh; + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j); + Vector fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + + layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, 1, RD::TEXTURE_SLICE_CUBEMAP); + + mmw = MAX(1u, mmw >> 1); + mmh = MAX(1u, mmh >> 1); + } + + layers.push_back(layer); + } + + } else { + mipmaps = p_low_quality ? 8 : mipmaps; + //regular cubemap, lower quality (aliasing, less memory) + ReflectionData::Layer layer; + uint32_t mmw = w; + uint32_t mmh = h; + layer.mipmaps.resize(mipmaps); + layer.views.resize(mipmaps); + for (int j = 0; j < mipmaps; j++) { + ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; + mm.size.width = mmw; + mm.size.height = mmh; + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j); + Vector fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + + layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, 1, RD::TEXTURE_SLICE_CUBEMAP); + + mmw = MAX(1u, mmw >> 1); + mmh = MAX(1u, mmh >> 1); + } + + layers.push_back(layer); + } + + radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, 1, RD::TEXTURE_SLICE_CUBEMAP); + RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap"); + RD::TextureFormat tf; + tf.format = p_texture_format; + tf.width = 64; // Always 64x64 + tf.height = 64; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; + tf.array_layers = 6; + tf.mipmaps = 7; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(downsampled_radiance_cubemap, "downsampled radiance cubemap"); + { + uint32_t mmw = 64; + uint32_t mmh = 64; + downsampled_layer.mipmaps.resize(7); + for (int j = 0; j < downsampled_layer.mipmaps.size(); j++) { + ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j]; + mm.size.width = mmw; + mm.size.height = mmh; + mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, 1, RD::TEXTURE_SLICE_CUBEMAP); + RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " "); + if (prefer_raster_effects) { + // we need a framebuffer for each side of our cubemap + + for (int k = 0; k < 6; k++) { + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, k, j); + RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip: " + itos(j) + " Face: " + itos(k) + " "); + Vector fbtex; + fbtex.push_back(mm.views[k]); + mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); + } + } + + mmw = MAX(1u, mmw >> 1); + mmh = MAX(1u, mmh >> 1); + } + } +} + +void SkyRD::ReflectionData::create_reflection_fast_filter(bool p_use_arrays) { + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); + bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); + + if (prefer_raster_effects) { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); + } + + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); + } + } + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance + + if (p_use_arrays) { + RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads"); + for (int i = 0; i < layers.size(); i++) { + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i); + } + } + } else { + RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly"); + for (int j = 0; j < layers[0].mipmaps.size(); j++) { + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j); + } + } + } + RD::get_singleton()->draw_command_end_label(); // Filter radiance + } else { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); + copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + } + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance + Vector views; + if (p_use_arrays) { + for (int i = 1; i < layers.size(); i++) { + views.push_back(layers[i].views[0]); + } + } else { + for (int i = 1; i < layers[0].views.size(); i++) { + views.push_back(layers[0].views[i]); + } + } + RD::get_singleton()->draw_command_begin_label("Fast filter radiance"); + copy_effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); + RD::get_singleton()->draw_command_end_label(); // Filter radiance + } +} + +void SkyRD::ReflectionData::create_reflection_importance_sample(bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) { + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); + bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); + + if (prefer_raster_effects) { + if (p_base_layer == 1) { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); + } + + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); + } + } + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance + } + + RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); + if (p_use_arrays) { + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_roughness_raster( + downsampled_radiance_cubemap, + layers[p_base_layer].mipmaps[0].framebuffers[k], + k, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers.size() - 1.0), + layers[p_base_layer].mipmaps[0].size.x); + } + } else { + for (int k = 0; k < 6; k++) { + copy_effects->cubemap_roughness_raster( + downsampled_radiance_cubemap, + layers[0].mipmaps[p_base_layer].framebuffers[k], + k, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), + layers[0].mipmaps[p_base_layer].size.x); + } + } + } else { + if (p_base_layer == 1) { + RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); + copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + + for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { + copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + } + RD::get_singleton()->draw_command_end_label(); // Downsample Radiance + } + + RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); + if (p_use_arrays) { + copy_effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); + } else { + copy_effects->cubemap_roughness( + downsampled_radiance_cubemap, + layers[0].views[p_base_layer], + p_cube_side, + p_sky_ggx_samples_quality, + float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), + layers[0].mipmaps[p_base_layer].size.x); + } + } + RD::get_singleton()->draw_command_end_label(); // Filter radiance +} + +void SkyRD::ReflectionData::update_reflection_mipmaps(int p_start, int p_end) { + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); + bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); + + RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps"); + for (int i = p_start; i < p_end; i++) { + for (int j = 0; j < layers[i].views.size() - 1; j++) { + RID view = layers[i].views[j]; + Size2i size = layers[i].mipmaps[j + 1].size; + if (prefer_raster_effects) { + for (int k = 0; k < 6; k++) { + RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k]; + copy_effects->cubemap_downsample_raster(view, framebuffer, k, size); + } + } else { + RID texture = layers[i].views[j + 1]; + copy_effects->cubemap_downsample(view, texture, size); + } + } + } + RD::get_singleton()->draw_command_end_label(); +} + +//////////////////////////////////////////////////////////////////////////////// +// SkyRD::Sky + +void SkyRD::Sky::free() { + if (radiance.is_valid()) { + RD::get_singleton()->free(radiance); + radiance = RID(); + } + reflection.clear_reflection_data(); + + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + uniform_buffer = RID(); + } + + if (half_res_pass.is_valid()) { + RD::get_singleton()->free(half_res_pass); + half_res_pass = RID(); + } + + if (quarter_res_pass.is_valid()) { + RD::get_singleton()->free(quarter_res_pass); + quarter_res_pass = RID(); + } + + if (material.is_valid()) { + RSG::material_storage->material_free(material); + material = RID(); + } +} + +RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd) { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + + if (texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(texture_uniform_sets[p_version])) { + return texture_uniform_sets[p_version]; + } + Vector uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + if (radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { + u.append_id(radiance); + } else { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1; // half res + if (half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { + if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { + u.append_id(reflection.layers[0].views[1]); + } else { + u.append_id(half_res_pass); + } + } else { + if (p_version < SKY_TEXTURE_SET_CUBEMAP) { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); + } else { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + } + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; // quarter res + if (quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { + if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { + u.append_id(reflection.layers[0].views[2]); + } else { + u.append_id(quarter_res_pass); + } + } else { + if (p_version < SKY_TEXTURE_SET_CUBEMAP) { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); + } else { + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + } + } + uniforms.push_back(u); + } + + texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, p_default_shader_rd, SKY_SET_TEXTURES); + return texture_uniform_sets[p_version]; +} + +bool SkyRD::Sky::set_radiance_size(int p_radiance_size) { + ERR_FAIL_COND_V(p_radiance_size < 32 || p_radiance_size > 2048, false); + if (radiance_size == p_radiance_size) { + return false; + } + radiance_size = p_radiance_size; + + if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { + WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); + radiance_size = 256; + } + + if (radiance.is_valid()) { + RD::get_singleton()->free(radiance); + radiance = RID(); + } + reflection.clear_reflection_data(); + + return true; +} + +bool SkyRD::Sky::set_mode(RS::SkyMode p_mode) { + if (mode == p_mode) { + return false; + } + + mode = p_mode; + + if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { + WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); + set_radiance_size(256); + } + + if (radiance.is_valid()) { + RD::get_singleton()->free(radiance); + radiance = RID(); + } + reflection.clear_reflection_data(); + + return true; +} + +bool SkyRD::Sky::set_material(RID p_material) { + if (material == p_material) { + return false; + } + + material = p_material; + return true; +} + +Ref SkyRD::Sky::bake_panorama(float p_energy, int p_roughness_layers, const Size2i &p_size) { + if (radiance.is_valid()) { + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + tf.width = p_size.width; + tf.height = p_size.height; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + + RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView()); + copy_effects->copy_cubemap_to_panorama(radiance, rad_tex, p_size, p_roughness_layers, reflection.layers.size() > 1); + Vector data = RD::get_singleton()->texture_get_data(rad_tex, 0); + RD::get_singleton()->free(rad_tex); + + Ref img; + img.instantiate(); + img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data); + for (int i = 0; i < p_size.width; i++) { + for (int j = 0; j < p_size.height; j++) { + Color c = img->get_pixel(i, j); + c.r *= p_energy; + c.g *= p_energy; + c.b *= p_energy; + img->set_pixel(i, j, c); + } + } + return img; + } + + return Ref(); +} + +//////////////////////////////////////////////////////////////////////////////// +// SkyRD + +RendererRD::ShaderData *SkyRD::_create_sky_shader_func() { + SkyShaderData *shader_data = memnew(SkyShaderData); + return shader_data; +} + +RendererRD::ShaderData *SkyRD::_create_sky_shader_funcs() { + // !BAS! Why isn't _create_sky_shader_func not just static too? + return static_cast(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func(); +}; + +RendererRD::MaterialData *SkyRD::_create_sky_material_func(SkyShaderData *p_shader) { + SkyMaterialData *material_data = memnew(SkyMaterialData); + material_data->shader_data = p_shader; + //update will happen later anyway so do nothing. + return material_data; +} + +RendererRD::MaterialData *SkyRD::_create_sky_material_funcs(RendererRD::ShaderData *p_shader) { + // !BAS! same here, we could just make _create_sky_material_func static? + return static_cast(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast(p_shader)); +}; + +SkyRD::SkyRD() { + roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers"); + sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"); + sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections"); +} + +void SkyRD::init() { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + + { + // Start with the directional lights for the sky + sky_scene_state.max_directional_lights = 4; + uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData); + sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); + sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); + sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1; + sky_scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); + + String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_scene_state.max_directional_lights) + "\n"; + + // Initialize sky + Vector sky_modes; + sky_modes.push_back(""); // Full size + sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res + sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res + sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap + sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap + sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap + + sky_modes.push_back("\n#define USE_MULTIVIEW\n"); // Full size multiview + sky_modes.push_back("\n#define USE_HALF_RES_PASS\n#define USE_MULTIVIEW\n"); // Half Res multiview + sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n#define USE_MULTIVIEW\n"); // Quarter res multiview + + sky_shader.shader.initialize(sky_modes, defines); + + if (!RendererCompositorRD::singleton->is_xr_enabled()) { + sky_shader.shader.set_variant_enabled(SKY_VERSION_BACKGROUND_MULTIVIEW, false); + sky_shader.shader.set_variant_enabled(SKY_VERSION_HALF_RES_MULTIVIEW, false); + sky_shader.shader.set_variant_enabled(SKY_VERSION_QUARTER_RES_MULTIVIEW, false); + } + } + + // register our shader funds + material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); + material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_SKY, _create_sky_material_funcs); + + { + ShaderCompiler::DefaultIdentifierActions actions; + + actions.renames["COLOR"] = "color"; + actions.renames["ALPHA"] = "alpha"; + actions.renames["EYEDIR"] = "cube_normal"; + actions.renames["POSITION"] = "params.position_multiplier.xyz"; + actions.renames["SKY_COORDS"] = "panorama_coords"; + actions.renames["SCREEN_UV"] = "uv"; + actions.renames["FRAGCOORD"] = "gl_FragCoord"; + actions.renames["TIME"] = "params.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); + actions.renames["HALF_RES_COLOR"] = "half_res_color"; + actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color"; + actions.renames["RADIANCE"] = "radiance"; + actions.renames["FOG"] = "custom_fog"; + actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled"; + actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz"; + actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w"; + actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz"; + actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w"; + actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled"; + actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz"; + actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w"; + actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz"; + actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w"; + actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled"; + actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz"; + actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w"; + actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz"; + actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w"; + actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled"; + actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz"; + actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w"; + actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz"; + actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w"; + actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS"; + actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS"; + actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS"; + 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; + actions.texture_layout_set = 1; + actions.base_uniform_string = "material."; + actions.base_varying_index = 10; + + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; + actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; + actions.global_buffer_array_variable = "global_variables.data"; + + sky_shader.compiler.initialize(actions); + } + + { + // default material and shader for sky shader + sky_shader.default_shader = material_storage->shader_allocate(); + material_storage->shader_initialize(sky_shader.default_shader); + + material_storage->shader_set_code(sky_shader.default_shader, R"( +// Default sky shader. + +shader_type sky; + +void sky() { + COLOR = vec3(0.0); +} +)"); + + sky_shader.default_material = material_storage->material_allocate(); + material_storage->material_initialize(sky_shader.default_material); + + material_storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader); + + SkyMaterialData *md = static_cast(material_storage->material_get_data(sky_shader.default_material, RendererRD::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 uniforms; + + { + Vector ids; + ids.resize(12); + RID *ids_ptr = ids.ptrw(); + ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + + RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 0, ids); + + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.append_id(RendererRD::MaterialStorage::get_singleton()->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.append_id(sky_scene_state.uniform_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.append_id(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 uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID vfog = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE); + u.append_id(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 = material_storage->shader_allocate(); + material_storage->shader_initialize(sky_scene_state.fog_shader); + + material_storage->shader_set_code(sky_scene_state.fog_shader, R"( +// Default clear color sky shader. + +shader_type sky; + +uniform vec4 clear_color; + +void sky() { + COLOR = clear_color.rgb; +} +)"); + sky_scene_state.fog_material = material_storage->material_allocate(); + material_storage->material_initialize(sky_scene_state.fog_material); + + material_storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader); + + Vector uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1; + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; + u.append_id(texture_storage->texture_rd_get_default(RendererRD::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); + } + + { //create index array for copy shaders + Vector pv; + pv.resize(6 * 4); + { + uint8_t *w = pv.ptrw(); + int *p32 = (int *)w; + p32[0] = 0; + p32[1] = 1; + p32[2] = 2; + p32[3] = 0; + p32[4] = 2; + p32[5] = 3; + } + index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); + index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6); + } +} + +void SkyRD::set_texture_format(RD::DataFormat p_texture_format) { + texture_format = p_texture_format; +} + +SkyRD::~SkyRD() { + // cleanup anything created in init... + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + + SkyMaterialData *md = static_cast(material_storage->material_get_data(sky_shader.default_material, RendererRD::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); + material_storage->shader_free(sky_shader.default_shader); + material_storage->material_free(sky_shader.default_material); + material_storage->shader_free(sky_scene_state.fog_shader); + material_storage->material_free(sky_scene_state.fog_material); + + if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) { + RD::get_singleton()->free(sky_scene_state.uniform_set); + } + + if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.default_fog_uniform_set)) { + RD::get_singleton()->free(sky_scene_state.default_fog_uniform_set); + } + + if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_only_texture_uniform_set)) { + RD::get_singleton()->free(sky_scene_state.fog_only_texture_uniform_set); + } + + RD::get_singleton()->free(index_buffer); //array gets freed as dependency +} + +void SkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const PagedArray &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + ERR_FAIL_COND(!p_env); + + SkyMaterialData *material = nullptr; + Sky *sky = get_sky(p_env->sky); + + RID sky_material; + + SkyShaderData *shader_data = nullptr; + + if (sky) { + sky_material = sky_get_material(p_env->sky); + + if (sky_material.is_valid()) { + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + sky_material = sky_shader.default_material; + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + } + + ERR_FAIL_COND(!material); + + shader_data = material->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(); + } + invalidate_sky(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(); + } + invalidate_sky(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()) { + invalidate_sky(sky); + update_dirty_skys(); + } + + if (shader_data->uses_time && p_scene_render->time - sky->prev_time > 0.00001) { + sky->prev_time = p_scene_render->time; + sky->reflection.dirty = true; + RenderingServerDefault::redraw_request(); + } + + 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 (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) { + sky->prev_position = p_transform.origin; + sky->reflection.dirty = true; + } + + if (shader_data->uses_light) { + sky_scene_state.ubo.directional_light_count = 0; + // Run through the list of lights in the scene and pick out the Directional Lights. + // This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called + // after the depth prepass, but this runs before the depth prepass + for (int i = 0; i < (int)p_lights.size(); i++) { + RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_lights[i]); + if (!li) { + continue; + } + RID base = li->light; + + ERR_CONTINUE(base.is_null()); + + RS::LightType type = light_storage->light_get_type(base); + if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) { + SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count]; + Transform3D light_transform = li->transform; + 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; + + float sign = light_storage->light_is_negative(base) ? -1 : 1; + sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY); + + Color linear_col = light_storage->light_get_color(base).srgb_to_linear(); + sky_light_data.color[0] = linear_col.r; + sky_light_data.color[1] = linear_col.g; + sky_light_data.color[2] = linear_col.b; + + sky_light_data.enabled = true; + + float angular_diameter = light_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; + } + sky_light_data.size = angular_diameter; + sky_scene_state.ubo.directional_light_count++; + if (sky_scene_state.ubo.directional_light_count >= sky_scene_state.max_directional_lights) { + break; + } + } + } + // Check whether the directional_light_buffer changes + bool light_data_dirty = false; + + // Light buffer is dirty if we have fewer or more lights + // If we have fewer lights, make sure that old lights are disabled + 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); + + 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; + } + } + } + + //setup fog variables + sky_scene_state.ubo.volumetric_fog_enabled = false; + if (p_render_buffers.is_valid()) { + if (p_scene_render->render_buffers_has_volumetric_fog(p_render_buffers)) { + sky_scene_state.ubo.volumetric_fog_enabled = true; + + float fog_end = p_scene_render->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; + } + + float fog_detail_spread = p_scene_render->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.fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers); + } + } + + sky_scene_state.ubo.z_far = p_projection.get_z_far(); + sky_scene_state.ubo.fog_enabled = p_env->fog_enabled; + sky_scene_state.ubo.fog_density = p_env->fog_density; + sky_scene_state.ubo.fog_aerial_perspective = p_env->fog_aerial_perspective; + Color fog_color = p_env->fog_light_color.srgb_to_linear(); + float fog_energy = p_env->fog_light_energy; + 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 = p_env->fog_sun_scatter; + + RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo); +} + +void SkyRD::update(RendererSceneEnvironmentRD *p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) { + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + ERR_FAIL_COND(!p_env); + + Sky *sky = get_sky(p_env->sky); + ERR_FAIL_COND(!sky); + + RID sky_material = sky_get_material(p_env->sky); + + SkyMaterialData *material = nullptr; + + if (sky_material.is_valid()) { + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + sky_material = sky_shader.default_material; + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + } + + ERR_FAIL_COND(!material); + + SkyShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + float multiplier = p_env->bg_energy; + + bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY; + RS::SkyMode sky_mode = sky->mode; + + if (sky_mode == RS::SKY_MODE_AUTOMATIC) { + if (shader_data->uses_time || shader_data->uses_position) { + update_single_frame = true; + sky_mode = RS::SKY_MODE_REALTIME; + } else if (shader_data->uses_light || shader_data->ubo_size > 0) { + update_single_frame = false; + sky_mode = RS::SKY_MODE_INCREMENTAL; + } else { + update_single_frame = true; + sky_mode = RS::SKY_MODE_QUALITY; + } + } + + if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) { + // On the first frame after creating sky, rebuild in single frame + update_single_frame = true; + sky_mode = RS::SKY_MODE_QUALITY; + } + + int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size(); + + // Update radiance cubemap + if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) { + static const Vector3 view_normals[6] = { + Vector3(+1, 0, 0), + Vector3(-1, 0, 0), + Vector3(0, +1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1) + }; + static const Vector3 view_up[6] = { + Vector3(0, -1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1), + Vector3(0, -1, 0), + Vector3(0, -1, 0) + }; + + Projection cm; + cm.set_perspective(90, 1, 0.01, 10.0); + Projection correction; + correction.set_depth_correction(true); + cm = correction * cm; + + if (shader_data->uses_quarter_res) { + RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter Res Cubemap"); + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; + + Vector clear_colors; + clear_colors.push_back(Color(0.0, 0.0, 0.0)); + RD::DrawListID cubemap_draw_list; + + for (int i = 0; i < 6; i++) { + Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd); + + 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); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier); + RD::get_singleton()->draw_list_end(); + } + RD::get_singleton()->draw_command_end_label(); + } + + if (shader_data->uses_half_res) { + RD::get_singleton()->draw_command_begin_label("Render Sky to Half Res Cubemap"); + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; + + Vector clear_colors; + clear_colors.push_back(Color(0.0, 0.0, 0.0)); + RD::DrawListID cubemap_draw_list; + + for (int i = 0; i < 6; i++) { + Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd); + + 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); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier); + RD::get_singleton()->draw_list_end(); + } + RD::get_singleton()->draw_command_end_label(); + } + + RD::DrawListID cubemap_draw_list; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; + + RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap"); + for (int i = 0; i < 6; i++) { + Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd); + + 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); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier); + RD::get_singleton()->draw_list_end(); + } + RD::get_singleton()->draw_command_end_label(); + + if (sky_mode == RS::SKY_MODE_REALTIME) { + sky->reflection.create_reflection_fast_filter(sky_use_cubemap_array); + if (sky_use_cubemap_array) { + sky->reflection.update_reflection_mipmaps(0, sky->reflection.layers.size()); + } + } else { + if (update_single_frame) { + for (int i = 1; i < max_processing_layer; i++) { + sky->reflection.create_reflection_importance_sample(sky_use_cubemap_array, 10, i, sky_ggx_samples_quality); + } + if (sky_use_cubemap_array) { + sky->reflection.update_reflection_mipmaps(0, sky->reflection.layers.size()); + } + } else { + if (sky_use_cubemap_array) { + // Multi-Frame so just update the first array level + sky->reflection.update_reflection_mipmaps(0, 1); + } + } + sky->processing_layer = 1; + } + + sky->reflection.dirty = false; + + } else { + if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) { + sky->reflection.create_reflection_importance_sample(sky_use_cubemap_array, 10, sky->processing_layer, sky_ggx_samples_quality); + + if (sky_use_cubemap_array) { + sky->reflection.update_reflection_mipmaps(sky->processing_layer, sky->processing_layer + 1); + } + + sky->processing_layer++; + } + } +} + +void SkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time) { + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + ERR_FAIL_COND(!p_env); + + ERR_FAIL_COND(p_view_count == 0); + ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); + + Sky *sky = get_sky(p_env->sky); + + SkyMaterialData *material = nullptr; + RID sky_material; + + RS::EnvironmentBG background = p_env->background; + + if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { + ERR_FAIL_COND(!sky); + sky_material = sky_get_material(p_env->sky); + + if (sky_material.is_valid()) { + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + sky_material = sky_shader.default_material; + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + } + } + + if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { + sky_material = sky_scene_state.fog_material; + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + } + + ERR_FAIL_COND(!material); + + SkyShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + Basis sky_transform = p_env->sky_orientation; + sky_transform.invert(); + + float multiplier = p_env->bg_energy; + float custom_fov = p_env->sky_custom_fov; + + // Camera + Projection camera; + uint32_t view_count = p_view_count; + const Projection *projections = p_projections; + + if (custom_fov) { + // With custom fov we don't support stereo... + float near_plane = p_projections[0].get_z_near(); + float far_plane = p_projections[0].get_z_far(); + float aspect = p_projections[0].get_aspect(); + + camera.set_perspective(custom_fov, aspect, near_plane, far_plane); + + view_count = 1; + projections = &camera; + } + + sky_transform = sky_transform * p_transform.basis; + + if (shader_data->uses_quarter_res) { + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES]; + + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd); + + Vector clear_colors; + 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); + _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0); + RD::get_singleton()->draw_list_end(); + } + + if (shader_data->uses_half_res) { + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES]; + + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd); + + Vector clear_colors; + 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); + _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0); + RD::get_singleton()->draw_list_end(); + } + + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND]; + + RID texture_uniform_set; + if (sky) { + texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd); + } 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); + _render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0); + RD::get_singleton()->draw_list_end(); +} + +void SkyRD::update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) { + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + ERR_FAIL_COND(!p_env); + + ERR_FAIL_COND(p_view_count == 0); + ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); + + Sky *sky = get_sky(p_env->sky); + ERR_FAIL_COND(!sky); + + SkyMaterialData *material = nullptr; + RID sky_material; + + sky_material = sky_get_material(p_env->sky); + + if (sky_material.is_valid()) { + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + sky_material = sky_shader.default_material; + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + } + + ERR_FAIL_COND(!material); + + SkyShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + Basis sky_transform = p_env->sky_orientation; + sky_transform.invert(); + + float multiplier = p_env->bg_energy; + float custom_fov = p_env->sky_custom_fov; + + // Camera + Projection camera; + uint32_t view_count = p_view_count; + const Projection *projections = p_projections; + + if (custom_fov) { + // With custom fov we don't support stereo... + float near_plane = p_projections[0].get_z_near(); + float far_plane = p_projections[0].get_z_far(); + float aspect = p_projections[0].get_aspect(); + + camera.set_perspective(custom_fov, aspect, near_plane, far_plane); + + view_count = 1; + projections = &camera; + } + + sky_transform = p_transform.basis * sky_transform; + + if (shader_data->uses_quarter_res) { + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES]; + + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd); + + Vector clear_colors; + 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); + _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier); + RD::get_singleton()->draw_list_end(); + } + + if (shader_data->uses_half_res) { + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES]; + + RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd); + + Vector clear_colors; + 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); + _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier); + RD::get_singleton()->draw_list_end(); + } +} + +void SkyRD::draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) { + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + ERR_FAIL_COND(!p_env); + + ERR_FAIL_COND(p_view_count == 0); + ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); + + Sky *sky = get_sky(p_env->sky); + + SkyMaterialData *material = nullptr; + RID sky_material; + + RS::EnvironmentBG background = p_env->background; + + if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { + ERR_FAIL_COND(!sky); + sky_material = sky_get_material(p_env->sky); + + if (sky_material.is_valid()) { + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + sky_material = sky_shader.default_material; + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + } + } + + if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { + sky_material = sky_scene_state.fog_material; + material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); + } + + ERR_FAIL_COND(!material); + + SkyShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + Basis sky_transform = p_env->sky_orientation; + sky_transform.invert(); + + float multiplier = p_env->bg_energy; + float custom_fov = p_env->sky_custom_fov; + + // Camera + Projection camera; + uint32_t view_count = p_view_count; + const Projection *projections = p_projections; + + if (custom_fov) { + // With custom fov we don't support stereo... + float near_plane = p_projections[0].get_z_near(); + float far_plane = p_projections[0].get_z_far(); + float aspect = p_projections[0].get_aspect(); + + camera.set_perspective(custom_fov, aspect, near_plane, far_plane); + + view_count = 1; + projections = &camera; + } + + sky_transform = p_transform.basis * sky_transform; + + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND]; + + RID texture_uniform_set; + if (sky) { + texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd); + } else { + texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set; + } + + _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier); +} + +void SkyRD::invalidate_sky(Sky *p_sky) { + if (!p_sky->dirty) { + p_sky->dirty = true; + p_sky->dirty_list = dirty_sky_list; + dirty_sky_list = p_sky; + } +} + +void SkyRD::update_dirty_skys() { + Sky *sky = dirty_sky_list; + + while (sky) { + bool texture_set_dirty = false; + //update sky configuration if texture is missing + + if (sky->radiance.is_null()) { + int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; + + uint32_t w = sky->radiance_size, h = sky->radiance_size; + int layers = roughness_layers; + if (sky->mode == RS::SKY_MODE_REALTIME) { + layers = 8; + if (roughness_layers != 8) { + WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections"); + } + } + + if (sky_use_cubemap_array) { + //array (higher quality, 6 times more memory) + RD::TextureFormat tf; + tf.array_layers = layers * 6; + tf.format = texture_format; + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.mipmaps = mipmaps; + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + + sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); + + } else { + //regular cubemap, lower quality (aliasing, less memory) + RD::TextureFormat tf; + tf.array_layers = 6; + tf.format = texture_format; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; + tf.mipmaps = MIN(mipmaps, layers); + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + + sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); + } + texture_set_dirty = true; + } + + // 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 = texture_format; + tformat.width = sky->screen_size.x / 2; + tformat.height = sky->screen_size.y / 2; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tformat.texture_type = RD::TEXTURE_TYPE_2D; + + sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + Vector texs; + texs.push_back(sky->half_res_pass); + sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); + texture_set_dirty = true; + } + + if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { + RD::TextureFormat tformat; + tformat.format = texture_format; + tformat.width = sky->screen_size.x / 4; + tformat.height = sky->screen_size.y / 4; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tformat.texture_type = RD::TEXTURE_TYPE_2D; + + sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + Vector texs; + texs.push_back(sky->quarter_res_pass); + sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); + texture_set_dirty = true; + } + + if (texture_set_dirty) { + for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) { + if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) { + RD::get_singleton()->free(sky->texture_uniform_sets[i]); + sky->texture_uniform_sets[i] = RID(); + } + } + } + + sky->reflection.dirty = true; + sky->processing_layer = 0; + + Sky *next = sky->dirty_list; + sky->dirty_list = nullptr; + sky->dirty = false; + sky = next; + } + + dirty_sky_list = nullptr; +} + +RID SkyRD::sky_get_material(RID p_sky) const { + Sky *sky = get_sky(p_sky); + ERR_FAIL_COND_V(!sky, RID()); + + return sky->material; +} + +RID SkyRD::allocate_sky_rid() { + return sky_owner.allocate_rid(); +} + +void SkyRD::initialize_sky_rid(RID p_rid) { + sky_owner.initialize_rid(p_rid, Sky()); +} + +SkyRD::Sky *SkyRD::get_sky(RID p_sky) const { + return sky_owner.get_or_null(p_sky); +} + +void SkyRD::free_sky(RID p_sky) { + Sky *sky = get_sky(p_sky); + ERR_FAIL_COND(!sky); + + sky->free(); + sky_owner.free(p_sky); +} + +void SkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { + Sky *sky = get_sky(p_sky); + ERR_FAIL_COND(!sky); + + if (sky->set_radiance_size(p_radiance_size)) { + invalidate_sky(sky); + } +} + +void SkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { + Sky *sky = get_sky(p_sky); + ERR_FAIL_COND(!sky); + + if (sky->set_mode(p_mode)) { + invalidate_sky(sky); + } +} + +void SkyRD::sky_set_material(RID p_sky, RID p_material) { + Sky *sky = get_sky(p_sky); + ERR_FAIL_COND(!sky); + + if (sky->set_material(p_material)) { + invalidate_sky(sky); + } +} + +Ref SkyRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { + Sky *sky = get_sky(p_sky); + ERR_FAIL_COND_V(!sky, Ref()); + + update_dirty_skys(); + + return sky->bake_panorama(p_energy, p_bake_irradiance ? roughness_layers : 0, p_size); +} + +RID SkyRD::sky_get_radiance_texture_rd(RID p_sky) const { + Sky *sky = get_sky(p_sky); + ERR_FAIL_COND_V(!sky, RID()); + + return sky->radiance; +} diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h new file mode 100644 index 0000000000..c3962f20b7 --- /dev/null +++ b/servers/rendering/renderer_rd/environment/sky.h @@ -0,0 +1,325 @@ +/*************************************************************************/ +/* sky.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SKY_RD_H +#define SKY_RD_H + +#include "core/templates/rid_owner.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" +#include "servers/rendering/renderer_rd/shaders/environment/sky.glsl.gen.h" +#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/rendering_device.h" +#include "servers/rendering/shader_compiler.h" + +// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound +class RendererSceneRenderRD; + +namespace RendererRD { + +class SkyRD { +public: + enum SkySet { + SKY_SET_UNIFORMS, + SKY_SET_MATERIAL, + SKY_SET_TEXTURES, + SKY_SET_FOG, + SKY_SET_MAX + }; + + // Skys need less info from Directional Lights than the normal shaders + struct SkyDirectionalLightData { + float direction[3]; + float energy; + float color[3]; + float size; + uint32_t enabled; + uint32_t pad[3]; + }; + +private: + RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + + RID index_buffer; + RID index_array; + + enum SkyTextureSetVersion { + SKY_TEXTURE_SET_BACKGROUND, + SKY_TEXTURE_SET_HALF_RES, + SKY_TEXTURE_SET_QUARTER_RES, + SKY_TEXTURE_SET_CUBEMAP, + SKY_TEXTURE_SET_CUBEMAP_HALF_RES, + SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, + SKY_TEXTURE_SET_MAX + }; + + enum SkyVersion { + SKY_VERSION_BACKGROUND, + SKY_VERSION_HALF_RES, + SKY_VERSION_QUARTER_RES, + SKY_VERSION_CUBEMAP, + SKY_VERSION_CUBEMAP_HALF_RES, + SKY_VERSION_CUBEMAP_QUARTER_RES, + + SKY_VERSION_BACKGROUND_MULTIVIEW, + SKY_VERSION_HALF_RES_MULTIVIEW, + SKY_VERSION_QUARTER_RES_MULTIVIEW, + + SKY_VERSION_MAX + }; + + struct SkyPushConstant { + float orientation[12]; // 48 - 48 + float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 80 + float position[3]; // 12 - 92 + float multiplier; // 4 - 96 + float time; // 4 - 100 + float luminance_multiplier; // 4 - 104 + float pad[2]; // 8 - 112 // Using pad to align on 16 bytes + // 128 is the max size of a push constant. We can replace "pad" but we can't add any more. + }; + + struct SkyShaderData : public RendererRD::ShaderData { + bool valid = false; + RID version; + + PipelineCacheRD pipelines[SKY_VERSION_MAX]; + HashMap uniforms; + Vector texture_uniforms; + + Vector ubo_offsets; + uint32_t ubo_size = 0; + + String path; + String code; + HashMap> default_texture_params; + + bool uses_time = false; + bool uses_position = false; + bool uses_half_res = false; + bool uses_quarter_res = false; + bool uses_light = false; + + virtual void set_code(const String &p_Code); + virtual void set_path_hint(const String &p_hint); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); + virtual void get_param_list(List *p_param_list) const; + virtual void get_instance_param_list(List *p_param_list) const; + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + + SkyShaderData() {} + virtual ~SkyShaderData(); + }; + + void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier); + +public: + struct SkySceneState { + struct UBO { + uint32_t volumetric_fog_enabled; + float volumetric_fog_inv_length; + float volumetric_fog_detail_spread; + + float fog_aerial_perspective; + + 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 = nullptr; + SkyDirectionalLightData *last_frame_directional_lights = nullptr; + uint32_t max_directional_lights; + uint32_t last_frame_directional_light_count; + RID directional_light_buffer; + 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 ReflectionData { + struct Layer { + struct Mipmap { + RID framebuffers[6]; + RID views[6]; + Size2i size; + }; + Vector mipmaps; //per-face view + Vector views; // per-cubemap view + }; + + struct DownsampleLayer { + struct Mipmap { + RID view; + Size2i size; + + // for mobile only + RID views[6]; + RID framebuffers[6]; + }; + Vector mipmaps; + }; + + RID radiance_base_cubemap; //cubemap for first layer, first cubemap + RID downsampled_radiance_cubemap; + DownsampleLayer downsampled_layer; + RID coefficient_buffer; + + bool dirty = true; + + Vector layers; + + void clear_reflection_data(); + void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format); + void create_reflection_fast_filter(bool p_use_arrays); + void create_reflection_importance_sample(bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality); + void update_reflection_mipmaps(int p_start, int p_end); + }; + + /* Sky shader */ + + struct SkyShader { + SkyShaderRD shader; + ShaderCompiler compiler; + + RID default_shader; + RID default_material; + RID default_shader_rd; + } sky_shader; + + struct SkyMaterialData : public RendererRD::MaterialData { + SkyShaderData *shader_data = nullptr; + RID uniform_set; + bool uniform_set_updated; + + virtual void set_render_priority(int p_priority) {} + virtual void set_next_pass(RID p_pass) {} + virtual bool update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~SkyMaterialData(); + }; + + struct Sky { + RID radiance; + RID half_res_pass; + RID half_res_framebuffer; + RID quarter_res_pass; + RID quarter_res_framebuffer; + Size2i screen_size; + + RID texture_uniform_sets[SKY_TEXTURE_SET_MAX]; + RID uniform_set; + + RID material; + RID uniform_buffer; + + int radiance_size = 256; + + RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC; + + ReflectionData reflection; + bool dirty = false; + int processing_layer = 0; + Sky *dirty_list = nullptr; + + //State to track when radiance cubemap needs updating + SkyMaterialData *prev_material = nullptr; + Vector3 prev_position; + float prev_time; + + void free(); + + RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd); + bool set_radiance_size(int p_radiance_size); + bool set_mode(RS::SkyMode p_mode); + bool set_material(RID p_material); + Ref bake_panorama(float p_energy, int p_roughness_layers, const Size2i &p_size); + }; + + uint32_t sky_ggx_samples_quality; + bool sky_use_cubemap_array; + Sky *dirty_sky_list = nullptr; + mutable RID_Owner sky_owner; + int roughness_layers; + + RendererRD::ShaderData *_create_sky_shader_func(); + static RendererRD::ShaderData *_create_sky_shader_funcs(); + + RendererRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); + static RendererRD::MaterialData *_create_sky_material_funcs(RendererRD::ShaderData *p_shader); + + SkyRD(); + void init(); + void set_texture_format(RD::DataFormat p_texture_format); + ~SkyRD(); + + void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const PagedArray &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); + void update(RendererSceneEnvironmentRD *p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); + void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time); // only called by clustered renderer + void update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); + void draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); + + void invalidate_sky(Sky *p_sky); + void update_dirty_skys(); + + RID sky_get_material(RID p_sky) const; + + RID allocate_sky_rid(); + void initialize_sky_rid(RID p_rid); + Sky *get_sky(RID p_sky) const; + void free_sky(RID p_sky); + void sky_set_radiance_size(RID p_sky, int p_radiance_size); + void sky_set_mode(RID p_sky, RS::SkyMode p_mode); + void sky_set_material(RID p_sky, RID p_material); + Ref sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size); + + RID sky_get_radiance_texture_rd(RID p_sky) const; +}; + +} // namespace RendererRD + +#endif // SKY_RD_H diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 937a0cec70..3161f03192 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -558,29 +558,28 @@ Ref RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba //////////////////////////////////////////////////////////// RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) { - FogVolumeInstance fvi; - fvi.volume = p_fog_volume; - return fog_volume_instance_owner.make_rid(fvi); + return RendererRD::Fog::get_singleton()->fog_volume_instance_create(p_fog_volume); } + void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) { - FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); ERR_FAIL_COND(!fvi); fvi->transform = p_transform; } void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) { - FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); ERR_FAIL_COND(!fvi); fvi->active = p_active; } RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const { - FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); ERR_FAIL_COND_V(!fvi, RID()); return fvi->volume; } Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const { - FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance); ERR_FAIL_COND_V(!fvi, Vector3()); return fvi->transform.get_origin(); @@ -3689,242 +3688,7 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray &p_decals, const //////////////////////////////////////////////////////////////////////////////// // FOG SHADER -void RendererSceneRenderRD::FogShaderData::set_path_hint(const String &p_path) { - path = p_path; -} - -void RendererSceneRenderRD::FogShaderData::set_code(const String &p_code) { - //compile - - code = p_code; - valid = false; - ubo_size = 0; - uniforms.clear(); - - if (code.is_empty()) { - return; //just invalid, but no error - } - - ShaderCompiler::GeneratedCode gen_code; - ShaderCompiler::IdentifierActions actions; - actions.entry_point_stages["fog"] = ShaderCompiler::STAGE_COMPUTE; - - uses_time = false; - - actions.usage_flag_pointers["TIME"] = &uses_time; - - actions.uniforms = &uniforms; - - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - - Error err = scene_singleton->volumetric_fog.compiler.compile(RS::SHADER_FOG, code, &actions, path, gen_code); - ERR_FAIL_COND_MSG(err != OK, "Fog shader compilation failed."); - - if (version.is_null()) { - version = scene_singleton->volumetric_fog.shader.version_create(); - } - - scene_singleton->volumetric_fog.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_COMPUTE], gen_code.defines); - ERR_FAIL_COND(!scene_singleton->volumetric_fog.shader.version_is_valid(version)); - - ubo_size = gen_code.uniform_total_size; - ubo_offsets = gen_code.uniform_offsets; - texture_uniforms = gen_code.texture_uniforms; - - pipeline = RD::get_singleton()->compute_pipeline_create(scene_singleton->volumetric_fog.shader.version_get_shader(version, 0)); - - valid = true; -} - -void RendererSceneRenderRD::FogShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { - if (!p_texture.is_valid()) { - if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { - default_texture_params[p_name].erase(p_index); - - if (default_texture_params[p_name].is_empty()) { - default_texture_params.erase(p_name); - } - } - } else { - if (!default_texture_params.has(p_name)) { - default_texture_params[p_name] = HashMap(); - } - default_texture_params[p_name][p_index] = p_texture; - } -} - -void RendererSceneRenderRD::FogShaderData::get_param_list(List *p_param_list) const { - RBMap order; - - for (const KeyValue &E : uniforms) { - if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { - continue; - } - - if (E.value.texture_order >= 0) { - order[E.value.texture_order + 100000] = E.key; - } else { - order[E.value.order] = E.key; - } - } - - for (const KeyValue &E : order) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); - pi.name = E.value; - p_param_list->push_back(pi); - } -} - -void RendererSceneRenderRD::FogShaderData::get_instance_param_list(List *p_param_list) const { - for (const KeyValue &E : uniforms) { - if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { - continue; - } - - RendererMaterialStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E.value); - p.info.name = E.key; //supply name - p.index = E.value.instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); - p_param_list->push_back(p); - } -} - -bool RendererSceneRenderRD::FogShaderData::is_param_texture(const StringName &p_param) const { - if (!uniforms.has(p_param)) { - return false; - } - - return uniforms[p_param].texture_order >= 0; -} - -bool RendererSceneRenderRD::FogShaderData::is_animated() const { - return false; -} - -bool RendererSceneRenderRD::FogShaderData::casts_shadows() const { - return false; -} - -Variant RendererSceneRenderRD::FogShaderData::get_default_parameter(const StringName &p_parameter) const { - if (uniforms.has(p_parameter)) { - ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; - Vector default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); - } - return Variant(); -} - -RS::ShaderNativeSourceCode RendererSceneRenderRD::FogShaderData::get_native_source_code() const { - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - - return scene_singleton->volumetric_fog.shader.version_get_native_source_code(version); -} - -RendererSceneRenderRD::FogShaderData::~FogShaderData() { - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - ERR_FAIL_COND(!scene_singleton); - //pipeline variants will clear themselves if shader is gone - if (version.is_valid()) { - scene_singleton->volumetric_fog.shader.version_free(version); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Fog material - -bool RendererSceneRenderRD::FogMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - - uniform_set_updated = true; - - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL); -} - -RendererSceneRenderRD::FogMaterialData::~FogMaterialData() { - free_parameters_uniform_set(uniform_set); -} - -RendererRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_func() { - FogShaderData *shader_data = memnew(FogShaderData); - return shader_data; -} - -RendererRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_funcs() { - return static_cast(RendererSceneRenderRD::singleton)->_create_fog_shader_func(); -}; - -RendererRD::MaterialData *RendererSceneRenderRD::_create_fog_material_func(FogShaderData *p_shader) { - FogMaterialData *material_data = memnew(FogMaterialData); - material_data->shader_data = p_shader; - //update will happen later anyway so do nothing. - return material_data; -} - -RendererRD::MaterialData *RendererSceneRenderRD::_create_fog_material_funcs(RendererRD::ShaderData *p_shader) { - return static_cast(RendererSceneRenderRD::singleton)->_create_fog_material_func(static_cast(p_shader)); -}; - -//////////////////////////////////////////////////////////////////////////////// -// Volumetric Fog - -void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { - ERR_FAIL_COND(!rb->volumetric_fog); - - RD::get_singleton()->free(rb->volumetric_fog->prev_light_density_map); - RD::get_singleton()->free(rb->volumetric_fog->light_density_map); - RD::get_singleton()->free(rb->volumetric_fog->fog_map); - RD::get_singleton()->free(rb->volumetric_fog->density_map); - RD::get_singleton()->free(rb->volumetric_fog->light_map); - RD::get_singleton()->free(rb->volumetric_fog->emissive_map); - - if (rb->volumetric_fog->fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) { - RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set); - } - if (rb->volumetric_fog->process_uniform_set_density.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set_density)) { - RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set_density); - } - if (rb->volumetric_fog->process_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set)) { - RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set); - } - if (rb->volumetric_fog->process_uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set2)) { - RD::get_singleton()->free(rb->volumetric_fog->process_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; -} - -Vector3i RendererSceneRenderRD::_point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform) { - Vector3 view_position = p_cam_transform.affine_inverse().xform(p_point); - view_position.z = MIN(view_position.z, -0.01); // Clamp to the front of camera - Vector3 fog_position = Vector3(0, 0, 0); - - view_position.y = -view_position.y; - fog_position.z = -view_position.z / fog_end; - fog_position.x = (view_position.x / (2 * (fog_near_size.x * (1.0 - fog_position.z) + fog_far_size.x * fog_position.z))) + 0.5; - fog_position.y = (view_position.y / (2 * (fog_near_size.y * (1.0 - fog_position.z) + fog_far_size.y * fog_position.z))) + 0.5; - fog_position.z = Math::pow(float(fog_position.z), float(1.0 / volumetric_fog_detail_spread)); - fog_position = fog_position * fog_size - Vector3(0.5, 0.5, 0.5); - - fog_position.x = CLAMP(fog_position.x, 0.0, fog_size.x); - fog_position.y = CLAMP(fog_position.y, 0.0, fog_size.y); - fog_position.z = CLAMP(fog_position.z, 0.0, fog_size.z); - - return Vector3i(fog_position); -} - void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes) { - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); @@ -3937,7 +3701,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e 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); + memdelete(rb->volumetric_fog); + rb->volumetric_fog = nullptr; } } @@ -3946,684 +3711,38 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e return; } - RENDER_TIMESTAMP("> Volumetric Fog"); - RD::get_singleton()->draw_command_begin_label("Volumetric Fog"); - 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.texture_type = RD::TEXTURE_TYPE_3D; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - - rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_density_map, "Fog light-density map"); - - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - - rb->volumetric_fog->prev_light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->prev_light_density_map, "Fog previous light-density map"); - RD::get_singleton()->texture_clear(rb->volumetric_fog->prev_light_density_map, Color(0, 0, 0, 0), 0, 1, 0, 1); - - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->fog_map, "Fog map"); - -#if defined(MACOS_ENABLED) || defined(IOS_ENABLED) - Vector dm; - dm.resize(target_width * target_height * volumetric_fog_depth * 4); - dm.fill(0); - - rb->volumetric_fog->density_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map"); - rb->volumetric_fog->light_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map"); - rb->volumetric_fog->emissive_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map"); -#else - tf.format = RD::DATA_FORMAT_R32_UINT; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - rb->volumetric_fog->density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map"); - RD::get_singleton()->texture_clear(rb->volumetric_fog->density_map, Color(0, 0, 0, 0), 0, 1, 0, 1); - rb->volumetric_fog->light_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map"); - RD::get_singleton()->texture_clear(rb->volumetric_fog->light_map, Color(0, 0, 0, 0), 0, 1, 0, 1); - rb->volumetric_fog->emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map"); - RD::get_singleton()->texture_clear(rb->volumetric_fog->emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1); -#endif - - Vector uniforms; - { - RD::Uniform u; - u.binding = 0; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.append_id(rb->volumetric_fog->fog_map); - uniforms.push_back(u); - } - - rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky.sky_shader.default_shader_rd, RendererSceneSkyRD::SKY_SET_FOG); - } - - if (p_fog_volumes.size() > 0) { - RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog Volumes"); - - RENDER_TIMESTAMP("Render FogVolumes"); - - VolumetricFogShader::VolumeUBO params; - - 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(); - } - - params.fog_frustum_size_begin[0] = fog_near_size.x; - params.fog_frustum_size_begin[1] = fog_near_size.y; - - params.fog_frustum_size_end[0] = fog_far_size.x; - params.fog_frustum_size_end[1] = fog_far_size.y; - - params.fog_frustum_end = fog_end; - params.z_near = z_near; - params.z_far = z_far; - params.time = time; - - params.fog_volume_size[0] = rb->volumetric_fog->width; - params.fog_volume_size[1] = rb->volumetric_fog->height; - params.fog_volume_size[2] = rb->volumetric_fog->depth; - - params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection; - params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES; - params.detail_spread = env->volumetric_fog_detail_spread; - params.temporal_blend = env->volumetric_fog_temporal_reprojection_amount; - - Transform3D to_prev_cam_view = p_prev_cam_inv_transform * p_cam_transform; - RendererRD::MaterialStorage::store_transform(to_prev_cam_view, params.to_prev_view); - RendererRD::MaterialStorage::store_transform(p_cam_transform, params.transform); - - RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); - - if (rb->volumetric_fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) { - Vector uniforms; - - { - RD::Uniform u; -#if defined(MACOS_ENABLED) || defined(IOS_ENABLED) - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -#else - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -#endif - u.binding = 1; - u.append_id(rb->volumetric_fog->emissive_map); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 2; - u.append_id(volumetric_fog.volume_ubo); - uniforms.push_back(u); - } - - { - RD::Uniform u; -#if defined(MACOS_ENABLED) || defined(IOS_ENABLED) - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -#else - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -#endif - u.binding = 3; - u.append_id(rb->volumetric_fog->density_map); - uniforms.push_back(u); - } - - { - RD::Uniform u; -#if defined(MACOS_ENABLED) || defined(IOS_ENABLED) - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -#else - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -#endif - u.binding = 4; - u.append_id(rb->volumetric_fog->light_map); - uniforms.push_back(u); - } - - rb->volumetric_fog->fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS); - } - - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - bool any_uses_time = false; - - for (int i = 0; i < (int)p_fog_volumes.size(); i++) { - FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]); - ERR_FAIL_COND(!fog_volume_instance); - RID fog_volume = fog_volume_instance->volume; - - RID fog_material = RendererRD::Fog::get_singleton()->fog_volume_get_material(fog_volume); - - FogMaterialData *material = nullptr; - - if (fog_material.is_valid()) { - material = static_cast(material_storage->material_get_data(fog_material, RendererRD::SHADER_TYPE_FOG)); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - fog_material = volumetric_fog.default_material; - material = static_cast(material_storage->material_get_data(fog_material, RendererRD::SHADER_TYPE_FOG)); - } - - ERR_FAIL_COND(!material); - - FogShaderData *shader_data = material->shader_data; - - ERR_FAIL_COND(!shader_data); - - any_uses_time |= shader_data->uses_time; - - Vector3i min = Vector3i(); - Vector3i max = Vector3i(); - Vector3i kernel_size = Vector3i(); - - Vector3 position = fog_volume_instance->transform.get_origin(); - RS::FogVolumeShape volume_type = RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume); - Vector3 extents = RendererRD::Fog::get_singleton()->fog_volume_get_extents(fog_volume); - - if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) { - // Local fog volume. - Vector3i points[8]; - points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); - - min = Vector3i(int32_t(rb->volumetric_fog->width) - 1, int32_t(rb->volumetric_fog->height) - 1, int32_t(rb->volumetric_fog->depth) - 1); - max = Vector3i(1, 1, 1); - - for (int j = 0; j < 8; j++) { - min = Vector3i(MIN(min.x, points[j].x), MIN(min.y, points[j].y), MIN(min.z, points[j].z)); - max = Vector3i(MAX(max.x, points[j].x), MAX(max.y, points[j].y), MAX(max.z, points[j].z)); - } - - kernel_size = max - min; - } else { - // Volume type global runs on all cells - extents = Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); - min = Vector3i(0, 0, 0); - kernel_size = Vector3i(int32_t(rb->volumetric_fog->width), int32_t(rb->volumetric_fog->height), int32_t(rb->volumetric_fog->depth)); - } - - if (kernel_size.x == 0 || kernel_size.y == 0 || kernel_size.z == 0) { - continue; - } - - volumetric_fog.push_constant.position[0] = position.x; - volumetric_fog.push_constant.position[1] = position.y; - volumetric_fog.push_constant.position[2] = position.z; - volumetric_fog.push_constant.extents[0] = extents.x; - volumetric_fog.push_constant.extents[1] = extents.y; - volumetric_fog.push_constant.extents[2] = extents.z; - volumetric_fog.push_constant.corner[0] = min.x; - volumetric_fog.push_constant.corner[1] = min.y; - volumetric_fog.push_constant.corner[2] = min.z; - volumetric_fog.push_constant.shape = uint32_t(RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume)); - RendererRD::MaterialStorage::store_transform(fog_volume_instance->transform.affine_inverse(), volumetric_fog.push_constant.transform); - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline); - - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &volumetric_fog.push_constant, sizeof(VolumetricFogShader::FogPushConstant)); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, volumetric_fog.base_uniform_set, VolumetricFogShader::FogSet::FOG_SET_BASE); - if (material->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material->uniform_set)) { // Material may not have a uniform set. - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, material->uniform_set, VolumetricFogShader::FogSet::FOG_SET_MATERIAL); - } - - RD::get_singleton()->compute_list_dispatch_threads(compute_list, kernel_size.x, kernel_size.y, kernel_size.z); - } - if (any_uses_time || env->volumetric_fog_temporal_reprojection) { - RenderingServerDefault::redraw_request(); - } - - RD::get_singleton()->draw_command_end_label(); - - RD::get_singleton()->compute_list_end(); + rb->volumetric_fog = memnew(RendererRD::Fog::VolumetricFog(Vector3i(target_width, target_height, volumetric_fog_depth), sky.sky_shader.default_shader_rd)); } - if (rb->volumetric_fog->process_uniform_set_density.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set_density)) { - //re create uniform set if needed - Vector uniforms; - Vector copy_uniforms; - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1; - ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); - if (shadow_atlas == nullptr || shadow_atlas->depth.is_null()) { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK)); - } else { - u.append_id(shadow_atlas->depth); - } - - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; - if (directional_shadow.depth.is_valid()) { - u.append_id(directional_shadow.depth); - } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK)); - } - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 3; - u.append_id(get_omni_light_buffer()); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 4; - u.append_id(get_spot_light_buffer()); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 5; - u.append_id(get_directional_light_buffer()); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 6; - u.append_id(rb->cluster_builder->get_cluster_buffer()); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 7; - u.append_id(material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 8; - u.append_id(rb->volumetric_fog->light_density_map); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 9; - u.append_id(rb->volumetric_fog->fog_map); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 9; - u.append_id(rb->volumetric_fog->prev_light_density_map); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 10; - u.append_id(shadow_sampler); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 11; - u.append_id(render_buffers_get_voxel_gi_buffer(p_render_buffers)); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 12; - for (int i = 0; i < RendererRD::GI::MAX_VOXEL_GI_INSTANCES; i++) { - u.append_id(rb->rbgi.voxel_gi_textures[i]); - } - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 13; - u.append_id(material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 14; - u.append_id(volumetric_fog.params_ubo); - uniforms.push_back(u); - copy_uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 15; - u.append_id(rb->volumetric_fog->prev_light_density_map); - uniforms.push_back(u); - } - { - RD::Uniform u; -#if defined(MACOS_ENABLED) || defined(IOS_ENABLED) - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -#else - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -#endif - u.binding = 16; - u.append_id(rb->volumetric_fog->density_map); - uniforms.push_back(u); - } - { - RD::Uniform u; -#if defined(MACOS_ENABLED) || defined(IOS_ENABLED) - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -#else - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -#endif - u.binding = 17; - u.append_id(rb->volumetric_fog->light_map); - uniforms.push_back(u); - } - - { - RD::Uniform u; -#if defined(MACOS_ENABLED) || defined(IOS_ENABLED) - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -#else - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -#endif - u.binding = 18; - u.append_id(rb->volumetric_fog->emissive_map); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 19; - RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); - RID sky_texture = env->sky.is_valid() ? sky.sky_get_radiance_texture_rd(env->sky) : RID(); - u.append_id(sky_texture.is_valid() ? sky_texture : radiance_texture); - uniforms.push_back(u); - } - - rb->volumetric_fog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0); - - rb->volumetric_fog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0); - - RID aux7 = uniforms.write[7].get_id(0); - RID aux8 = uniforms.write[8].get_id(0); - - uniforms.write[7].set_id(0, aux8); - uniforms.write[8].set_id(0, aux7); - - rb->volumetric_fog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0); - - uniforms.remove_at(8); - uniforms.write[7].set_id(0, aux7); - rb->volumetric_fog->process_uniform_set_density = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 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 uniforms; - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.append_id(gi.sdfgi_ubo); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1; - u.append_id(rb->sdfgi->ambient_texture); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; - u.append_id(rb->sdfgi->occlusion_texture); - uniforms.push_back(u); - } - - rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI), 1); - } - } - - rb->volumetric_fog->length = env->volumetric_fog_length; - rb->volumetric_fog->spread = env->volumetric_fog_detail_spread; - - VolumetricFogShader::ParamsUBO params; - - 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(); - } - - params.fog_frustum_size_begin[0] = fog_near_size.x; - params.fog_frustum_size_begin[1] = fog_near_size.y; - - params.fog_frustum_size_end[0] = fog_far_size.x; - params.fog_frustum_size_end[1] = fog_far_size.y; - - params.ambient_inject = env->volumetric_fog_ambient_inject * env->ambient_light_energy; - params.z_far = z_far; - - params.fog_frustum_end = fog_end; - - Color ambient_color = env->ambient_light.srgb_to_linear(); - params.ambient_color[0] = ambient_color.r; - params.ambient_color[1] = ambient_color.g; - params.ambient_color[2] = ambient_color.b; - params.sky_contribution = env->ambient_sky_contribution; - - params.fog_volume_size[0] = rb->volumetric_fog->width; - params.fog_volume_size[1] = rb->volumetric_fog->height; - params.fog_volume_size[2] = rb->volumetric_fog->depth; - - params.directional_light_count = p_directional_light_count; - - Color emission = env->volumetric_fog_emission.srgb_to_linear(); - params.base_emission[0] = emission.r * env->volumetric_fog_emission_energy; - params.base_emission[1] = emission.g * env->volumetric_fog_emission_energy; - params.base_emission[2] = emission.b * env->volumetric_fog_emission_energy; - params.base_density = env->volumetric_fog_density; - - Color base_scattering = env->volumetric_fog_scattering.srgb_to_linear(); - params.base_scattering[0] = base_scattering.r; - params.base_scattering[1] = base_scattering.g; - params.base_scattering[2] = base_scattering.b; - params.phase_g = env->volumetric_fog_anisotropy; - - params.detail_spread = env->volumetric_fog_detail_spread; - params.gi_inject = env->volumetric_fog_gi_inject; - - params.cam_rotation[0] = p_cam_transform.basis[0][0]; - params.cam_rotation[1] = p_cam_transform.basis[1][0]; - params.cam_rotation[2] = p_cam_transform.basis[2][0]; - params.cam_rotation[3] = 0; - params.cam_rotation[4] = p_cam_transform.basis[0][1]; - params.cam_rotation[5] = p_cam_transform.basis[1][1]; - params.cam_rotation[6] = p_cam_transform.basis[2][1]; - params.cam_rotation[7] = 0; - params.cam_rotation[8] = p_cam_transform.basis[0][2]; - params.cam_rotation[9] = p_cam_transform.basis[1][2]; - params.cam_rotation[10] = p_cam_transform.basis[2][2]; - params.cam_rotation[11] = 0; - params.filter_axis = 0; - params.max_voxel_gi_instances = env->volumetric_fog_gi_inject > 0.001 ? p_voxel_gi_count : 0; - params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES; - - Transform3D to_prev_cam_view = p_prev_cam_inv_transform * p_cam_transform; - RendererRD::MaterialStorage::store_transform(to_prev_cam_view, params.to_prev_view); - - params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection; - params.temporal_blend = env->volumetric_fog_temporal_reprojection_amount; - - { - uint32_t cluster_size = rb->cluster_builder->get_cluster_size(); - params.cluster_shift = get_shift_from_power_of_2(cluster_size); - - uint32_t cluster_screen_width = (rb->width - 1) / cluster_size + 1; - uint32_t cluster_screen_height = (rb->height - 1) / cluster_size + 1; - params.max_cluster_element_count_div_32 = max_cluster_elements / 32; - params.cluster_type_size = cluster_screen_width * cluster_screen_height * (params.max_cluster_element_count_div_32 + 32); - params.cluster_width = cluster_screen_width; - - params.screen_size[0] = rb->width; - params.screen_size[1] = rb->height; - } - - Basis sky_transform = env->sky_orientation; - sky_transform = sky_transform.inverse() * p_cam_transform.basis; - RendererRD::MaterialStorage::store_transform_3x3(sky_transform, params.radiance_inverse_xform); - - RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog"); - - RENDER_TIMESTAMP("Render Fog"); - RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); - - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]); - - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set_density, 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_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); - RD::get_singleton()->compute_list_add_barrier(compute_list); - - // Copy fog to history buffer - if (env->volumetric_fog_temporal_reprojection) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->copy_uniform_set, 0); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); - RD::get_singleton()->compute_list_add_barrier(compute_list); - } - RD::get_singleton()->draw_command_end_label(); - - if (volumetric_fog_filter_active) { - RD::get_singleton()->draw_command_begin_label("Filter Fog"); - - RENDER_TIMESTAMP("Filter Fog"); - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); - - RD::get_singleton()->compute_list_end(); - //need restart for buffer update - - params.filter_axis = 1; - RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms); + if (rb->volumetric_fog) { + RendererRD::Fog::VolumetricFogSettings settings; + settings.rb_size = Vector2i(rb->width, rb->height); + settings.time = time; + settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array(); + settings.max_cluster_elements = max_cluster_elements; + settings.volumetric_fog_filter_active = volumetric_fog_filter_active; + + settings.shadow_sampler = shadow_sampler; + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); + settings.shadow_atlas_depth = shadow_atlas ? shadow_atlas->depth : RID(); + settings.voxel_gl_buffer = render_buffers_get_voxel_gi_buffer(p_render_buffers); + settings.omni_light_buffer = get_omni_light_buffer(); + settings.spot_light_buffer = get_spot_light_buffer(); + settings.directional_shadow_depth = directional_shadow.depth; + settings.directional_light_buffer = get_directional_light_buffer(); - compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set2, 0); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); + settings.vfog = rb->volumetric_fog; + settings.cluster_builder = rb->cluster_builder; + settings.rbgi = &rb->rbgi; + settings.sdfgi = rb->sdfgi; + settings.env = env; + settings.sky = &sky; + settings.gi = &gi; - RD::get_singleton()->compute_list_add_barrier(compute_list); - RD::get_singleton()->draw_command_end_label(); + RendererRD::Fog::get_singleton()->volumetric_fog_update(settings, p_cam_projection, p_cam_transform, p_prev_cam_inv_transform, p_shadow_atlas, p_directional_light_count, p_use_directional_shadows, p_positional_light_count, p_voxel_gi_count, p_fog_volumes); } - - RENDER_TIMESTAMP("Integrate Fog"); - RD::get_singleton()->draw_command_begin_label("Integrate Fog"); - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1); - - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER); - - RENDER_TIMESTAMP("< Volumetric Fog"); - RD::get_singleton()->draw_command_end_label(); - RD::get_singleton()->draw_command_end_label(); } bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) { @@ -5229,7 +4348,8 @@ bool RendererSceneRenderRD::free(RID p_rid) { rb->sdfgi = nullptr; } if (rb->volumetric_fog) { - _volumetric_fog_erase(rb); + memdelete(rb->volumetric_fog); + rb->volumetric_fog = nullptr; } if (rb->cluster_builder) { memdelete(rb->cluster_builder); @@ -5304,8 +4424,8 @@ bool RendererSceneRenderRD::free(RID p_rid) { } else if (shadow_atlas_owner.owns(p_rid)) { shadow_atlas_set_size(p_rid, 0); shadow_atlas_owner.free(p_rid); - } else if (fog_volume_instance_owner.owns(p_rid)) { - fog_volume_instance_owner.free(p_rid); + } else if (RendererRD::Fog::get_singleton()->owns_fog_volume_instance(p_rid)) { + RendererRD::Fog::get_singleton()->fog_instance_free(p_rid); } else { return false; } @@ -5499,8 +4619,6 @@ RendererSceneRenderRD::RendererSceneRenderRD() { } void RendererSceneRenderRD::init() { - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - max_cluster_elements = get_max_elements(); directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size"); @@ -5551,124 +4669,7 @@ void RendererSceneRenderRD::init() { } if (is_volumetric_supported()) { - { - // Initialize local fog shader - Vector volumetric_fog_modes; - volumetric_fog_modes.push_back(""); - volumetric_fog.shader.initialize(volumetric_fog_modes); - - material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_FOG, _create_fog_shader_funcs); - material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_FOG, _create_fog_material_funcs); - volumetric_fog.volume_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::VolumeUBO)); - } - - { - ShaderCompiler::DefaultIdentifierActions actions; - - actions.renames["TIME"] = "scene_params.time"; - actions.renames["PI"] = _MKSTR(Math_PI); - actions.renames["TAU"] = _MKSTR(Math_TAU); - actions.renames["E"] = _MKSTR(Math_E); - actions.renames["WORLD_POSITION"] = "world.xyz"; - actions.renames["OBJECT_POSITION"] = "params.position"; - actions.renames["UVW"] = "uvw"; - actions.renames["EXTENTS"] = "params.extents"; - actions.renames["ALBEDO"] = "albedo"; - actions.renames["DENSITY"] = "density"; - actions.renames["EMISSION"] = "emission"; - actions.renames["SDF"] = "sdf"; - - actions.usage_defines["SDF"] = "#define SDF_USED\n"; - actions.usage_defines["DENSITY"] = "#define DENSITY_USED\n"; - actions.usage_defines["ALBEDO"] = "#define ALBEDO_USED\n"; - actions.usage_defines["EMISSION"] = "#define EMISSION_USED\n"; - - actions.sampler_array_name = "material_samplers"; - actions.base_texture_binding_index = 1; - actions.texture_layout_set = VolumetricFogShader::FogSet::FOG_SET_MATERIAL; - actions.base_uniform_string = "material."; - - actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; - actions.default_repeat = ShaderLanguage::REPEAT_DISABLE; - actions.global_buffer_array_variable = "global_variables.data"; - - volumetric_fog.compiler.initialize(actions); - } - - { - // default material and shader for fog shader - volumetric_fog.default_shader = material_storage->shader_allocate(); - material_storage->shader_initialize(volumetric_fog.default_shader); - material_storage->shader_set_code(volumetric_fog.default_shader, R"( -// Default fog shader. - -shader_type fog; - -void fog() { - DENSITY = 1.0; - ALBEDO = vec3(1.0); -} -)"); - volumetric_fog.default_material = material_storage->material_allocate(); - material_storage->material_initialize(volumetric_fog.default_material); - material_storage->material_set_shader(volumetric_fog.default_material, volumetric_fog.default_shader); - - FogMaterialData *md = static_cast(material_storage->material_get_data(volumetric_fog.default_material, RendererRD::SHADER_TYPE_FOG)); - volumetric_fog.default_shader_rd = volumetric_fog.shader.version_get_shader(md->shader_data->version, 0); - - Vector uniforms; - - { - Vector ids; - ids.resize(12); - RID *ids_ptr = ids.ptrw(); - ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - - RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 1, ids); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 2; - u.append_id(RendererRD::MaterialStorage::get_singleton()->global_variables_get_storage_buffer()); - uniforms.push_back(u); - } - - volumetric_fog.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_BASE); - } - { - String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; - defines += "\n#define MAX_SKY_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; - if (is_using_radiance_cubemap_array()) { - defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; - } - Vector 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_modes.push_back("\n#define MODE_COPY\n"); - - volumetric_fog.process_shader.initialize(volumetric_fog_modes, defines); - volumetric_fog.process_shader_version = volumetric_fog.process_shader.version_create(); - for (int i = 0; i < VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_MAX; i++) { - volumetric_fog.process_pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, i)); - } - volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO)); - } + RendererRD::Fog::get_singleton()->init_fog_shader(cluster.max_directional_lights, get_roughness_layers(), is_using_radiance_cubemap_array()); } { @@ -5721,8 +4722,6 @@ void fog() { } RendererSceneRenderRD::~RendererSceneRenderRD() { - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - if (bokeh_dof) { memdelete(bokeh_dof); } @@ -5752,11 +4751,7 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { } if (is_volumetric_supported()) { - volumetric_fog.process_shader.version_free(volumetric_fog.process_shader_version); - RD::get_singleton()->free(volumetric_fog.volume_ubo); - RD::get_singleton()->free(volumetric_fog.params_ubo); - material_storage->shader_free(volumetric_fog.default_shader); - material_storage->material_free(volumetric_fog.default_material); + RendererRD::Fog::get_singleton()->free_fog_shader(); } memdelete_arr(directional_penumbra_shadow_kernel); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 0e15c9155d..cd56b8efb3 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -40,11 +40,10 @@ #include "servers/rendering/renderer_rd/effects/ss_effects.h" #include "servers/rendering/renderer_rd/effects/tone_mapper.h" #include "servers/rendering/renderer_rd/effects/vrs.h" +#include "servers/rendering/renderer_rd/environment/fog.h" #include "servers/rendering/renderer_rd/environment/gi.h" +#include "servers/rendering/renderer_rd/environment/sky.h" #include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" -#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" -#include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl.gen.h" #include "servers/rendering/renderer_scene.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" @@ -99,7 +98,7 @@ struct RenderDataRD { }; class RendererSceneRenderRD : public RendererSceneRender { - friend RendererSceneSkyRD; + friend RendererRD::SkyRD; friend RendererRD::GI; protected: @@ -167,7 +166,7 @@ protected: RendererRD::SSEffects *ss_effects = nullptr; RendererRD::GI gi; - RendererSceneSkyRD sky; + RendererRD::SkyRD sky; RendererSceneEnvironmentRD *get_environment(RID p_environment) { if (p_environment.is_valid()) { @@ -212,7 +211,7 @@ private: struct Reflection { RID owner; - RendererSceneSkyRD::ReflectionData data; + RendererRD::SkyRD::ReflectionData data; RID fbs[6]; }; @@ -407,16 +406,6 @@ private: mutable RID_Owner light_instance_owner; - /* FOG VOLUMES */ - - struct FogVolumeInstance { - RID volume; - Transform3D transform; - bool active = false; - }; - - mutable RID_Owner fog_volume_instance_owner; - /* ENVIRONMENT */ RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; @@ -471,8 +460,6 @@ private: ClusterBuilderSharedDataRD cluster_builder_shared; ClusterBuilderRD *current_cluster_builder = nullptr; - struct VolumetricFog; - struct RenderBuffers { RenderBufferData *data = nullptr; int internal_width = 0; @@ -508,8 +495,8 @@ private: Vector views; RendererRD::GI::SDFGI *sdfgi = nullptr; - VolumetricFog *volumetric_fog = nullptr; RendererRD::GI::RenderBuffersGI rbgi; + RendererRD::Fog::VolumetricFog *volumetric_fog = nullptr; ClusterBuilderRD *cluster_builder = nullptr; @@ -749,204 +736,6 @@ private: bool depth_prepass_used; // this does not seem used anywhere... } render_state; - struct VolumetricFog { - enum { - MAX_TEMPORAL_FRAMES = 16 - }; - - uint32_t width = 0; - uint32_t height = 0; - uint32_t depth = 0; - - float length; - float spread; - - RID light_density_map; - RID prev_light_density_map; - RID fog_map; - RID density_map; - RID light_map; - RID emissive_map; - - RID fog_uniform_set; - RID copy_uniform_set; - RID process_uniform_set_density; - RID process_uniform_set; - RID process_uniform_set2; - RID sdfgi_uniform_set; - RID sky_uniform_set; - - int last_shadow_filter = -1; - }; - - struct VolumetricFogShader { - enum FogSet { - FOG_SET_BASE, - FOG_SET_UNIFORMS, - FOG_SET_MATERIAL, - FOG_SET_MAX, - }; - - struct FogPushConstant { - float position[3]; - float pad; - - float extents[3]; - float pad2; - - int32_t corner[3]; - uint32_t shape; - - float transform[16]; - }; - - struct VolumeUBO { - float fog_frustum_size_begin[2]; - float fog_frustum_size_end[2]; - - float fog_frustum_end; - float z_near; - float z_far; - float time; - - int32_t fog_volume_size[3]; - uint32_t directional_light_count; - - uint32_t use_temporal_reprojection; - uint32_t temporal_frame; - float detail_spread; - float temporal_blend; - - float to_prev_view[16]; - float transform[16]; - }; - - ShaderCompiler compiler; - VolumetricFogShaderRD shader; - FogPushConstant push_constant; - RID volume_ubo; - - RID default_shader; - RID default_material; - RID default_shader_rd; - - RID base_uniform_set; - - RID params_ubo; - - enum { - VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY, - VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI, - VOLUMETRIC_FOG_PROCESS_SHADER_FILTER, - VOLUMETRIC_FOG_PROCESS_SHADER_FOG, - VOLUMETRIC_FOG_PROCESS_SHADER_COPY, - VOLUMETRIC_FOG_PROCESS_SHADER_MAX, - }; - - struct ParamsUBO { - float fog_frustum_size_begin[2]; - float fog_frustum_size_end[2]; - - float fog_frustum_end; - float ambient_inject; - float z_far; - uint32_t filter_axis; - - float ambient_color[3]; - float sky_contribution; - - int32_t fog_volume_size[3]; - uint32_t directional_light_count; - - float base_emission[3]; - float base_density; - - float base_scattering[3]; - float phase_g; - - float detail_spread; - float gi_inject; - uint32_t max_voxel_gi_instances; - uint32_t cluster_type_size; - - float screen_size[2]; - uint32_t cluster_shift; - uint32_t cluster_width; - - uint32_t max_cluster_element_count_div_32; - uint32_t use_temporal_reprojection; - uint32_t temporal_frame; - float temporal_blend; - - float cam_rotation[12]; - float to_prev_view[16]; - float radiance_inverse_xform[12]; - }; - - VolumetricFogProcessShaderRD process_shader; - - RID process_shader_version; - RID process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX]; - - } volumetric_fog; - - uint32_t volumetric_fog_depth = 128; - uint32_t volumetric_fog_size = 128; - bool volumetric_fog_filter_active = true; - - Vector3i _point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform); - void _volumetric_fog_erase(RenderBuffers *rb); - void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes); - - struct FogShaderData : public RendererRD::ShaderData { - bool valid = false; - RID version; - - RID pipeline; - HashMap uniforms; - Vector texture_uniforms; - - Vector ubo_offsets; - uint32_t ubo_size = 0; - - String path; - String code; - HashMap> default_texture_params; - - bool uses_time = false; - - virtual void set_code(const String &p_Code); - virtual void set_path_hint(const String &p_hint); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); - virtual void get_param_list(List *p_param_list) const; - virtual void get_instance_param_list(List *p_param_list) const; - virtual bool is_param_texture(const StringName &p_param) const; - virtual bool is_animated() const; - virtual bool casts_shadows() const; - virtual Variant get_default_parameter(const StringName &p_parameter) const; - virtual RS::ShaderNativeSourceCode get_native_source_code() const; - - FogShaderData() {} - virtual ~FogShaderData(); - }; - - struct FogMaterialData : public RendererRD::MaterialData { - FogShaderData *shader_data = nullptr; - RID uniform_set; - bool uniform_set_updated; - - virtual void set_render_priority(int p_priority) {} - virtual void set_next_pass(RID p_pass) {} - virtual bool update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~FogMaterialData(); - }; - - RendererRD::ShaderData *_create_fog_shader_func(); - static RendererRD::ShaderData *_create_fog_shader_funcs(); - - RendererRD::MaterialData *_create_fog_material_func(FogShaderData *p_shader); - static RendererRD::MaterialData *_create_fog_material_funcs(RendererRD::ShaderData *p_shader); - RID shadow_sampler; uint64_t scene_pass = 0; @@ -963,6 +752,14 @@ private: void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RendererScene::RenderInfo *p_render_info = nullptr); + /* Volumetric Fog */ + + uint32_t volumetric_fog_size = 128; + uint32_t volumetric_fog_depth = 128; + bool volumetric_fog_filter_active = true; + + void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes); + public: virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) = 0; virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) = 0; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp deleted file mode 100644 index 33c21f5b04..0000000000 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ /dev/null @@ -1,1924 +0,0 @@ -/*************************************************************************/ -/* renderer_scene_sky_rd.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "renderer_scene_sky_rd.h" -#include "core/config/project_settings.h" -#include "core/math/math_defs.h" -#include "renderer_scene_render_rd.h" -#include "servers/rendering/renderer_rd/effects/copy_effects.h" -#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" -#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" -#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" -#include "servers/rendering/rendering_server_default.h" -#include "servers/rendering/rendering_server_globals.h" - -//////////////////////////////////////////////////////////////////////////////// -// SKY SHADER - -void RendererSceneSkyRD::SkyShaderData::set_path_hint(const String &p_path) { - path = p_path; -} - -void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { - //compile - - code = p_code; - valid = false; - ubo_size = 0; - uniforms.clear(); - - if (code.is_empty()) { - return; //just invalid, but no error - } - - ShaderCompiler::GeneratedCode gen_code; - ShaderCompiler::IdentifierActions actions; - actions.entry_point_stages["sky"] = ShaderCompiler::STAGE_FRAGMENT; - - uses_time = false; - uses_half_res = false; - uses_quarter_res = false; - uses_position = false; - uses_light = false; - - actions.render_mode_flags["use_half_res_pass"] = &uses_half_res; - actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res; - - actions.usage_flag_pointers["TIME"] = &uses_time; - actions.usage_flag_pointers["POSITION"] = &uses_position; - actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light; - actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light; - actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light; - actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light; - actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light; - actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light; - actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light; - actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light; - actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light; - actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light; - actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light; - actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light; - actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light; - actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light; - actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light; - actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light; - actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light; - actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light; - actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light; - actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light; - - actions.uniforms = &uniforms; - - // !BAS! Contemplate making `SkyShader sky` accessible from this struct or even part of this struct. - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - - Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code); - ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); - - if (version.is_null()) { - version = scene_singleton->sky.sky_shader.shader.version_create(); - } - -#if 0 - print_line("**compiling shader:"); - print_line("**defines:\n"); - for (int i = 0; i < gen_code.defines.size(); i++) { - print_line(gen_code.defines[i]); - } - print_line("\n**uniforms:\n" + gen_code.uniforms); - // print_line("\n**vertex_globals:\n" + gen_code.vertex_global); - // print_line("\n**vertex_code:\n" + gen_code.vertex); - print_line("\n**fragment_globals:\n" + gen_code.fragment_global); - print_line("\n**fragment_code:\n" + gen_code.fragment); - print_line("\n**light_code:\n" + gen_code.light); -#endif - - scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); - ERR_FAIL_COND(!scene_singleton->sky.sky_shader.shader.version_is_valid(version)); - - ubo_size = gen_code.uniform_total_size; - ubo_offsets = gen_code.uniform_offsets; - texture_uniforms = gen_code.texture_uniforms; - - //update pipelines - - for (int i = 0; i < SKY_VERSION_MAX; i++) { - RD::PipelineDepthStencilState depth_stencil_state; - depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - - if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) { - RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); - pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0); - } else { - pipelines[i].clear(); - } - } - - valid = true; -} - -void RendererSceneSkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { - if (!p_texture.is_valid()) { - if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { - default_texture_params[p_name].erase(p_index); - - if (default_texture_params[p_name].is_empty()) { - default_texture_params.erase(p_name); - } - } - } else { - if (!default_texture_params.has(p_name)) { - default_texture_params[p_name] = HashMap(); - } - default_texture_params[p_name][p_index] = p_texture; - } -} - -void RendererSceneSkyRD::SkyShaderData::get_param_list(List *p_param_list) const { - HashMap order; - - for (const KeyValue &E : uniforms) { - if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { - continue; - } - - if (E.value.texture_order >= 0) { - order[E.value.texture_order + 100000] = E.key; - } else { - order[E.value.order] = E.key; - } - } - - for (const KeyValue &E : order) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); - pi.name = E.value; - p_param_list->push_back(pi); - } -} - -void RendererSceneSkyRD::SkyShaderData::get_instance_param_list(List *p_param_list) const { - for (const KeyValue &E : uniforms) { - if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { - continue; - } - - RendererMaterialStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E.value); - p.info.name = E.key; //supply name - p.index = E.value.instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); - p_param_list->push_back(p); - } -} - -bool RendererSceneSkyRD::SkyShaderData::is_param_texture(const StringName &p_param) const { - if (!uniforms.has(p_param)) { - return false; - } - - return uniforms[p_param].texture_order >= 0; -} - -bool RendererSceneSkyRD::SkyShaderData::is_animated() const { - return false; -} - -bool RendererSceneSkyRD::SkyShaderData::casts_shadows() const { - return false; -} - -Variant RendererSceneSkyRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const { - if (uniforms.has(p_parameter)) { - ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; - Vector default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); - } - return Variant(); -} - -RS::ShaderNativeSourceCode RendererSceneSkyRD::SkyShaderData::get_native_source_code() const { - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - - return scene_singleton->sky.sky_shader.shader.version_get_native_source_code(version); -} - -RendererSceneSkyRD::SkyShaderData::~SkyShaderData() { - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - ERR_FAIL_COND(!scene_singleton); - //pipeline variants will clear themselves if shader is gone - if (version.is_valid()) { - scene_singleton->sky.sky_shader.shader.version_free(version); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Sky material - -bool RendererSceneSkyRD::SkyMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RendererSceneRenderRD *scene_singleton = static_cast(RendererSceneRenderRD::singleton); - - uniform_set_updated = true; - - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); -} - -RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() { - free_parameters_uniform_set(uniform_set); -} - -//////////////////////////////////////////////////////////////////////////////// -// Render sky - -static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) { - p_array[0] = p_basis.rows[0][0]; - p_array[1] = p_basis.rows[1][0]; - p_array[2] = p_basis.rows[2][0]; - p_array[3] = 0; - p_array[4] = p_basis.rows[0][1]; - p_array[5] = p_basis.rows[1][1]; - p_array[6] = p_basis.rows[2][1]; - p_array[7] = 0; - p_array[8] = p_basis.rows[0][2]; - p_array[9] = p_basis.rows[1][2]; - p_array[10] = p_basis.rows[2][2]; - p_array[11] = 0; -} - -void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier) { - SkyPushConstant sky_push_constant; - - memset(&sky_push_constant, 0, sizeof(SkyPushConstant)); - - for (uint32_t v = 0; v < p_view_count; v++) { - // We only need key components of our projection matrix - sky_push_constant.projections[v][0] = p_projections[v].matrix[2][0]; - sky_push_constant.projections[v][1] = p_projections[v].matrix[0][0]; - sky_push_constant.projections[v][2] = p_projections[v].matrix[2][1]; - sky_push_constant.projections[v][3] = p_projections[v].matrix[1][1]; - } - sky_push_constant.position[0] = p_position.x; - sky_push_constant.position[1] = p_position.y; - sky_push_constant.position[2] = p_position.z; - sky_push_constant.multiplier = p_multiplier; - sky_push_constant.time = p_time; - sky_push_constant.luminance_multiplier = p_luminance_multiplier; - store_transform_3x3(p_orientation, sky_push_constant.orientation); - - RenderingDevice::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_fb); - - RD::DrawListID draw_list = p_list; - - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format, false, RD::get_singleton()->draw_list_get_current_pass())); - - // Update uniform sets. - { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0); - if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set. - 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); - // Fog uniform set can be invalidated before drawing, so validate at draw time - if (sky_scene_state.fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_uniform_set)) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3); - } else { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.default_fog_uniform_set, 3); - } - } - - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - - RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant)); - - RD::get_singleton()->draw_list_draw(draw_list, true); -} - -//////////////////////////////////////////////////////////////////////////////// -// ReflectionData - -void RendererSceneSkyRD::ReflectionData::clear_reflection_data() { - layers.clear(); - radiance_base_cubemap = RID(); - if (downsampled_radiance_cubemap.is_valid()) { - RD::get_singleton()->free(downsampled_radiance_cubemap); - } - downsampled_radiance_cubemap = RID(); - downsampled_layer.mipmaps.clear(); - coefficient_buffer = RID(); -} - -void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format) { - //recreate radiance and all data - - int mipmaps = p_mipmaps; - uint32_t w = p_size, h = p_size; - - EffectsRD *effects = RendererCompositorRD::singleton->get_effects(); - ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); - bool prefer_raster_effects = effects->get_prefer_raster_effects(); - - if (p_use_array) { - int num_layers = p_low_quality ? 8 : p_roughness_layers; - - for (int i = 0; i < num_layers; i++) { - ReflectionData::Layer layer; - uint32_t mmw = w; - uint32_t mmh = h; - layer.mipmaps.resize(mipmaps); - layer.views.resize(mipmaps); - for (int j = 0; j < mipmaps; j++) { - ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; - mm.size.width = mmw; - mm.size.height = mmh; - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } - - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, 1, RD::TEXTURE_SLICE_CUBEMAP); - - mmw = MAX(1u, mmw >> 1); - mmh = MAX(1u, mmh >> 1); - } - - layers.push_back(layer); - } - - } else { - mipmaps = p_low_quality ? 8 : mipmaps; - //regular cubemap, lower quality (aliasing, less memory) - ReflectionData::Layer layer; - uint32_t mmw = w; - uint32_t mmh = h; - layer.mipmaps.resize(mipmaps); - layer.views.resize(mipmaps); - for (int j = 0; j < mipmaps; j++) { - ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; - mm.size.width = mmw; - mm.size.height = mmh; - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } - - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, 1, RD::TEXTURE_SLICE_CUBEMAP); - - mmw = MAX(1u, mmw >> 1); - mmh = MAX(1u, mmh >> 1); - } - - layers.push_back(layer); - } - - radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, 1, RD::TEXTURE_SLICE_CUBEMAP); - RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap"); - RD::TextureFormat tf; - tf.format = p_texture_format; - tf.width = 64; // Always 64x64 - tf.height = 64; - tf.texture_type = RD::TEXTURE_TYPE_CUBE; - tf.array_layers = 6; - tf.mipmaps = 7; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - - downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(downsampled_radiance_cubemap, "downsampled radiance cubemap"); - { - uint32_t mmw = 64; - uint32_t mmh = 64; - downsampled_layer.mipmaps.resize(7); - for (int j = 0; j < downsampled_layer.mipmaps.size(); j++) { - ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j]; - mm.size.width = mmw; - mm.size.height = mmh; - mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, 1, RD::TEXTURE_SLICE_CUBEMAP); - RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " "); - if (prefer_raster_effects) { - // we need a framebuffer for each side of our cubemap - - for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, k, j); - RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip: " + itos(j) + " Face: " + itos(k) + " "); - Vector fbtex; - fbtex.push_back(mm.views[k]); - mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); - } - } - - mmw = MAX(1u, mmw >> 1); - mmh = MAX(1u, mmh >> 1); - } - } -} - -void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(bool p_use_arrays) { - RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); - ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); - bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); - - if (prefer_raster_effects) { - RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); - } - - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); - } - } - RD::get_singleton()->draw_command_end_label(); // Downsample Radiance - - if (p_use_arrays) { - RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads"); - for (int i = 0; i < layers.size(); i++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i); - } - } - } else { - RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly"); - for (int j = 0; j < layers[0].mipmaps.size(); j++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j); - } - } - } - RD::get_singleton()->draw_command_end_label(); // Filter radiance - } else { - RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); - copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); - - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); - } - RD::get_singleton()->draw_command_end_label(); // Downsample Radiance - Vector views; - if (p_use_arrays) { - for (int i = 1; i < layers.size(); i++) { - views.push_back(layers[i].views[0]); - } - } else { - for (int i = 1; i < layers[0].views.size(); i++) { - views.push_back(layers[0].views[i]); - } - } - RD::get_singleton()->draw_command_begin_label("Fast filter radiance"); - copy_effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); - RD::get_singleton()->draw_command_end_label(); // Filter radiance - } -} - -void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) { - RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); - ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); - bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); - - if (prefer_raster_effects) { - if (p_base_layer == 1) { - RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); - } - - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); - } - } - RD::get_singleton()->draw_command_end_label(); // Downsample Radiance - } - - RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); - if (p_use_arrays) { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_roughness_raster( - downsampled_radiance_cubemap, - layers[p_base_layer].mipmaps[0].framebuffers[k], - k, - p_sky_ggx_samples_quality, - float(p_base_layer) / (layers.size() - 1.0), - layers[p_base_layer].mipmaps[0].size.x); - } - } else { - for (int k = 0; k < 6; k++) { - copy_effects->cubemap_roughness_raster( - downsampled_radiance_cubemap, - layers[0].mipmaps[p_base_layer].framebuffers[k], - k, - p_sky_ggx_samples_quality, - float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), - layers[0].mipmaps[p_base_layer].size.x); - } - } - } else { - if (p_base_layer == 1) { - RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); - copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); - - for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); - } - RD::get_singleton()->draw_command_end_label(); // Downsample Radiance - } - - RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); - if (p_use_arrays) { - copy_effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); - } else { - copy_effects->cubemap_roughness( - downsampled_radiance_cubemap, - layers[0].views[p_base_layer], - p_cube_side, - p_sky_ggx_samples_quality, - float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), - layers[0].mipmaps[p_base_layer].size.x); - } - } - RD::get_singleton()->draw_command_end_label(); // Filter radiance -} - -void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(int p_start, int p_end) { - RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); - ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); - bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); - - RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps"); - for (int i = p_start; i < p_end; i++) { - for (int j = 0; j < layers[i].views.size() - 1; j++) { - RID view = layers[i].views[j]; - Size2i size = layers[i].mipmaps[j + 1].size; - if (prefer_raster_effects) { - for (int k = 0; k < 6; k++) { - RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k]; - copy_effects->cubemap_downsample_raster(view, framebuffer, k, size); - } - } else { - RID texture = layers[i].views[j + 1]; - copy_effects->cubemap_downsample(view, texture, size); - } - } - } - RD::get_singleton()->draw_command_end_label(); -} - -//////////////////////////////////////////////////////////////////////////////// -// RendererSceneSkyRD::Sky - -void RendererSceneSkyRD::Sky::free() { - if (radiance.is_valid()) { - RD::get_singleton()->free(radiance); - radiance = RID(); - } - reflection.clear_reflection_data(); - - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - if (half_res_pass.is_valid()) { - RD::get_singleton()->free(half_res_pass); - half_res_pass = RID(); - } - - if (quarter_res_pass.is_valid()) { - RD::get_singleton()->free(quarter_res_pass); - quarter_res_pass = RID(); - } - - if (material.is_valid()) { - RSG::material_storage->material_free(material); - material = RID(); - } -} - -RID RendererSceneSkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd) { - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - - if (texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(texture_uniform_sets[p_version])) { - return texture_uniform_sets[p_version]; - } - Vector uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 0; - if (radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { - u.append_id(radiance); - } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); - } - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1; // half res - if (half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { - if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { - u.append_id(reflection.layers[0].views[1]); - } else { - u.append_id(half_res_pass); - } - } else { - if (p_version < SKY_TEXTURE_SET_CUBEMAP) { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); - } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); - } - } - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; // quarter res - if (quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { - if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { - u.append_id(reflection.layers[0].views[2]); - } else { - u.append_id(quarter_res_pass); - } - } else { - if (p_version < SKY_TEXTURE_SET_CUBEMAP) { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); - } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); - } - } - uniforms.push_back(u); - } - - texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, p_default_shader_rd, SKY_SET_TEXTURES); - return texture_uniform_sets[p_version]; -} - -bool RendererSceneSkyRD::Sky::set_radiance_size(int p_radiance_size) { - ERR_FAIL_COND_V(p_radiance_size < 32 || p_radiance_size > 2048, false); - if (radiance_size == p_radiance_size) { - return false; - } - radiance_size = p_radiance_size; - - if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { - WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); - radiance_size = 256; - } - - if (radiance.is_valid()) { - RD::get_singleton()->free(radiance); - radiance = RID(); - } - reflection.clear_reflection_data(); - - return true; -} - -bool RendererSceneSkyRD::Sky::set_mode(RS::SkyMode p_mode) { - if (mode == p_mode) { - return false; - } - - mode = p_mode; - - if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { - WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); - set_radiance_size(256); - } - - if (radiance.is_valid()) { - RD::get_singleton()->free(radiance); - radiance = RID(); - } - reflection.clear_reflection_data(); - - return true; -} - -bool RendererSceneSkyRD::Sky::set_material(RID p_material) { - if (material == p_material) { - return false; - } - - material = p_material; - return true; -} - -Ref RendererSceneSkyRD::Sky::bake_panorama(float p_energy, int p_roughness_layers, const Size2i &p_size) { - if (radiance.is_valid()) { - RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); - - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; - tf.width = p_size.width; - tf.height = p_size.height; - tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - - RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView()); - copy_effects->copy_cubemap_to_panorama(radiance, rad_tex, p_size, p_roughness_layers, reflection.layers.size() > 1); - Vector data = RD::get_singleton()->texture_get_data(rad_tex, 0); - RD::get_singleton()->free(rad_tex); - - Ref img; - img.instantiate(); - img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data); - for (int i = 0; i < p_size.width; i++) { - for (int j = 0; j < p_size.height; j++) { - Color c = img->get_pixel(i, j); - c.r *= p_energy; - c.g *= p_energy; - c.b *= p_energy; - img->set_pixel(i, j, c); - } - } - return img; - } - - return Ref(); -} - -//////////////////////////////////////////////////////////////////////////////// -// RendererSceneSkyRD - -RendererRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_func() { - SkyShaderData *shader_data = memnew(SkyShaderData); - return shader_data; -} - -RendererRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_funcs() { - // !BAS! Why isn't _create_sky_shader_func not just static too? - return static_cast(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func(); -}; - -RendererRD::MaterialData *RendererSceneSkyRD::_create_sky_material_func(SkyShaderData *p_shader) { - SkyMaterialData *material_data = memnew(SkyMaterialData); - material_data->shader_data = p_shader; - //update will happen later anyway so do nothing. - return material_data; -} - -RendererRD::MaterialData *RendererSceneSkyRD::_create_sky_material_funcs(RendererRD::ShaderData *p_shader) { - // !BAS! same here, we could just make _create_sky_material_func static? - return static_cast(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast(p_shader)); -}; - -RendererSceneSkyRD::RendererSceneSkyRD() { - roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers"); - sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"); - sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections"); -} - -void RendererSceneSkyRD::init() { - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - - { - // Start with the directional lights for the sky - sky_scene_state.max_directional_lights = 4; - uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData); - sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); - sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); - sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1; - sky_scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); - - String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_scene_state.max_directional_lights) + "\n"; - - // Initialize sky - Vector sky_modes; - sky_modes.push_back(""); // Full size - sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res - sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res - sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap - sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap - sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap - - sky_modes.push_back("\n#define USE_MULTIVIEW\n"); // Full size multiview - sky_modes.push_back("\n#define USE_HALF_RES_PASS\n#define USE_MULTIVIEW\n"); // Half Res multiview - sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n#define USE_MULTIVIEW\n"); // Quarter res multiview - - sky_shader.shader.initialize(sky_modes, defines); - - if (!RendererCompositorRD::singleton->is_xr_enabled()) { - sky_shader.shader.set_variant_enabled(SKY_VERSION_BACKGROUND_MULTIVIEW, false); - sky_shader.shader.set_variant_enabled(SKY_VERSION_HALF_RES_MULTIVIEW, false); - sky_shader.shader.set_variant_enabled(SKY_VERSION_QUARTER_RES_MULTIVIEW, false); - } - } - - // register our shader funds - material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); - material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_SKY, _create_sky_material_funcs); - - { - ShaderCompiler::DefaultIdentifierActions actions; - - actions.renames["COLOR"] = "color"; - actions.renames["ALPHA"] = "alpha"; - actions.renames["EYEDIR"] = "cube_normal"; - actions.renames["POSITION"] = "params.position_multiplier.xyz"; - actions.renames["SKY_COORDS"] = "panorama_coords"; - actions.renames["SCREEN_UV"] = "uv"; - actions.renames["FRAGCOORD"] = "gl_FragCoord"; - actions.renames["TIME"] = "params.time"; - actions.renames["PI"] = _MKSTR(Math_PI); - actions.renames["TAU"] = _MKSTR(Math_TAU); - actions.renames["E"] = _MKSTR(Math_E); - actions.renames["HALF_RES_COLOR"] = "half_res_color"; - actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color"; - actions.renames["RADIANCE"] = "radiance"; - actions.renames["FOG"] = "custom_fog"; - actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled"; - actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz"; - actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w"; - actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz"; - actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w"; - actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled"; - actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz"; - actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w"; - actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz"; - actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w"; - actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled"; - actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz"; - actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w"; - actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz"; - actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w"; - actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled"; - actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz"; - actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w"; - actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz"; - actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w"; - actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS"; - actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS"; - actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS"; - 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; - actions.texture_layout_set = 1; - actions.base_uniform_string = "material."; - actions.base_varying_index = 10; - - actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; - actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; - actions.global_buffer_array_variable = "global_variables.data"; - - sky_shader.compiler.initialize(actions); - } - - { - // default material and shader for sky shader - sky_shader.default_shader = material_storage->shader_allocate(); - material_storage->shader_initialize(sky_shader.default_shader); - - material_storage->shader_set_code(sky_shader.default_shader, R"( -// Default sky shader. - -shader_type sky; - -void sky() { - COLOR = vec3(0.0); -} -)"); - - sky_shader.default_material = material_storage->material_allocate(); - material_storage->material_initialize(sky_shader.default_material); - - material_storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader); - - SkyMaterialData *md = static_cast(material_storage->material_get_data(sky_shader.default_material, RendererRD::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 uniforms; - - { - Vector ids; - ids.resize(12); - RID *ids_ptr = ids.ptrw(); - ids_ptr[0] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[1] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[2] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[3] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[4] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[5] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[6] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[7] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[8] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[9] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[10] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[11] = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - - RD::Uniform u(RD::UNIFORM_TYPE_SAMPLER, 0, ids); - - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 1; - u.append_id(RendererRD::MaterialStorage::get_singleton()->global_variables_get_storage_buffer()); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 2; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.append_id(sky_scene_state.uniform_buffer); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 3; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.append_id(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 uniforms; - { - RD::Uniform u; - u.binding = 0; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID vfog = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE); - u.append_id(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 = material_storage->shader_allocate(); - material_storage->shader_initialize(sky_scene_state.fog_shader); - - material_storage->shader_set_code(sky_scene_state.fog_shader, R"( -// Default clear color sky shader. - -shader_type sky; - -uniform vec4 clear_color; - -void sky() { - COLOR = clear_color.rgb; -} -)"); - sky_scene_state.fog_material = material_storage->material_allocate(); - material_storage->material_initialize(sky_scene_state.fog_material); - - material_storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader); - - Vector uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 0; - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1; - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; - u.append_id(texture_storage->texture_rd_get_default(RendererRD::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); - } - - { //create index array for copy shaders - Vector pv; - pv.resize(6 * 4); - { - uint8_t *w = pv.ptrw(); - int *p32 = (int *)w; - p32[0] = 0; - p32[1] = 1; - p32[2] = 2; - p32[3] = 0; - p32[4] = 2; - p32[5] = 3; - } - index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); - index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6); - } -} - -void RendererSceneSkyRD::set_texture_format(RD::DataFormat p_texture_format) { - texture_format = p_texture_format; -} - -RendererSceneSkyRD::~RendererSceneSkyRD() { - // cleanup anything created in init... - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - - SkyMaterialData *md = static_cast(material_storage->material_get_data(sky_shader.default_material, RendererRD::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); - material_storage->shader_free(sky_shader.default_shader); - material_storage->material_free(sky_shader.default_material); - material_storage->shader_free(sky_scene_state.fog_shader); - material_storage->material_free(sky_scene_state.fog_material); - - if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) { - RD::get_singleton()->free(sky_scene_state.uniform_set); - } - - if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.default_fog_uniform_set)) { - RD::get_singleton()->free(sky_scene_state.default_fog_uniform_set); - } - - if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_only_texture_uniform_set)) { - RD::get_singleton()->free(sky_scene_state.fog_only_texture_uniform_set); - } - - RD::get_singleton()->free(index_buffer); //array gets freed as dependency -} - -void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const PagedArray &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) { - RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - ERR_FAIL_COND(!p_env); - - SkyMaterialData *material = nullptr; - Sky *sky = get_sky(p_env->sky); - - RID sky_material; - - SkyShaderData *shader_data = nullptr; - - if (sky) { - sky_material = sky_get_material(p_env->sky); - - if (sky_material.is_valid()) { - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - sky_material = sky_shader.default_material; - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - } - - ERR_FAIL_COND(!material); - - shader_data = material->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(); - } - invalidate_sky(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(); - } - invalidate_sky(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()) { - invalidate_sky(sky); - update_dirty_skys(); - } - - if (shader_data->uses_time && p_scene_render->time - sky->prev_time > 0.00001) { - sky->prev_time = p_scene_render->time; - sky->reflection.dirty = true; - RenderingServerDefault::redraw_request(); - } - - 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 (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) { - sky->prev_position = p_transform.origin; - sky->reflection.dirty = true; - } - - if (shader_data->uses_light) { - sky_scene_state.ubo.directional_light_count = 0; - // Run through the list of lights in the scene and pick out the Directional Lights. - // This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called - // after the depth prepass, but this runs before the depth prepass - for (int i = 0; i < (int)p_lights.size(); i++) { - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_lights[i]); - if (!li) { - continue; - } - RID base = li->light; - - ERR_CONTINUE(base.is_null()); - - RS::LightType type = light_storage->light_get_type(base); - if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) { - SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count]; - Transform3D light_transform = li->transform; - 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; - - float sign = light_storage->light_is_negative(base) ? -1 : 1; - sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY); - - Color linear_col = light_storage->light_get_color(base).srgb_to_linear(); - sky_light_data.color[0] = linear_col.r; - sky_light_data.color[1] = linear_col.g; - sky_light_data.color[2] = linear_col.b; - - sky_light_data.enabled = true; - - float angular_diameter = light_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; - } - sky_light_data.size = angular_diameter; - sky_scene_state.ubo.directional_light_count++; - if (sky_scene_state.ubo.directional_light_count >= sky_scene_state.max_directional_lights) { - break; - } - } - } - // Check whether the directional_light_buffer changes - bool light_data_dirty = false; - - // Light buffer is dirty if we have fewer or more lights - // If we have fewer lights, make sure that old lights are disabled - 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); - - 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; - } - } - } - - //setup fog variables - sky_scene_state.ubo.volumetric_fog_enabled = false; - if (p_render_buffers.is_valid()) { - if (p_scene_render->render_buffers_has_volumetric_fog(p_render_buffers)) { - sky_scene_state.ubo.volumetric_fog_enabled = true; - - float fog_end = p_scene_render->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; - } - - float fog_detail_spread = p_scene_render->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.fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers); - } - } - - sky_scene_state.ubo.z_far = p_projection.get_z_far(); - sky_scene_state.ubo.fog_enabled = p_env->fog_enabled; - sky_scene_state.ubo.fog_density = p_env->fog_density; - sky_scene_state.ubo.fog_aerial_perspective = p_env->fog_aerial_perspective; - Color fog_color = p_env->fog_light_color.srgb_to_linear(); - float fog_energy = p_env->fog_light_energy; - 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 = p_env->fog_sun_scatter; - - RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo); -} - -void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) { - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - ERR_FAIL_COND(!p_env); - - Sky *sky = get_sky(p_env->sky); - ERR_FAIL_COND(!sky); - - RID sky_material = sky_get_material(p_env->sky); - - SkyMaterialData *material = nullptr; - - if (sky_material.is_valid()) { - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - sky_material = sky_shader.default_material; - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - } - - ERR_FAIL_COND(!material); - - SkyShaderData *shader_data = material->shader_data; - - ERR_FAIL_COND(!shader_data); - - float multiplier = p_env->bg_energy; - - bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY; - RS::SkyMode sky_mode = sky->mode; - - if (sky_mode == RS::SKY_MODE_AUTOMATIC) { - if (shader_data->uses_time || shader_data->uses_position) { - update_single_frame = true; - sky_mode = RS::SKY_MODE_REALTIME; - } else if (shader_data->uses_light || shader_data->ubo_size > 0) { - update_single_frame = false; - sky_mode = RS::SKY_MODE_INCREMENTAL; - } else { - update_single_frame = true; - sky_mode = RS::SKY_MODE_QUALITY; - } - } - - if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) { - // On the first frame after creating sky, rebuild in single frame - update_single_frame = true; - sky_mode = RS::SKY_MODE_QUALITY; - } - - int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size(); - - // Update radiance cubemap - if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) { - static const Vector3 view_normals[6] = { - Vector3(+1, 0, 0), - Vector3(-1, 0, 0), - Vector3(0, +1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1) - }; - static const Vector3 view_up[6] = { - Vector3(0, -1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1), - Vector3(0, -1, 0), - Vector3(0, -1, 0) - }; - - Projection cm; - cm.set_perspective(90, 1, 0.01, 10.0); - Projection correction; - correction.set_depth_correction(true); - cm = correction * cm; - - if (shader_data->uses_quarter_res) { - RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter Res Cubemap"); - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; - - Vector clear_colors; - clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID cubemap_draw_list; - - for (int i = 0; i < 6; i++) { - Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd); - - 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); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier); - RD::get_singleton()->draw_list_end(); - } - RD::get_singleton()->draw_command_end_label(); - } - - if (shader_data->uses_half_res) { - RD::get_singleton()->draw_command_begin_label("Render Sky to Half Res Cubemap"); - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; - - Vector clear_colors; - clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID cubemap_draw_list; - - for (int i = 0; i < 6; i++) { - Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd); - - 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); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier); - RD::get_singleton()->draw_list_end(); - } - RD::get_singleton()->draw_command_end_label(); - } - - RD::DrawListID cubemap_draw_list; - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; - - RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap"); - for (int i = 0; i < 6; i++) { - Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd); - - 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); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier); - RD::get_singleton()->draw_list_end(); - } - RD::get_singleton()->draw_command_end_label(); - - if (sky_mode == RS::SKY_MODE_REALTIME) { - sky->reflection.create_reflection_fast_filter(sky_use_cubemap_array); - if (sky_use_cubemap_array) { - sky->reflection.update_reflection_mipmaps(0, sky->reflection.layers.size()); - } - } else { - if (update_single_frame) { - for (int i = 1; i < max_processing_layer; i++) { - sky->reflection.create_reflection_importance_sample(sky_use_cubemap_array, 10, i, sky_ggx_samples_quality); - } - if (sky_use_cubemap_array) { - sky->reflection.update_reflection_mipmaps(0, sky->reflection.layers.size()); - } - } else { - if (sky_use_cubemap_array) { - // Multi-Frame so just update the first array level - sky->reflection.update_reflection_mipmaps(0, 1); - } - } - sky->processing_layer = 1; - } - - sky->reflection.dirty = false; - - } else { - if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) { - sky->reflection.create_reflection_importance_sample(sky_use_cubemap_array, 10, sky->processing_layer, sky_ggx_samples_quality); - - if (sky_use_cubemap_array) { - sky->reflection.update_reflection_mipmaps(sky->processing_layer, sky->processing_layer + 1); - } - - sky->processing_layer++; - } - } -} - -void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time) { - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - ERR_FAIL_COND(!p_env); - - ERR_FAIL_COND(p_view_count == 0); - ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); - - Sky *sky = get_sky(p_env->sky); - - SkyMaterialData *material = nullptr; - RID sky_material; - - RS::EnvironmentBG background = p_env->background; - - if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { - ERR_FAIL_COND(!sky); - sky_material = sky_get_material(p_env->sky); - - if (sky_material.is_valid()) { - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - sky_material = sky_shader.default_material; - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - } - } - - if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { - sky_material = sky_scene_state.fog_material; - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - } - - ERR_FAIL_COND(!material); - - SkyShaderData *shader_data = material->shader_data; - - ERR_FAIL_COND(!shader_data); - - Basis sky_transform = p_env->sky_orientation; - sky_transform.invert(); - - float multiplier = p_env->bg_energy; - float custom_fov = p_env->sky_custom_fov; - - // Camera - Projection camera; - uint32_t view_count = p_view_count; - const Projection *projections = p_projections; - - if (custom_fov) { - // With custom fov we don't support stereo... - float near_plane = p_projections[0].get_z_near(); - float far_plane = p_projections[0].get_z_far(); - float aspect = p_projections[0].get_aspect(); - - camera.set_perspective(custom_fov, aspect, near_plane, far_plane); - - view_count = 1; - projections = &camera; - } - - sky_transform = sky_transform * p_transform.basis; - - if (shader_data->uses_quarter_res) { - PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES]; - - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd); - - Vector clear_colors; - 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); - _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0); - RD::get_singleton()->draw_list_end(); - } - - if (shader_data->uses_half_res) { - PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES]; - - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd); - - Vector clear_colors; - 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); - _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0); - RD::get_singleton()->draw_list_end(); - } - - PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND]; - - RID texture_uniform_set; - if (sky) { - texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd); - } 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); - _render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0); - RD::get_singleton()->draw_list_end(); -} - -void RendererSceneSkyRD::update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) { - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - ERR_FAIL_COND(!p_env); - - ERR_FAIL_COND(p_view_count == 0); - ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); - - Sky *sky = get_sky(p_env->sky); - ERR_FAIL_COND(!sky); - - SkyMaterialData *material = nullptr; - RID sky_material; - - sky_material = sky_get_material(p_env->sky); - - if (sky_material.is_valid()) { - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - sky_material = sky_shader.default_material; - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - } - - ERR_FAIL_COND(!material); - - SkyShaderData *shader_data = material->shader_data; - - ERR_FAIL_COND(!shader_data); - - Basis sky_transform = p_env->sky_orientation; - sky_transform.invert(); - - float multiplier = p_env->bg_energy; - float custom_fov = p_env->sky_custom_fov; - - // Camera - Projection camera; - uint32_t view_count = p_view_count; - const Projection *projections = p_projections; - - if (custom_fov) { - // With custom fov we don't support stereo... - float near_plane = p_projections[0].get_z_near(); - float far_plane = p_projections[0].get_z_far(); - float aspect = p_projections[0].get_aspect(); - - camera.set_perspective(custom_fov, aspect, near_plane, far_plane); - - view_count = 1; - projections = &camera; - } - - sky_transform = p_transform.basis * sky_transform; - - if (shader_data->uses_quarter_res) { - PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES]; - - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd); - - Vector clear_colors; - 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); - _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier); - RD::get_singleton()->draw_list_end(); - } - - if (shader_data->uses_half_res) { - PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES]; - - RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd); - - Vector clear_colors; - 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); - _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier); - RD::get_singleton()->draw_list_end(); - } -} - -void RendererSceneSkyRD::draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) { - RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - ERR_FAIL_COND(!p_env); - - ERR_FAIL_COND(p_view_count == 0); - ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); - - Sky *sky = get_sky(p_env->sky); - - SkyMaterialData *material = nullptr; - RID sky_material; - - RS::EnvironmentBG background = p_env->background; - - if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { - ERR_FAIL_COND(!sky); - sky_material = sky_get_material(p_env->sky); - - if (sky_material.is_valid()) { - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - sky_material = sky_shader.default_material; - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - } - } - - if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { - sky_material = sky_scene_state.fog_material; - material = static_cast(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY)); - } - - ERR_FAIL_COND(!material); - - SkyShaderData *shader_data = material->shader_data; - - ERR_FAIL_COND(!shader_data); - - Basis sky_transform = p_env->sky_orientation; - sky_transform.invert(); - - float multiplier = p_env->bg_energy; - float custom_fov = p_env->sky_custom_fov; - - // Camera - Projection camera; - uint32_t view_count = p_view_count; - const Projection *projections = p_projections; - - if (custom_fov) { - // With custom fov we don't support stereo... - float near_plane = p_projections[0].get_z_near(); - float far_plane = p_projections[0].get_z_far(); - float aspect = p_projections[0].get_aspect(); - - camera.set_perspective(custom_fov, aspect, near_plane, far_plane); - - view_count = 1; - projections = &camera; - } - - sky_transform = p_transform.basis * sky_transform; - - PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND]; - - RID texture_uniform_set; - if (sky) { - texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd); - } else { - texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set; - } - - _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier); -} - -void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) { - if (!p_sky->dirty) { - p_sky->dirty = true; - p_sky->dirty_list = dirty_sky_list; - dirty_sky_list = p_sky; - } -} - -void RendererSceneSkyRD::update_dirty_skys() { - Sky *sky = dirty_sky_list; - - while (sky) { - bool texture_set_dirty = false; - //update sky configuration if texture is missing - - if (sky->radiance.is_null()) { - int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; - - uint32_t w = sky->radiance_size, h = sky->radiance_size; - int layers = roughness_layers; - if (sky->mode == RS::SKY_MODE_REALTIME) { - layers = 8; - if (roughness_layers != 8) { - WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections"); - } - } - - if (sky_use_cubemap_array) { - //array (higher quality, 6 times more memory) - RD::TextureFormat tf; - tf.array_layers = layers * 6; - tf.format = texture_format; - tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; - tf.mipmaps = mipmaps; - tf.width = w; - tf.height = h; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); - - } else { - //regular cubemap, lower quality (aliasing, less memory) - RD::TextureFormat tf; - tf.array_layers = 6; - tf.format = texture_format; - tf.texture_type = RD::TEXTURE_TYPE_CUBE; - tf.mipmaps = MIN(mipmaps, layers); - tf.width = w; - tf.height = h; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format); - } - texture_set_dirty = true; - } - - // 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 = texture_format; - tformat.width = sky->screen_size.x / 2; - tformat.height = sky->screen_size.y / 2; - tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.texture_type = RD::TEXTURE_TYPE_2D; - - sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); - Vector texs; - texs.push_back(sky->half_res_pass); - sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); - texture_set_dirty = true; - } - - if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { - RD::TextureFormat tformat; - tformat.format = texture_format; - tformat.width = sky->screen_size.x / 4; - tformat.height = sky->screen_size.y / 4; - tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.texture_type = RD::TEXTURE_TYPE_2D; - - sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); - Vector texs; - texs.push_back(sky->quarter_res_pass); - sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); - texture_set_dirty = true; - } - - if (texture_set_dirty) { - for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) { - if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) { - RD::get_singleton()->free(sky->texture_uniform_sets[i]); - sky->texture_uniform_sets[i] = RID(); - } - } - } - - sky->reflection.dirty = true; - sky->processing_layer = 0; - - Sky *next = sky->dirty_list; - sky->dirty_list = nullptr; - sky->dirty = false; - sky = next; - } - - dirty_sky_list = nullptr; -} - -RID RendererSceneSkyRD::sky_get_material(RID p_sky) const { - Sky *sky = get_sky(p_sky); - ERR_FAIL_COND_V(!sky, RID()); - - return sky->material; -} - -RID RendererSceneSkyRD::allocate_sky_rid() { - return sky_owner.allocate_rid(); -} - -void RendererSceneSkyRD::initialize_sky_rid(RID p_rid) { - sky_owner.initialize_rid(p_rid, Sky()); -} - -RendererSceneSkyRD::Sky *RendererSceneSkyRD::get_sky(RID p_sky) const { - return sky_owner.get_or_null(p_sky); -} - -void RendererSceneSkyRD::free_sky(RID p_sky) { - Sky *sky = get_sky(p_sky); - ERR_FAIL_COND(!sky); - - sky->free(); - sky_owner.free(p_sky); -} - -void RendererSceneSkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { - Sky *sky = get_sky(p_sky); - ERR_FAIL_COND(!sky); - - if (sky->set_radiance_size(p_radiance_size)) { - invalidate_sky(sky); - } -} - -void RendererSceneSkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { - Sky *sky = get_sky(p_sky); - ERR_FAIL_COND(!sky); - - if (sky->set_mode(p_mode)) { - invalidate_sky(sky); - } -} - -void RendererSceneSkyRD::sky_set_material(RID p_sky, RID p_material) { - Sky *sky = get_sky(p_sky); - ERR_FAIL_COND(!sky); - - if (sky->set_material(p_material)) { - invalidate_sky(sky); - } -} - -Ref RendererSceneSkyRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { - Sky *sky = get_sky(p_sky); - ERR_FAIL_COND_V(!sky, Ref()); - - update_dirty_skys(); - - return sky->bake_panorama(p_energy, p_bake_irradiance ? roughness_layers : 0, p_size); -} - -RID RendererSceneSkyRD::sky_get_radiance_texture_rd(RID p_sky) const { - Sky *sky = get_sky(p_sky); - ERR_FAIL_COND_V(!sky, RID()); - - return sky->radiance; -} diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h deleted file mode 100644 index dd63dc95ae..0000000000 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ /dev/null @@ -1,321 +0,0 @@ -/*************************************************************************/ -/* renderer_scene_sky_rd.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RENDERER_SCENE_SKY_RD_H -#define RENDERER_SCENE_SKY_RD_H - -#include "core/templates/rid_owner.h" -#include "servers/rendering/renderer_compositor.h" -#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" -#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" -#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h" -#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" -#include "servers/rendering/renderer_scene_render.h" -#include "servers/rendering/rendering_device.h" -#include "servers/rendering/shader_compiler.h" - -// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound -class RendererSceneRenderRD; - -class RendererSceneSkyRD { -public: - enum SkySet { - SKY_SET_UNIFORMS, - SKY_SET_MATERIAL, - SKY_SET_TEXTURES, - SKY_SET_FOG, - SKY_SET_MAX - }; - - // Skys need less info from Directional Lights than the normal shaders - struct SkyDirectionalLightData { - float direction[3]; - float energy; - float color[3]; - float size; - uint32_t enabled; - uint32_t pad[3]; - }; - -private: - RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - - RID index_buffer; - RID index_array; - - enum SkyTextureSetVersion { - SKY_TEXTURE_SET_BACKGROUND, - SKY_TEXTURE_SET_HALF_RES, - SKY_TEXTURE_SET_QUARTER_RES, - SKY_TEXTURE_SET_CUBEMAP, - SKY_TEXTURE_SET_CUBEMAP_HALF_RES, - SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, - SKY_TEXTURE_SET_MAX - }; - - enum SkyVersion { - SKY_VERSION_BACKGROUND, - SKY_VERSION_HALF_RES, - SKY_VERSION_QUARTER_RES, - SKY_VERSION_CUBEMAP, - SKY_VERSION_CUBEMAP_HALF_RES, - SKY_VERSION_CUBEMAP_QUARTER_RES, - - SKY_VERSION_BACKGROUND_MULTIVIEW, - SKY_VERSION_HALF_RES_MULTIVIEW, - SKY_VERSION_QUARTER_RES_MULTIVIEW, - - SKY_VERSION_MAX - }; - - struct SkyPushConstant { - float orientation[12]; // 48 - 48 - float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 80 - float position[3]; // 12 - 92 - float multiplier; // 4 - 96 - float time; // 4 - 100 - float luminance_multiplier; // 4 - 104 - float pad[2]; // 8 - 112 // Using pad to align on 16 bytes - // 128 is the max size of a push constant. We can replace "pad" but we can't add any more. - }; - - struct SkyShaderData : public RendererRD::ShaderData { - bool valid = false; - RID version; - - PipelineCacheRD pipelines[SKY_VERSION_MAX]; - HashMap uniforms; - Vector texture_uniforms; - - Vector ubo_offsets; - uint32_t ubo_size = 0; - - String path; - String code; - HashMap> default_texture_params; - - bool uses_time = false; - bool uses_position = false; - bool uses_half_res = false; - bool uses_quarter_res = false; - bool uses_light = false; - - virtual void set_code(const String &p_Code); - virtual void set_path_hint(const String &p_hint); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); - virtual void get_param_list(List *p_param_list) const; - virtual void get_instance_param_list(List *p_param_list) const; - virtual bool is_param_texture(const StringName &p_param) const; - virtual bool is_animated() const; - virtual bool casts_shadows() const; - virtual Variant get_default_parameter(const StringName &p_parameter) const; - virtual RS::ShaderNativeSourceCode get_native_source_code() const; - - SkyShaderData() {} - virtual ~SkyShaderData(); - }; - - void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier); - -public: - struct SkySceneState { - struct UBO { - uint32_t volumetric_fog_enabled; - float volumetric_fog_inv_length; - float volumetric_fog_detail_spread; - - float fog_aerial_perspective; - - 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 = nullptr; - SkyDirectionalLightData *last_frame_directional_lights = nullptr; - uint32_t max_directional_lights; - uint32_t last_frame_directional_light_count; - RID directional_light_buffer; - 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 ReflectionData { - struct Layer { - struct Mipmap { - RID framebuffers[6]; - RID views[6]; - Size2i size; - }; - Vector mipmaps; //per-face view - Vector views; // per-cubemap view - }; - - struct DownsampleLayer { - struct Mipmap { - RID view; - Size2i size; - - // for mobile only - RID views[6]; - RID framebuffers[6]; - }; - Vector mipmaps; - }; - - RID radiance_base_cubemap; //cubemap for first layer, first cubemap - RID downsampled_radiance_cubemap; - DownsampleLayer downsampled_layer; - RID coefficient_buffer; - - bool dirty = true; - - Vector layers; - - void clear_reflection_data(); - void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format); - void create_reflection_fast_filter(bool p_use_arrays); - void create_reflection_importance_sample(bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality); - void update_reflection_mipmaps(int p_start, int p_end); - }; - - /* Sky shader */ - - struct SkyShader { - SkyShaderRD shader; - ShaderCompiler compiler; - - RID default_shader; - RID default_material; - RID default_shader_rd; - } sky_shader; - - struct SkyMaterialData : public RendererRD::MaterialData { - SkyShaderData *shader_data = nullptr; - RID uniform_set; - bool uniform_set_updated; - - virtual void set_render_priority(int p_priority) {} - virtual void set_next_pass(RID p_pass) {} - virtual bool update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~SkyMaterialData(); - }; - - struct Sky { - RID radiance; - RID half_res_pass; - RID half_res_framebuffer; - RID quarter_res_pass; - RID quarter_res_framebuffer; - Size2i screen_size; - - RID texture_uniform_sets[SKY_TEXTURE_SET_MAX]; - RID uniform_set; - - RID material; - RID uniform_buffer; - - int radiance_size = 256; - - RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC; - - ReflectionData reflection; - bool dirty = false; - int processing_layer = 0; - Sky *dirty_list = nullptr; - - //State to track when radiance cubemap needs updating - SkyMaterialData *prev_material = nullptr; - Vector3 prev_position; - float prev_time; - - void free(); - - RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd); - bool set_radiance_size(int p_radiance_size); - bool set_mode(RS::SkyMode p_mode); - bool set_material(RID p_material); - Ref bake_panorama(float p_energy, int p_roughness_layers, const Size2i &p_size); - }; - - uint32_t sky_ggx_samples_quality; - bool sky_use_cubemap_array; - Sky *dirty_sky_list = nullptr; - mutable RID_Owner sky_owner; - int roughness_layers; - - RendererRD::ShaderData *_create_sky_shader_func(); - static RendererRD::ShaderData *_create_sky_shader_funcs(); - - RendererRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); - static RendererRD::MaterialData *_create_sky_material_funcs(RendererRD::ShaderData *p_shader); - - RendererSceneSkyRD(); - void init(); - void set_texture_format(RD::DataFormat p_texture_format); - ~RendererSceneSkyRD(); - - void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const PagedArray &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); - void update(RendererSceneEnvironmentRD *p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); - void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time); // only called by clustered renderer - void update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); - void draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); - - void invalidate_sky(Sky *p_sky); - void update_dirty_skys(); - - RID sky_get_material(RID p_sky) const; - - RID allocate_sky_rid(); - void initialize_sky_rid(RID p_rid); - Sky *get_sky(RID p_sky) const; - void free_sky(RID p_sky); - void sky_set_radiance_size(RID p_sky, int p_radiance_size); - void sky_set_mode(RID p_sky, RS::SkyMode p_mode); - void sky_set_material(RID p_sky, RID p_material); - Ref sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size); - - RID sky_get_radiance_texture_rd(RID p_sky) const; -}; - -#endif // RENDERER_SCENE_SKY_RD_H diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl new file mode 100644 index 0000000000..5b4594da99 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl @@ -0,0 +1,253 @@ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#define MAX_VIEWS 2 + +#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview) +#extension GL_EXT_multiview : enable +#endif + +layout(location = 0) out vec2 uv_interp; + +layout(push_constant, std430) uniform Params { + mat3 orientation; + vec4 projections[MAX_VIEWS]; + vec4 position_multiplier; + float time; + float luminance_multiplier; + float pad[2]; +} +params; + +void main() { + vec2 base_arr[4] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(1.0, -1.0)); + uv_interp = base_arr[gl_VertexIndex]; + gl_Position = vec4(uv_interp, 1.0, 1.0); +} + +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#ifdef USE_MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +// !BAS! This needs to become an input once we implement our fallback! +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#else // USE_MULTIVIEW +// Set to zero, not supported in non stereo +#define ViewIndex 0 +#endif //USE_MULTIVIEW + +#define M_PI 3.14159265359 +#define MAX_VIEWS 2 + +layout(location = 0) in vec2 uv_interp; + +layout(push_constant, std430) uniform Params { + mat3 orientation; + vec4 projections[MAX_VIEWS]; + vec4 position_multiplier; + float time; + float luminance_multiplier; + float pad[2]; +} +params; + +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + +layout(set = 0, binding = 0) uniform sampler material_samplers[12]; + +layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + +layout(set = 0, binding = 2, std140) uniform SceneData { + bool volumetric_fog_enabled; + float volumetric_fog_inv_length; + float volumetric_fog_detail_spread; + + float fog_aerial_perspective; + + 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 MATERIAL_UNIFORMS_USED +layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ +#MATERIAL_UNIFORMS +} material; +#endif + +layout(set = 2, binding = 0) uniform textureCube radiance; +#ifdef USE_CUBEMAP_PASS +layout(set = 2, binding = 1) uniform textureCube half_res; +layout(set = 2, binding = 2) uniform textureCube quarter_res; +#else +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 +#define AT_CUBEMAP_PASS false +#endif + +#ifdef USE_HALF_RES_PASS +#define AT_HALF_RES_PASS true +#else +#define AT_HALF_RES_PASS false +#endif + +#ifdef USE_QUARTER_RES_PASS +#define AT_QUARTER_RES_PASS true +#else +#define AT_QUARTER_RES_PASS false +#endif + +#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 sky_color) { + vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective); + + if (scene_data.fog_sun_scatter > 0.001) { + vec4 sun_scatter = vec4(0.0); + 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; + cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y; + cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w; + cube_normal = mat3(params.orientation) * cube_normal; + cube_normal = normalize(cube_normal); + + vec2 uv = uv_interp * 0.5 + 0.5; + + vec2 panorama_coords = vec2(atan(cube_normal.x, -cube_normal.z), acos(cube_normal.y)); + + if (panorama_coords.x < 0.0) { + panorama_coords.x += M_PI * 2.0; + } + + panorama_coords /= vec2(M_PI * 2.0, M_PI); + + vec3 color = vec3(0.0, 0.0, 0.0); + float alpha = 1.0; // Only available to subpasses + vec4 half_res_color = vec4(1.0); + vec4 quarter_res_color = vec4(1.0); + vec4 custom_fog = vec4(0.0); + +#ifdef USE_CUBEMAP_PASS +#ifdef USES_HALF_RES_COLOR + half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) * params.luminance_multiplier; +#endif +#ifdef USES_QUARTER_RES_COLOR + quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) * params.luminance_multiplier; +#endif +#else +#ifdef USES_HALF_RES_COLOR + half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier; +#endif +#ifdef USES_QUARTER_RES_COLOR + quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier; +#endif +#endif + + { + +#CODE : SKY + + } + + frag_color.rgb = color * params.position_multiplier.w; + frag_color.a = alpha; + +#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS) + + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + if (scene_data.fog_enabled) { + vec4 fog = fog_process(cube_normal, frag_color.rgb); + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + } + + if (scene_data.volumetric_fog_enabled) { + vec4 fog = volumetric_fog_process(uv); + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + } + + if (custom_fog.a > 0.0) { + frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_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) { + frag_color.a = 0.0; + } + + // For mobile renderer we're dividing by 2.0 as we're using a UNORM buffer + frag_color.rgb = frag_color.rgb / params.luminance_multiplier; +} diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl new file mode 100644 index 0000000000..fb3c725b1f --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl @@ -0,0 +1,309 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; + +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + +#define DENSITY_SCALE 1024.0 + +#include "../cluster_data_inc.glsl" +#include "../light_data_inc.glsl" + +#define M_PI 3.14159265359 + +layout(set = 0, binding = 1) uniform sampler material_samplers[12]; + +layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + +layout(push_constant, std430) uniform Params { + vec3 position; + float pad; + + vec3 extents; + float pad2; + + ivec3 corner; + uint shape; + + mat4 transform; +} +params; + +#ifdef MOLTENVK_USED +layout(set = 1, binding = 1) volatile buffer emissive_only_map_buffer { + uint emissive_only_map[]; +}; +#else +layout(r32ui, set = 1, binding = 1) uniform volatile uimage3D emissive_only_map; +#endif + +layout(set = 1, binding = 2, std140) uniform SceneParams { + vec2 fog_frustum_size_begin; + vec2 fog_frustum_size_end; + + float fog_frustum_end; + float z_near; // + float z_far; // + float time; + + ivec3 fog_volume_size; + uint directional_light_count; // + + bool use_temporal_reprojection; + uint temporal_frame; + float detail_spread; + float temporal_blend; + + mat4 to_prev_view; + mat4 transform; +} +scene_params; + +#ifdef MOLTENVK_USED +layout(set = 1, binding = 3) volatile buffer density_only_map_buffer { + uint density_only_map[]; +}; +layout(set = 1, binding = 4) volatile buffer light_only_map_buffer { + uint light_only_map[]; +}; +#else +layout(r32ui, set = 1, binding = 3) uniform volatile uimage3D density_only_map; +layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map; +#endif + +#ifdef MATERIAL_UNIFORMS_USED +layout(set = 2, binding = 0, std140) uniform MaterialUniforms{ +#MATERIAL_UNIFORMS +} material; +#endif + +#GLOBALS + +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, scene_params.detail_spread); + return scene_params.fog_frustum_end * d; +} + +#define TEMPORAL_FRAMES 16 + +const vec3 halton_map[TEMPORAL_FRAMES] = vec3[]( + vec3(0.5, 0.33333333, 0.2), + vec3(0.25, 0.66666667, 0.4), + vec3(0.75, 0.11111111, 0.6), + vec3(0.125, 0.44444444, 0.8), + vec3(0.625, 0.77777778, 0.04), + vec3(0.375, 0.22222222, 0.24), + vec3(0.875, 0.55555556, 0.44), + vec3(0.0625, 0.88888889, 0.64), + vec3(0.5625, 0.03703704, 0.84), + vec3(0.3125, 0.37037037, 0.08), + vec3(0.8125, 0.7037037, 0.28), + vec3(0.1875, 0.14814815, 0.48), + vec3(0.6875, 0.48148148, 0.68), + vec3(0.4375, 0.81481481, 0.88), + vec3(0.9375, 0.25925926, 0.12), + vec3(0.03125, 0.59259259, 0.32)); + +void main() { + vec3 fog_cell_size = 1.0 / vec3(scene_params.fog_volume_size); + + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz) + params.corner; + if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) { + return; //do not compute + } +#ifdef MOLTENVK_USED + uint lpos = pos.z * scene_params.fog_volume_size.x * scene_params.fog_volume_size.y + pos.y * scene_params.fog_volume_size.x + pos.x; +#endif + + vec3 posf = vec3(pos); + + 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, scene_params.detail_spread); + + vec3 view_pos; + view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z)); + view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z; + view_pos.y = -view_pos.y; + + if (scene_params.use_temporal_reprojection) { + vec3 prev_view = (scene_params.to_prev_view * vec4(view_pos, 1.0)).xyz; + //undo transform into prev view + prev_view.y = -prev_view.y; + //z back to unit size + prev_view.z /= -scene_params.fog_frustum_end; + //xy back to unit size + prev_view.xy /= mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(prev_view.z)); + prev_view.xy = prev_view.xy * 0.5 + 0.5; + //z back to unspread value + prev_view.z = pow(prev_view.z, 1.0 / scene_params.detail_spread); + + if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) { + //reprojectinon fits + // Since we can reproject, now we must jitter the current view pos. + // This is done here because cells that can't reproject should not jitter. + + fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[scene_params.temporal_frame]; //center of voxels, offset by halton table + fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread); + + view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z)); + view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z; + view_pos.y = -view_pos.y; + } + } + + float density = 0.0; + vec3 emission = vec3(0.0); + vec3 albedo = vec3(0.0); + + float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1)); + + vec4 world = scene_params.transform * vec4(view_pos, 1.0); + world.xyz /= world.w; + + vec3 uvw = fog_unit_pos; + + vec4 local_pos = params.transform * world; + local_pos.xyz /= local_pos.w; + + float sdf = -1.0; + if (params.shape == 0) { + // Ellipsoid + // https://www.shadertoy.com/view/tdS3DG + float k0 = length(local_pos.xyz / params.extents); + float k1 = length(local_pos.xyz / (params.extents * params.extents)); + sdf = k0 * (k0 - 1.0) / k1; + } else if (params.shape == 1) { + // Cone + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + + // Compute the cone angle automatically to fit within the volume's extents. + float inv_height = 1.0 / max(0.001, params.extents.y); + float radius = 1.0 / max(0.001, (min(params.extents.x, params.extents.z) * 0.5)); + float hypotenuse = sqrt(radius * radius + inv_height * inv_height); + float rsin = radius / hypotenuse; + float rcos = inv_height / hypotenuse; + vec2 c = vec2(rsin, rcos); + + float q = length(local_pos.xz); + sdf = max(dot(c, vec2(q, local_pos.y - params.extents.y)), -params.extents.y - local_pos.y); + } else if (params.shape == 2) { + // Cylinder + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + vec2 d = abs(vec2(length(local_pos.xz), local_pos.y)) - vec2(min(params.extents.x, params.extents.z), params.extents.y); + sdf = min(max(d.x, d.y), 0.0) + length(max(d, 0.0)); + } else if (params.shape == 3) { + // Box + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + vec3 q = abs(local_pos.xyz) - params.extents; + sdf = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0); + } + + float cull_mask = 1.0; //used to cull cells that do not contribute + if (params.shape <= 3) { +#ifndef SDF_USED + cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf); +#endif + uvw = clamp((local_pos.xyz + params.extents) / (2.0 * params.extents), 0.0, 1.0); + } + + if (cull_mask > 0.0) { + { +#CODE : FOG + } + +#ifdef DENSITY_USED + density *= cull_mask; + if (abs(density) > 0.001) { + int final_density = int(density * DENSITY_SCALE); +#ifdef MOLTENVK_USED + atomicAdd(density_only_map[lpos], uint(final_density)); +#else + imageAtomicAdd(density_only_map, pos, uint(final_density)); +#endif + +#ifdef EMISSION_USED + { + emission *= clamp(density, 0.0, 1.0); + emission = clamp(emission, vec3(0.0), vec3(4.0)); + // Scale to fit into R11G11B10 with a range of 0-4 + uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0); + // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint + uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b; +#ifdef MOLTENVK_USED + uint prev_emission = atomicAdd(emissive_only_map[lpos], final_emission); +#else + uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission); +#endif + + // Adding can lead to colors overflowing, so validate + uvec3 prev_emission_u = uvec3(prev_emission >> 21, (prev_emission << 11) >> 21, prev_emission % 1024); + uint add_emission = final_emission + prev_emission; + uvec3 add_emission_u = uvec3(add_emission >> 21, (add_emission << 11) >> 21, add_emission % 1024); + + bvec3 overflowing = lessThan(add_emission_u, prev_emission_u + emission_u); + + if (any(overflowing)) { + uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing); + uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b; +#ifdef MOLTENVK_USED + atomicOr(emissive_only_map[lpos], force_max); +#else + imageAtomicOr(emissive_only_map, pos, force_max); +#endif + } + } +#endif +#ifdef ALBEDO_USED + { + vec3 scattering = albedo * clamp(density, 0.0, 1.0); + scattering = clamp(scattering, vec3(0.0), vec3(1.0)); + uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0); + // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint + uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b; +#ifdef MOLTENVK_USED + uint prev_scattering = atomicAdd(light_only_map[lpos], final_scattering); +#else + uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering); +#endif + + // Adding can lead to colors overflowing, so validate + uvec3 prev_scattering_u = uvec3(prev_scattering >> 21, (prev_scattering << 11) >> 21, prev_scattering % 1024); + uint add_scattering = final_scattering + prev_scattering; + uvec3 add_scattering_u = uvec3(add_scattering >> 21, (add_scattering << 11) >> 21, add_scattering % 1024); + + bvec3 overflowing = lessThan(add_scattering_u, prev_scattering_u + scattering_u); + + if (any(overflowing)) { + uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing); + uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b; +#ifdef MOLTENVK_USED + atomicOr(light_only_map[lpos], force_max); +#else + imageAtomicOr(light_only_map, pos, force_max); +#endif + } + } +#endif // ALBEDO_USED + } +#endif // DENSITY_USED + } +} diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl new file mode 100644 index 0000000000..e74cfad65c --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -0,0 +1,782 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +/* Do not use subgroups here, seems there is not much advantage and causes glitches +#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) +#extension GL_KHR_shader_subgroup_ballot: enable +#extension GL_KHR_shader_subgroup_arithmetic: enable + +#define USE_SUBGROUPS +#endif +*/ + +#ifdef MODE_DENSITY +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; +#else +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +#endif + +#include "../cluster_data_inc.glsl" +#include "../light_data_inc.glsl" + +#define M_PI 3.14159265359 + +#define DENSITY_SCALE 1024.0 + +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 OmniLights { + LightData data[]; +} +omni_lights; + +layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { + LightData data[]; +} +spot_lights; + +layout(set = 0, binding = 5, std140) uniform DirectionalLights { + DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} +directional_lights; + +layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer { + uint data[]; +} +cluster_buffer; + +layout(set = 0, binding = 7) uniform sampler linear_sampler; + +#ifdef MODE_DENSITY +layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map; +#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_COPY +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 + +#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_VOXEL_GI_INSTANCES 8 + +struct VoxelGIData { + mat4 xform; // 64 - 64 + + vec3 bounds; // 12 - 76 + float dynamic_range; // 4 - 80 + + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + bool blend_ambient; // 4 - 92 + uint mipmaps; // 4 - 96 +}; + +layout(set = 0, binding = 11, std140) uniform VoxelGIs { + VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; +} +voxel_gi_instances; + +layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; + +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 SDFVoxelGICascadeData { + 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; + + SDFVoxelGICascadeData 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(set = 0, binding = 14, std140) uniform Params { + vec2 fog_frustum_size_begin; + vec2 fog_frustum_size_end; + + float fog_frustum_end; + float ambient_inject; + float z_far; + int filter_axis; + + vec3 ambient_color; + float sky_contribution; + + ivec3 fog_volume_size; + uint directional_light_count; + + vec3 base_emission; + float base_density; + + vec3 base_scattering; + float phase_g; + + float detail_spread; + float gi_inject; + uint max_voxel_gi_instances; + uint cluster_type_size; + + vec2 screen_size; + uint cluster_shift; + uint cluster_width; + + uint max_cluster_element_count_div_32; + bool use_temporal_reprojection; + uint temporal_frame; + float temporal_blend; + + mat3x4 cam_rotation; + mat4 to_prev_view; + + mat3 radiance_inverse_xform; +} +params; +#ifndef MODE_COPY +layout(set = 0, binding = 15) uniform texture3D prev_density_texture; + +#ifdef MOLTENVK_USED +layout(set = 0, binding = 16) buffer density_only_map_buffer { + uint density_only_map[]; +}; +layout(set = 0, binding = 17) buffer light_only_map_buffer { + uint light_only_map[]; +}; +layout(set = 0, binding = 18) buffer emissive_only_map_buffer { + uint emissive_only_map[]; +}; +#else +layout(r32ui, set = 0, binding = 16) uniform uimage3D density_only_map; +layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map; +layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map; +#endif + +#ifdef USE_RADIANCE_CUBEMAP_ARRAY +layout(set = 0, binding = 19) uniform textureCubeArray sky_texture; +#else +layout(set = 0, binding = 19) uniform textureCube sky_texture; +#endif +#endif // MODE_COPY + +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)); +} + +float get_omni_attenuation(float dist, float inv_range, float decay) { + float nd = dist * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(dist, 0.0001), -decay); +} + +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFF; + item_max = item_min_max >> 16; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} + +float henyey_greenstein(float cos_theta, float g) { + const float k = 0.0795774715459; // 1 / (4 * PI) + return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5)); +} + +#define TEMPORAL_FRAMES 16 + +const vec3 halton_map[TEMPORAL_FRAMES] = vec3[]( + vec3(0.5, 0.33333333, 0.2), + vec3(0.25, 0.66666667, 0.4), + vec3(0.75, 0.11111111, 0.6), + vec3(0.125, 0.44444444, 0.8), + vec3(0.625, 0.77777778, 0.04), + vec3(0.375, 0.22222222, 0.24), + vec3(0.875, 0.55555556, 0.44), + vec3(0.0625, 0.88888889, 0.64), + vec3(0.5625, 0.03703704, 0.84), + vec3(0.3125, 0.37037037, 0.08), + vec3(0.8125, 0.7037037, 0.28), + vec3(0.1875, 0.14814815, 0.48), + vec3(0.6875, 0.48148148, 0.68), + vec3(0.4375, 0.81481481, 0.88), + vec3(0.9375, 0.25925926, 0.12), + vec3(0.03125, 0.59259259, 0.32)); + +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 + } +#ifdef MOLTENVK_USED + uint lpos = pos.z * params.fog_volume_size.x * params.fog_volume_size.y + pos.y * params.fog_volume_size.x + pos.x; +#endif + + 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 + + uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); + uvec2 cluster_pos = screen_pos >> params.cluster_shift; + uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); + //positions in screen are too spread apart, no hopes for optimizing with subgroups + + 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; + + vec4 reprojected_density = vec4(0.0); + float reproject_amount = 0.0; + + if (params.use_temporal_reprojection) { + vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz; + //undo transform into prev view + prev_view.y = -prev_view.y; + //z back to unit size + prev_view.z /= -params.fog_frustum_end; + //xy back to unit size + prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z)); + prev_view.xy = prev_view.xy * 0.5 + 0.5; + //z back to unspread value + prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread); + + if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) { + //reprojectinon fits + + reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0); + reproject_amount = params.temporal_blend; + + // Since we can reproject, now we must jitter the current view pos. + // This is done here because cells that can't reproject should not jitter. + + fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table + + screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); + cluster_pos = screen_pos >> params.cluster_shift; + cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); + //positions in screen are too spread apart, no hopes for optimizing with subgroups + + fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); + + 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; + } + } + + uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0)); + + vec3 total_light = vec3(0.0); + + float total_density = params.base_density; +#ifdef MOLTENVK_USED + uint local_density = density_only_map[lpos]; +#else + uint local_density = imageLoad(density_only_map, pos).x; +#endif + + total_density += float(int(local_density)) / DENSITY_SCALE; + total_density = max(0.0, total_density); + +#ifdef MOLTENVK_USED + uint scattering_u = light_only_map[lpos]; +#else + uint scattering_u = imageLoad(light_only_map, pos).x; +#endif + vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0); + scattering += params.base_scattering * params.base_density; + +#ifdef MOLTENVK_USED + uint emission_u = emissive_only_map[lpos]; +#else + uint emission_u = imageLoad(emissive_only_map, pos).x; +#endif + vec3 emission = vec3(emission_u >> 21, (emission_u << 11) >> 21, emission_u % 1024) / vec3(511.0, 511.0, 255.0); + emission += params.base_emission * 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 + + if (total_density > 0.001) { + 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 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); + + 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(vec3(0.0), vec3(1.0), shadow); + } + + total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot(normalize(view_pos), normalize(directional_lights.data[i].direction)), params.phase_g); + } + + // Compute light from sky + if (params.ambient_inject > 0.0) { + vec3 isotropic = vec3(0.0); + vec3 anisotropic = vec3(0.0); + if (params.sky_contribution > 0.0) { + float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice + vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g); +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb; + anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb; +#else + isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb; + anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + } + + total_light += mix(params.ambient_color, mix(isotropic, anisotropic, abs(params.phase_g)), params.sky_contribution) * params.ambient_inject; + } + + //compute lights from cluster + + { //omni lights + + uint cluster_omni_offset = cluster_offset; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint light_index = 32 * i + bit; + + //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} + + vec3 light_pos = omni_lights.data[light_index].position; + float d = distance(omni_lights.data[light_index].position, view_pos); + float shadow_attenuation = 1.0; + + if (d * omni_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation); + + vec3 light = omni_lights.data[light_index].color; + + if (omni_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 uv_rect = omni_lights.data[light_index].atlas_rect; + vec2 flip_offset = omni_lights.data[light_index].direction.xy; + + vec3 local_vert = (omni_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz; + + float shadow_len = length(local_vert); //need to remember shadow len from here + vec3 shadow_sample = normalize(local_vert); + + if (shadow_sample.z >= 0.0) { + uv_rect.xy += flip_offset; + } + + shadow_sample.z = 1.0 + abs(shadow_sample.z); + vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias); + pos.z *= omni_lights.data[light_index].inv_radius; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade); + } + total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g); + } + } + } + } + + { //spot lights + + uint cluster_spot_offset = cluster_offset + params.cluster_type_size; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + + //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} + + uint light_index = 32 * i + bit; + + vec3 light_pos = spot_lights.data[light_index].position; + vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos; + float d = length(light_rel_vec); + float shadow_attenuation = 1.0; + + if (d * spot_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation); + + vec3 spot_dir = spot_lights.data[light_index].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle)); + attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation); + + vec3 light = spot_lights.data[light_index].color; + + if (spot_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 uv_rect = spot_lights.data[light_index].atlas_rect; + vec2 flip_offset = spot_lights.data[light_index].direction.xy; + + vec3 local_vert = (spot_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz; + + float shadow_len = length(local_vert); //need to remember shadow len from here + vec3 shadow_sample = normalize(local_vert); + + if (shadow_sample.z >= 0.0) { + uv_rect.xy += flip_offset; + } + + shadow_sample.z = 1.0 + abs(shadow_sample.z); + vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - spot_lights.data[light_index].shadow_bias); + pos.z *= spot_lights.data[light_index].inv_radius; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); + } + total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g); + } + } + } + } + + vec3 world_pos = mat3(params.cam_rotation) * view_pos; + + for (uint i = 0; i < params.max_voxel_gi_instances; i++) { + vec3 position = (voxel_gi_instances.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, voxel_gi_instances.data[i].bounds))))) { + position /= voxel_gi_instances.data[i].bounds; + + vec4 light = vec4(0.0); + for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) { + vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j)); + float a = (1.0 - light.a); + light += a * slight; + } + + light.rgb *= voxel_gi_instances.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 + } + + vec4 final_density = vec4(total_light * scattering + emission, total_density); + + final_density = mix(final_density, reprojected_density, reproject_amount); + + imageStore(density_map, pos, final_density); +#ifdef MOLTENVK_USED + density_only_map[lpos] = 0; + light_only_map[lpos] = 0; + emissive_only_map[lpos] = 0; +#else + imageStore(density_only_map, pos, uvec4(0)); + imageStore(light_only_map, pos, uvec4(0)); + imageStore(emissive_only_map, pos, uvec4(0)); +#endif +#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, 0.0, 0.0, 1.0); + float prev_z = 0.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 previous pos + float d = abs(prev_z - z); + //compute transmittance using beer's law + float transmittance = exp(-d * fog.a); + + fog_accum.rgb += ((fog.rgb - fog.rgb * transmittance) / max(fog.a, 0.00001)) * fog_accum.a; + fog_accum.a *= transmittance; + + prev_z = z; + + imageStore(fog_map, fog_pos, vec4(fog_accum.rgb, 1.0 - fog_accum.a)); + } + +#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 +#ifdef MODE_COPY + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); + if (any(greaterThanEqual(pos, params.fog_volume_size))) { + return; //do not compute + } + + imageStore(dest_map, pos, imageLoad(source_map, pos)); + +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl deleted file mode 100644 index 5b4594da99..0000000000 --- a/servers/rendering/renderer_rd/shaders/sky.glsl +++ /dev/null @@ -1,253 +0,0 @@ -#[vertex] - -#version 450 - -#VERSION_DEFINES - -#define MAX_VIEWS 2 - -#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview) -#extension GL_EXT_multiview : enable -#endif - -layout(location = 0) out vec2 uv_interp; - -layout(push_constant, std430) uniform Params { - mat3 orientation; - vec4 projections[MAX_VIEWS]; - vec4 position_multiplier; - float time; - float luminance_multiplier; - float pad[2]; -} -params; - -void main() { - vec2 base_arr[4] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(1.0, -1.0)); - uv_interp = base_arr[gl_VertexIndex]; - gl_Position = vec4(uv_interp, 1.0, 1.0); -} - -#[fragment] - -#version 450 - -#VERSION_DEFINES - -#ifdef USE_MULTIVIEW -#ifdef has_VK_KHR_multiview -#extension GL_EXT_multiview : enable -#define ViewIndex gl_ViewIndex -#else // has_VK_KHR_multiview -// !BAS! This needs to become an input once we implement our fallback! -#define ViewIndex 0 -#endif // has_VK_KHR_multiview -#else // USE_MULTIVIEW -// Set to zero, not supported in non stereo -#define ViewIndex 0 -#endif //USE_MULTIVIEW - -#define M_PI 3.14159265359 -#define MAX_VIEWS 2 - -layout(location = 0) in vec2 uv_interp; - -layout(push_constant, std430) uniform Params { - mat3 orientation; - vec4 projections[MAX_VIEWS]; - vec4 position_multiplier; - float time; - float luminance_multiplier; - float pad[2]; -} -params; - -#define SAMPLER_NEAREST_CLAMP 0 -#define SAMPLER_LINEAR_CLAMP 1 -#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 -#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 -#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 -#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 -#define SAMPLER_NEAREST_REPEAT 6 -#define SAMPLER_LINEAR_REPEAT 7 -#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 -#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 -#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 -#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 - -layout(set = 0, binding = 0) uniform sampler material_samplers[12]; - -layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData { - vec4 data[]; -} -global_variables; - -layout(set = 0, binding = 2, std140) uniform SceneData { - bool volumetric_fog_enabled; - float volumetric_fog_inv_length; - float volumetric_fog_detail_spread; - - float fog_aerial_perspective; - - 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 MATERIAL_UNIFORMS_USED -layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ -#MATERIAL_UNIFORMS -} material; -#endif - -layout(set = 2, binding = 0) uniform textureCube radiance; -#ifdef USE_CUBEMAP_PASS -layout(set = 2, binding = 1) uniform textureCube half_res; -layout(set = 2, binding = 2) uniform textureCube quarter_res; -#else -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 -#define AT_CUBEMAP_PASS false -#endif - -#ifdef USE_HALF_RES_PASS -#define AT_HALF_RES_PASS true -#else -#define AT_HALF_RES_PASS false -#endif - -#ifdef USE_QUARTER_RES_PASS -#define AT_QUARTER_RES_PASS true -#else -#define AT_QUARTER_RES_PASS false -#endif - -#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 sky_color) { - vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective); - - if (scene_data.fog_sun_scatter > 0.001) { - vec4 sun_scatter = vec4(0.0); - 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; - cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y; - cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w; - cube_normal = mat3(params.orientation) * cube_normal; - cube_normal = normalize(cube_normal); - - vec2 uv = uv_interp * 0.5 + 0.5; - - vec2 panorama_coords = vec2(atan(cube_normal.x, -cube_normal.z), acos(cube_normal.y)); - - if (panorama_coords.x < 0.0) { - panorama_coords.x += M_PI * 2.0; - } - - panorama_coords /= vec2(M_PI * 2.0, M_PI); - - vec3 color = vec3(0.0, 0.0, 0.0); - float alpha = 1.0; // Only available to subpasses - vec4 half_res_color = vec4(1.0); - vec4 quarter_res_color = vec4(1.0); - vec4 custom_fog = vec4(0.0); - -#ifdef USE_CUBEMAP_PASS -#ifdef USES_HALF_RES_COLOR - half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) * params.luminance_multiplier; -#endif -#ifdef USES_QUARTER_RES_COLOR - quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) * params.luminance_multiplier; -#endif -#else -#ifdef USES_HALF_RES_COLOR - half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier; -#endif -#ifdef USES_QUARTER_RES_COLOR - quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier; -#endif -#endif - - { - -#CODE : SKY - - } - - frag_color.rgb = color * params.position_multiplier.w; - frag_color.a = alpha; - -#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS) - - // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. - if (scene_data.fog_enabled) { - vec4 fog = fog_process(cube_normal, frag_color.rgb); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - } - - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(uv); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - } - - if (custom_fog.a > 0.0) { - frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_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) { - frag_color.a = 0.0; - } - - // For mobile renderer we're dividing by 2.0 as we're using a UNORM buffer - frag_color.rgb = frag_color.rgb / params.luminance_multiplier; -} diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl deleted file mode 100644 index eee609fb48..0000000000 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl +++ /dev/null @@ -1,309 +0,0 @@ -#[compute] - -#version 450 - -#VERSION_DEFINES - -layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; - -#define SAMPLER_NEAREST_CLAMP 0 -#define SAMPLER_LINEAR_CLAMP 1 -#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 -#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 -#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 -#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 -#define SAMPLER_NEAREST_REPEAT 6 -#define SAMPLER_LINEAR_REPEAT 7 -#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 -#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 -#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 -#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 - -#define DENSITY_SCALE 1024.0 - -#include "cluster_data_inc.glsl" -#include "light_data_inc.glsl" - -#define M_PI 3.14159265359 - -layout(set = 0, binding = 1) uniform sampler material_samplers[12]; - -layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData { - vec4 data[]; -} -global_variables; - -layout(push_constant, std430) uniform Params { - vec3 position; - float pad; - - vec3 extents; - float pad2; - - ivec3 corner; - uint shape; - - mat4 transform; -} -params; - -#ifdef MOLTENVK_USED -layout(set = 1, binding = 1) volatile buffer emissive_only_map_buffer { - uint emissive_only_map[]; -}; -#else -layout(r32ui, set = 1, binding = 1) uniform volatile uimage3D emissive_only_map; -#endif - -layout(set = 1, binding = 2, std140) uniform SceneParams { - vec2 fog_frustum_size_begin; - vec2 fog_frustum_size_end; - - float fog_frustum_end; - float z_near; // - float z_far; // - float time; - - ivec3 fog_volume_size; - uint directional_light_count; // - - bool use_temporal_reprojection; - uint temporal_frame; - float detail_spread; - float temporal_blend; - - mat4 to_prev_view; - mat4 transform; -} -scene_params; - -#ifdef MOLTENVK_USED -layout(set = 1, binding = 3) volatile buffer density_only_map_buffer { - uint density_only_map[]; -}; -layout(set = 1, binding = 4) volatile buffer light_only_map_buffer { - uint light_only_map[]; -}; -#else -layout(r32ui, set = 1, binding = 3) uniform volatile uimage3D density_only_map; -layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map; -#endif - -#ifdef MATERIAL_UNIFORMS_USED -layout(set = 2, binding = 0, std140) uniform MaterialUniforms{ -#MATERIAL_UNIFORMS -} material; -#endif - -#GLOBALS - -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, scene_params.detail_spread); - return scene_params.fog_frustum_end * d; -} - -#define TEMPORAL_FRAMES 16 - -const vec3 halton_map[TEMPORAL_FRAMES] = vec3[]( - vec3(0.5, 0.33333333, 0.2), - vec3(0.25, 0.66666667, 0.4), - vec3(0.75, 0.11111111, 0.6), - vec3(0.125, 0.44444444, 0.8), - vec3(0.625, 0.77777778, 0.04), - vec3(0.375, 0.22222222, 0.24), - vec3(0.875, 0.55555556, 0.44), - vec3(0.0625, 0.88888889, 0.64), - vec3(0.5625, 0.03703704, 0.84), - vec3(0.3125, 0.37037037, 0.08), - vec3(0.8125, 0.7037037, 0.28), - vec3(0.1875, 0.14814815, 0.48), - vec3(0.6875, 0.48148148, 0.68), - vec3(0.4375, 0.81481481, 0.88), - vec3(0.9375, 0.25925926, 0.12), - vec3(0.03125, 0.59259259, 0.32)); - -void main() { - vec3 fog_cell_size = 1.0 / vec3(scene_params.fog_volume_size); - - ivec3 pos = ivec3(gl_GlobalInvocationID.xyz) + params.corner; - if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) { - return; //do not compute - } -#ifdef MOLTENVK_USED - uint lpos = pos.z * scene_params.fog_volume_size.x * scene_params.fog_volume_size.y + pos.y * scene_params.fog_volume_size.x + pos.x; -#endif - - vec3 posf = vec3(pos); - - 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, scene_params.detail_spread); - - vec3 view_pos; - view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z)); - view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z; - view_pos.y = -view_pos.y; - - if (scene_params.use_temporal_reprojection) { - vec3 prev_view = (scene_params.to_prev_view * vec4(view_pos, 1.0)).xyz; - //undo transform into prev view - prev_view.y = -prev_view.y; - //z back to unit size - prev_view.z /= -scene_params.fog_frustum_end; - //xy back to unit size - prev_view.xy /= mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(prev_view.z)); - prev_view.xy = prev_view.xy * 0.5 + 0.5; - //z back to unspread value - prev_view.z = pow(prev_view.z, 1.0 / scene_params.detail_spread); - - if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) { - //reprojectinon fits - // Since we can reproject, now we must jitter the current view pos. - // This is done here because cells that can't reproject should not jitter. - - fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[scene_params.temporal_frame]; //center of voxels, offset by halton table - fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread); - - view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z)); - view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z; - view_pos.y = -view_pos.y; - } - } - - float density = 0.0; - vec3 emission = vec3(0.0); - vec3 albedo = vec3(0.0); - - float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1)); - - vec4 world = scene_params.transform * vec4(view_pos, 1.0); - world.xyz /= world.w; - - vec3 uvw = fog_unit_pos; - - vec4 local_pos = params.transform * world; - local_pos.xyz /= local_pos.w; - - float sdf = -1.0; - if (params.shape == 0) { - // Ellipsoid - // https://www.shadertoy.com/view/tdS3DG - float k0 = length(local_pos.xyz / params.extents); - float k1 = length(local_pos.xyz / (params.extents * params.extents)); - sdf = k0 * (k0 - 1.0) / k1; - } else if (params.shape == 1) { - // Cone - // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm - - // Compute the cone angle automatically to fit within the volume's extents. - float inv_height = 1.0 / max(0.001, params.extents.y); - float radius = 1.0 / max(0.001, (min(params.extents.x, params.extents.z) * 0.5)); - float hypotenuse = sqrt(radius * radius + inv_height * inv_height); - float rsin = radius / hypotenuse; - float rcos = inv_height / hypotenuse; - vec2 c = vec2(rsin, rcos); - - float q = length(local_pos.xz); - sdf = max(dot(c, vec2(q, local_pos.y - params.extents.y)), -params.extents.y - local_pos.y); - } else if (params.shape == 2) { - // Cylinder - // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm - vec2 d = abs(vec2(length(local_pos.xz), local_pos.y)) - vec2(min(params.extents.x, params.extents.z), params.extents.y); - sdf = min(max(d.x, d.y), 0.0) + length(max(d, 0.0)); - } else if (params.shape == 3) { - // Box - // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm - vec3 q = abs(local_pos.xyz) - params.extents; - sdf = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0); - } - - float cull_mask = 1.0; //used to cull cells that do not contribute - if (params.shape <= 3) { -#ifndef SDF_USED - cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf); -#endif - uvw = clamp((local_pos.xyz + params.extents) / (2.0 * params.extents), 0.0, 1.0); - } - - if (cull_mask > 0.0) { - { -#CODE : FOG - } - -#ifdef DENSITY_USED - density *= cull_mask; - if (abs(density) > 0.001) { - int final_density = int(density * DENSITY_SCALE); -#ifdef MOLTENVK_USED - atomicAdd(density_only_map[lpos], uint(final_density)); -#else - imageAtomicAdd(density_only_map, pos, uint(final_density)); -#endif - -#ifdef EMISSION_USED - { - emission *= clamp(density, 0.0, 1.0); - emission = clamp(emission, vec3(0.0), vec3(4.0)); - // Scale to fit into R11G11B10 with a range of 0-4 - uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0); - // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint - uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b; -#ifdef MOLTENVK_USED - uint prev_emission = atomicAdd(emissive_only_map[lpos], final_emission); -#else - uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission); -#endif - - // Adding can lead to colors overflowing, so validate - uvec3 prev_emission_u = uvec3(prev_emission >> 21, (prev_emission << 11) >> 21, prev_emission % 1024); - uint add_emission = final_emission + prev_emission; - uvec3 add_emission_u = uvec3(add_emission >> 21, (add_emission << 11) >> 21, add_emission % 1024); - - bvec3 overflowing = lessThan(add_emission_u, prev_emission_u + emission_u); - - if (any(overflowing)) { - uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing); - uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b; -#ifdef MOLTENVK_USED - atomicOr(emissive_only_map[lpos], force_max); -#else - imageAtomicOr(emissive_only_map, pos, force_max); -#endif - } - } -#endif -#ifdef ALBEDO_USED - { - vec3 scattering = albedo * clamp(density, 0.0, 1.0); - scattering = clamp(scattering, vec3(0.0), vec3(1.0)); - uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0); - // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint - uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b; -#ifdef MOLTENVK_USED - uint prev_scattering = atomicAdd(light_only_map[lpos], final_scattering); -#else - uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering); -#endif - - // Adding can lead to colors overflowing, so validate - uvec3 prev_scattering_u = uvec3(prev_scattering >> 21, (prev_scattering << 11) >> 21, prev_scattering % 1024); - uint add_scattering = final_scattering + prev_scattering; - uvec3 add_scattering_u = uvec3(add_scattering >> 21, (add_scattering << 11) >> 21, add_scattering % 1024); - - bvec3 overflowing = lessThan(add_scattering_u, prev_scattering_u + scattering_u); - - if (any(overflowing)) { - uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing); - uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b; -#ifdef MOLTENVK_USED - atomicOr(light_only_map[lpos], force_max); -#else - imageAtomicOr(light_only_map, pos, force_max); -#endif - } - } -#endif // ALBEDO_USED - } -#endif // DENSITY_USED - } -} diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl deleted file mode 100644 index fdbd7d3e35..0000000000 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl +++ /dev/null @@ -1,782 +0,0 @@ -#[compute] - -#version 450 - -#VERSION_DEFINES - -/* Do not use subgroups here, seems there is not much advantage and causes glitches -#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) -#extension GL_KHR_shader_subgroup_ballot: enable -#extension GL_KHR_shader_subgroup_arithmetic: enable - -#define USE_SUBGROUPS -#endif -*/ - -#ifdef MODE_DENSITY -layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; -#else -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; -#endif - -#include "cluster_data_inc.glsl" -#include "light_data_inc.glsl" - -#define M_PI 3.14159265359 - -#define DENSITY_SCALE 1024.0 - -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 OmniLights { - LightData data[]; -} -omni_lights; - -layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { - LightData data[]; -} -spot_lights; - -layout(set = 0, binding = 5, std140) uniform DirectionalLights { - DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; -} -directional_lights; - -layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer { - uint data[]; -} -cluster_buffer; - -layout(set = 0, binding = 7) uniform sampler linear_sampler; - -#ifdef MODE_DENSITY -layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map; -#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_COPY -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 - -#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_VOXEL_GI_INSTANCES 8 - -struct VoxelGIData { - mat4 xform; // 64 - 64 - - vec3 bounds; // 12 - 76 - float dynamic_range; // 4 - 80 - - float bias; // 4 - 84 - float normal_bias; // 4 - 88 - bool blend_ambient; // 4 - 92 - uint mipmaps; // 4 - 96 -}; - -layout(set = 0, binding = 11, std140) uniform VoxelGIs { - VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; -} -voxel_gi_instances; - -layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; - -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 SDFVoxelGICascadeData { - 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; - - SDFVoxelGICascadeData 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(set = 0, binding = 14, std140) uniform Params { - vec2 fog_frustum_size_begin; - vec2 fog_frustum_size_end; - - float fog_frustum_end; - float ambient_inject; - float z_far; - int filter_axis; - - vec3 ambient_color; - float sky_contribution; - - ivec3 fog_volume_size; - uint directional_light_count; - - vec3 base_emission; - float base_density; - - vec3 base_scattering; - float phase_g; - - float detail_spread; - float gi_inject; - uint max_voxel_gi_instances; - uint cluster_type_size; - - vec2 screen_size; - uint cluster_shift; - uint cluster_width; - - uint max_cluster_element_count_div_32; - bool use_temporal_reprojection; - uint temporal_frame; - float temporal_blend; - - mat3x4 cam_rotation; - mat4 to_prev_view; - - mat3 radiance_inverse_xform; -} -params; -#ifndef MODE_COPY -layout(set = 0, binding = 15) uniform texture3D prev_density_texture; - -#ifdef MOLTENVK_USED -layout(set = 0, binding = 16) buffer density_only_map_buffer { - uint density_only_map[]; -}; -layout(set = 0, binding = 17) buffer light_only_map_buffer { - uint light_only_map[]; -}; -layout(set = 0, binding = 18) buffer emissive_only_map_buffer { - uint emissive_only_map[]; -}; -#else -layout(r32ui, set = 0, binding = 16) uniform uimage3D density_only_map; -layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map; -layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map; -#endif - -#ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 0, binding = 19) uniform textureCubeArray sky_texture; -#else -layout(set = 0, binding = 19) uniform textureCube sky_texture; -#endif -#endif // MODE_COPY - -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)); -} - -float get_omni_attenuation(float dist, float inv_range, float decay) { - float nd = dist * inv_range; - nd *= nd; - nd *= nd; // nd^4 - nd = max(1.0 - nd, 0.0); - nd *= nd; // nd^2 - return nd * pow(max(dist, 0.0001), -decay); -} - -void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { - uint item_min_max = cluster_buffer.data[p_offset]; - item_min = item_min_max & 0xFFFF; - item_max = item_min_max >> 16; - - item_from = item_min >> 5; - item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements -} - -uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { - int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); - int mask_width = min(int(z_max) - int(z_min), 32 - local_min); - return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); -} - -float henyey_greenstein(float cos_theta, float g) { - const float k = 0.0795774715459; // 1 / (4 * PI) - return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5)); -} - -#define TEMPORAL_FRAMES 16 - -const vec3 halton_map[TEMPORAL_FRAMES] = vec3[]( - vec3(0.5, 0.33333333, 0.2), - vec3(0.25, 0.66666667, 0.4), - vec3(0.75, 0.11111111, 0.6), - vec3(0.125, 0.44444444, 0.8), - vec3(0.625, 0.77777778, 0.04), - vec3(0.375, 0.22222222, 0.24), - vec3(0.875, 0.55555556, 0.44), - vec3(0.0625, 0.88888889, 0.64), - vec3(0.5625, 0.03703704, 0.84), - vec3(0.3125, 0.37037037, 0.08), - vec3(0.8125, 0.7037037, 0.28), - vec3(0.1875, 0.14814815, 0.48), - vec3(0.6875, 0.48148148, 0.68), - vec3(0.4375, 0.81481481, 0.88), - vec3(0.9375, 0.25925926, 0.12), - vec3(0.03125, 0.59259259, 0.32)); - -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 - } -#ifdef MOLTENVK_USED - uint lpos = pos.z * params.fog_volume_size.x * params.fog_volume_size.y + pos.y * params.fog_volume_size.x + pos.x; -#endif - - 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 - - uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); - uvec2 cluster_pos = screen_pos >> params.cluster_shift; - uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); - //positions in screen are too spread apart, no hopes for optimizing with subgroups - - 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; - - vec4 reprojected_density = vec4(0.0); - float reproject_amount = 0.0; - - if (params.use_temporal_reprojection) { - vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz; - //undo transform into prev view - prev_view.y = -prev_view.y; - //z back to unit size - prev_view.z /= -params.fog_frustum_end; - //xy back to unit size - prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z)); - prev_view.xy = prev_view.xy * 0.5 + 0.5; - //z back to unspread value - prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread); - - if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) { - //reprojectinon fits - - reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0); - reproject_amount = params.temporal_blend; - - // Since we can reproject, now we must jitter the current view pos. - // This is done here because cells that can't reproject should not jitter. - - fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table - - screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); - cluster_pos = screen_pos >> params.cluster_shift; - cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); - //positions in screen are too spread apart, no hopes for optimizing with subgroups - - fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); - - 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; - } - } - - uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0)); - - vec3 total_light = vec3(0.0); - - float total_density = params.base_density; -#ifdef MOLTENVK_USED - uint local_density = density_only_map[lpos]; -#else - uint local_density = imageLoad(density_only_map, pos).x; -#endif - - total_density += float(int(local_density)) / DENSITY_SCALE; - total_density = max(0.0, total_density); - -#ifdef MOLTENVK_USED - uint scattering_u = light_only_map[lpos]; -#else - uint scattering_u = imageLoad(light_only_map, pos).x; -#endif - vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0); - scattering += params.base_scattering * params.base_density; - -#ifdef MOLTENVK_USED - uint emission_u = emissive_only_map[lpos]; -#else - uint emission_u = imageLoad(emissive_only_map, pos).x; -#endif - vec3 emission = vec3(emission_u >> 21, (emission_u << 11) >> 21, emission_u % 1024) / vec3(511.0, 511.0, 255.0); - emission += params.base_emission * 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 - - if (total_density > 0.001) { - 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 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); - - 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(vec3(0.0), vec3(1.0), shadow); - } - - total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot(normalize(view_pos), normalize(directional_lights.data[i].direction)), params.phase_g); - } - - // Compute light from sky - if (params.ambient_inject > 0.0) { - vec3 isotropic = vec3(0.0); - vec3 anisotropic = vec3(0.0); - if (params.sky_contribution > 0.0) { - float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice - vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g); -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb; - anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb; -#else - isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb; - anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY - } - - total_light += mix(params.ambient_color, mix(isotropic, anisotropic, abs(params.phase_g)), params.sky_contribution) * params.ambient_inject; - } - - //compute lights from cluster - - { //omni lights - - uint cluster_omni_offset = cluster_offset; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); -#endif - - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_omni_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); -#else - uint merged_mask = mask; -#endif - - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } -#endif - uint light_index = 32 * i + bit; - - //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) { - // continue; //not masked - //} - - vec3 light_pos = omni_lights.data[light_index].position; - float d = distance(omni_lights.data[light_index].position, view_pos); - float shadow_attenuation = 1.0; - - if (d * omni_lights.data[light_index].inv_radius < 1.0) { - float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation); - - vec3 light = omni_lights.data[light_index].color; - - if (omni_lights.data[light_index].shadow_enabled) { - //has shadow - vec4 uv_rect = omni_lights.data[light_index].atlas_rect; - vec2 flip_offset = omni_lights.data[light_index].direction.xy; - - vec3 local_vert = (omni_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz; - - float shadow_len = length(local_vert); //need to remember shadow len from here - vec3 shadow_sample = normalize(local_vert); - - if (shadow_sample.z >= 0.0) { - uv_rect.xy += flip_offset; - } - - shadow_sample.z = 1.0 + abs(shadow_sample.z); - vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias); - pos.z *= omni_lights.data[light_index].inv_radius; - - pos.xy = pos.xy * 0.5 + 0.5; - pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; - - float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - - shadow_attenuation = exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade); - } - total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g); - } - } - } - } - - { //spot lights - - uint cluster_spot_offset = cluster_offset + params.cluster_type_size; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); -#endif - - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_spot_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); -#else - uint merged_mask = mask; -#endif - - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } -#endif - - //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) { - // continue; //not masked - //} - - uint light_index = 32 * i + bit; - - vec3 light_pos = spot_lights.data[light_index].position; - vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos; - float d = length(light_rel_vec); - float shadow_attenuation = 1.0; - - if (d * spot_lights.data[light_index].inv_radius < 1.0) { - float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation); - - vec3 spot_dir = spot_lights.data[light_index].direction; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle)); - attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation); - - vec3 light = spot_lights.data[light_index].color; - - if (spot_lights.data[light_index].shadow_enabled) { - //has shadow - vec4 uv_rect = spot_lights.data[light_index].atlas_rect; - vec2 flip_offset = spot_lights.data[light_index].direction.xy; - - vec3 local_vert = (spot_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz; - - float shadow_len = length(local_vert); //need to remember shadow len from here - vec3 shadow_sample = normalize(local_vert); - - if (shadow_sample.z >= 0.0) { - uv_rect.xy += flip_offset; - } - - shadow_sample.z = 1.0 + abs(shadow_sample.z); - vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - spot_lights.data[light_index].shadow_bias); - pos.z *= spot_lights.data[light_index].inv_radius; - - pos.xy = pos.xy * 0.5 + 0.5; - pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; - - float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - - shadow_attenuation = exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); - } - total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g); - } - } - } - } - - vec3 world_pos = mat3(params.cam_rotation) * view_pos; - - for (uint i = 0; i < params.max_voxel_gi_instances; i++) { - vec3 position = (voxel_gi_instances.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, voxel_gi_instances.data[i].bounds))))) { - position /= voxel_gi_instances.data[i].bounds; - - vec4 light = vec4(0.0); - for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) { - vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j)); - float a = (1.0 - light.a); - light += a * slight; - } - - light.rgb *= voxel_gi_instances.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 - } - - vec4 final_density = vec4(total_light * scattering + emission, total_density); - - final_density = mix(final_density, reprojected_density, reproject_amount); - - imageStore(density_map, pos, final_density); -#ifdef MOLTENVK_USED - density_only_map[lpos] = 0; - light_only_map[lpos] = 0; - emissive_only_map[lpos] = 0; -#else - imageStore(density_only_map, pos, uvec4(0)); - imageStore(light_only_map, pos, uvec4(0)); - imageStore(emissive_only_map, pos, uvec4(0)); -#endif -#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, 0.0, 0.0, 1.0); - float prev_z = 0.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 previous pos - float d = abs(prev_z - z); - //compute transmittance using beer's law - float transmittance = exp(-d * fog.a); - - fog_accum.rgb += ((fog.rgb - fog.rgb * transmittance) / max(fog.a, 0.00001)) * fog_accum.a; - fog_accum.a *= transmittance; - - prev_z = z; - - imageStore(fog_map, fog_pos, vec4(fog_accum.rgb, 1.0 - fog_accum.a)); - } - -#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 -#ifdef MODE_COPY - ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); - if (any(greaterThanEqual(pos, params.fog_volume_size))) { - return; //do not compute - } - - imageStore(dest_map, pos, imageLoad(source_map, pos)); - -#endif -} -- cgit v1.2.3