d95794ec8a
As many open source projects have started doing it, we're removing the current year from the copyright notice, so that we don't need to bump it every year. It seems like only the first year of publication is technically relevant for copyright notices, and even that seems to be something that many companies stopped listing altogether (in a version controlled codebase, the commits are a much better source of date of publication than a hardcoded copyright statement). We also now list Godot Engine contributors first as we're collectively the current maintainers of the project, and we clarify that the "exclusive" copyright of the co-founders covers the timespan before opensourcing (their further contributions are included as part of Godot Engine contributors). Also fixed "cf." Frenchism - it's meant as "refer to / see".
1124 lines
48 KiB
C++
1124 lines
48 KiB
C++
/**************************************************************************/
|
|
/* fog.cpp */
|
|
/**************************************************************************/
|
|
/* This file is part of: */
|
|
/* GODOT ENGINE */
|
|
/* https://godotengine.org */
|
|
/**************************************************************************/
|
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
/* */
|
|
/* 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 "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;
|
|
|
|
Fog::Fog() {
|
|
singleton = this;
|
|
}
|
|
|
|
Fog::~Fog() {
|
|
singleton = nullptr;
|
|
}
|
|
|
|
/* FOG VOLUMES */
|
|
|
|
RID Fog::fog_volume_allocate() {
|
|
return fog_volume_owner.allocate_rid();
|
|
}
|
|
|
|
void Fog::fog_volume_initialize(RID p_rid) {
|
|
fog_volume_owner.initialize_rid(p_rid, FogVolume());
|
|
}
|
|
|
|
void Fog::fog_volume_free(RID p_rid) {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_rid);
|
|
fog_volume->dependency.deleted_notify(p_rid);
|
|
fog_volume_owner.free(p_rid);
|
|
}
|
|
|
|
Dependency *Fog::fog_volume_get_dependency(RID p_fog_volume) const {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_NULL_V(fog_volume, nullptr);
|
|
|
|
return &fog_volume->dependency;
|
|
}
|
|
|
|
void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_COND(!fog_volume);
|
|
|
|
if (p_shape == fog_volume->shape) {
|
|
return;
|
|
}
|
|
|
|
fog_volume->shape = p_shape;
|
|
fog_volume->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
|
|
}
|
|
|
|
void Fog::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_COND(!fog_volume);
|
|
|
|
fog_volume->extents = p_extents;
|
|
fog_volume->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
|
|
}
|
|
|
|
void Fog::fog_volume_set_material(RID p_fog_volume, RID p_material) {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_COND(!fog_volume);
|
|
fog_volume->material = p_material;
|
|
}
|
|
|
|
RID Fog::fog_volume_get_material(RID p_fog_volume) const {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_COND_V(!fog_volume, RID());
|
|
|
|
return fog_volume->material;
|
|
}
|
|
|
|
RS::FogVolumeShape Fog::fog_volume_get_shape(RID p_fog_volume) const {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_COND_V(!fog_volume, RS::FOG_VOLUME_SHAPE_BOX);
|
|
|
|
return fog_volume->shape;
|
|
}
|
|
|
|
AABB Fog::fog_volume_get_aabb(RID p_fog_volume) const {
|
|
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_COND_V(!fog_volume, AABB());
|
|
|
|
switch (fog_volume->shape) {
|
|
case RS::FOG_VOLUME_SHAPE_ELLIPSOID:
|
|
case RS::FOG_VOLUME_SHAPE_CONE:
|
|
case RS::FOG_VOLUME_SHAPE_CYLINDER:
|
|
case RS::FOG_VOLUME_SHAPE_BOX: {
|
|
AABB aabb;
|
|
aabb.position = -fog_volume->extents;
|
|
aabb.size = fog_volume->extents * 2;
|
|
return aabb;
|
|
}
|
|
default: {
|
|
// Need some size otherwise will get culled
|
|
return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
|
|
}
|
|
}
|
|
}
|
|
|
|
Vector3 Fog::fog_volume_get_extents(RID p_fog_volume) const {
|
|
const FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
|
|
ERR_FAIL_COND_V(!fog_volume, Vector3());
|
|
return fog_volume->extents;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Fog material
|
|
|
|
bool Fog::FogMaterialData::update_parameters(const HashMap<StringName, Variant> &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, true);
|
|
}
|
|
|
|
Fog::FogMaterialData::~FogMaterialData() {
|
|
free_parameters_uniform_set(uniform_set);
|
|
}
|
|
|
|
RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_func() {
|
|
FogShaderData *shader_data = memnew(FogShaderData);
|
|
return shader_data;
|
|
}
|
|
|
|
RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_funcs() {
|
|
return Fog::get_singleton()->_create_fog_shader_func();
|
|
};
|
|
|
|
RendererRD::MaterialStorage::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::MaterialStorage::MaterialData *Fog::_create_fog_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
|
|
return Fog::get_singleton()->_create_fog_material_func(static_cast<FogShaderData *>(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<String> volumetric_fog_modes;
|
|
volumetric_fog_modes.push_back("");
|
|
volumetric_fog.shader.initialize(volumetric_fog_modes);
|
|
|
|
material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_FOG, _create_fog_shader_funcs);
|
|
material_storage->material_set_data_request_function(RendererRD::MaterialStorage::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<FogMaterialData *>(material_storage->material_get_data(volumetric_fog.default_material, RendererRD::MaterialStorage::SHADER_TYPE_FOG));
|
|
volumetric_fog.default_shader_rd = volumetric_fog.shader.version_get_shader(md->shader_data->version, 0);
|
|
|
|
Vector<RD::Uniform> uniforms;
|
|
|
|
{
|
|
Vector<RID> 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_shader_uniforms_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<String> volumetric_fog_modes;
|
|
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
|
|
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n");
|
|
volumetric_fog_modes.push_back("\n#define MODE_FILTER\n");
|
|
volumetric_fog_modes.push_back("\n#define MODE_FOG\n");
|
|
volumetric_fog_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_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;
|
|
}
|
|
|
|
bool Fog::FogShaderData::is_animated() const {
|
|
return false;
|
|
}
|
|
|
|
bool Fog::FogShaderData::casts_shadows() const {
|
|
return false;
|
|
}
|
|
|
|
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
|
|
|
|
void Fog::VolumetricFog::init(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(MACOS_ENABLED) || defined(IOS_ENABLED)
|
|
Vector<uint8_t> 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<RD::Uniform> 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<RID> &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");
|
|
|
|
Ref<VolumetricFog> fog = p_settings.vfog;
|
|
|
|
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 = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_length(p_settings.env);
|
|
|
|
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] = fog->width;
|
|
params.fog_volume_size[1] = fog->height;
|
|
params.fog_volume_size[2] = fog->depth;
|
|
|
|
params.use_temporal_reprojection = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env);
|
|
params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES;
|
|
params.detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
|
|
params.temporal_blend = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection_amount(p_settings.env);
|
|
|
|
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 (fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->fog_uniform_set)) {
|
|
Vector<RD::Uniform> 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(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(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(fog->light_map);
|
|
uniforms.push_back(u);
|
|
}
|
|
|
|
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<FogMaterialData *>(material_storage->material_get_data(fog_material, RendererRD::MaterialStorage::SHADER_TYPE_FOG));
|
|
if (!material || !material->shader_data->valid) {
|
|
material = nullptr;
|
|
}
|
|
}
|
|
|
|
if (!material) {
|
|
fog_material = volumetric_fog.default_material;
|
|
material = static_cast<FogMaterialData *>(material_storage->material_get_data(fog_material, RendererRD::MaterialStorage::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 max;
|
|
Vector3i kernel_size;
|
|
|
|
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(fog->width, fog->height, fog->depth);
|
|
float volumetric_fog_detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
|
|
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, 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, 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, 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, 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, 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, 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, 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, volumetric_fog_detail_spread, fog_size, p_cam_transform);
|
|
|
|
min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(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(fog->width, fog->height, fog->depth);
|
|
min = Vector3i(0, 0, 0);
|
|
kernel_size = Vector3i(int32_t(fog->width), int32_t(fog->height), int32_t(fog->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, fog->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);
|
|
material->set_as_used();
|
|
}
|
|
|
|
RD::get_singleton()->compute_list_dispatch_threads(compute_list, kernel_size.x, kernel_size.y, kernel_size.z);
|
|
}
|
|
if (any_uses_time || RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env)) {
|
|
RenderingServerDefault::redraw_request();
|
|
}
|
|
|
|
RD::get_singleton()->draw_command_end_label();
|
|
|
|
RD::get_singleton()->compute_list_end();
|
|
}
|
|
|
|
if (fog->process_uniform_set_density.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->process_uniform_set_density)) {
|
|
//re create uniform set if needed
|
|
Vector<RD::Uniform> uniforms;
|
|
Vector<RD::Uniform> 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::TextureStorage::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::TextureStorage::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(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(fog->fog_map);
|
|
uniforms.push_back(u);
|
|
}
|
|
|
|
{
|
|
RD::Uniform u;
|
|
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
|
u.binding = 9;
|
|
u.append_id(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(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_gi_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(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(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(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(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(p_settings.is_using_radiance_cubemap_array ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
|
|
RID sky_texture = RendererSceneRenderRD::get_singleton()->environment_get_sky(p_settings.env).is_valid() ? p_settings.sky->sky_get_radiance_texture_rd(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_settings.env)) : RID();
|
|
u.append_id(sky_texture.is_valid() ? sky_texture : radiance_texture);
|
|
uniforms.push_back(u);
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
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 = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_gi_inject(p_settings.env) > 0.0001 && RendererSceneRenderRD::get_singleton()->environment_get_sdfgi_enabled(p_settings.env) && (p_settings.sdfgi.is_valid());
|
|
|
|
if (using_sdfgi) {
|
|
if (fog->sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->sdfgi_uniform_set)) {
|
|
Vector<RD::Uniform> 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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
fog->length = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_length(p_settings.env);
|
|
fog->spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
|
|
|
|
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 = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_length(p_settings.env);
|
|
|
|
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 = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_ambient_inject(p_settings.env) * RendererSceneRenderRD::get_singleton()->environment_get_ambient_light_energy(p_settings.env);
|
|
params.z_far = z_far;
|
|
|
|
params.fog_frustum_end = fog_end;
|
|
|
|
Color ambient_color = RendererSceneRenderRD::get_singleton()->environment_get_ambient_light(p_settings.env).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 = RendererSceneRenderRD::get_singleton()->environment_get_ambient_sky_contribution(p_settings.env);
|
|
|
|
params.fog_volume_size[0] = fog->width;
|
|
params.fog_volume_size[1] = fog->height;
|
|
params.fog_volume_size[2] = fog->depth;
|
|
|
|
params.directional_light_count = p_directional_light_count;
|
|
|
|
Color emission = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_emission(p_settings.env).srgb_to_linear();
|
|
params.base_emission[0] = emission.r * RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_emission_energy(p_settings.env);
|
|
params.base_emission[1] = emission.g * RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_emission_energy(p_settings.env);
|
|
params.base_emission[2] = emission.b * RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_emission_energy(p_settings.env);
|
|
params.base_density = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_density(p_settings.env);
|
|
|
|
Color base_scattering = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_scattering(p_settings.env).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 = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_anisotropy(p_settings.env);
|
|
|
|
params.detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
|
|
params.gi_inject = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_gi_inject(p_settings.env);
|
|
|
|
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 = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_gi_inject(p_settings.env) > 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 = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env);
|
|
params.temporal_blend = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection_amount(p_settings.env);
|
|
|
|
{
|
|
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 = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_settings.env);
|
|
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, fog->process_uniform_set_density, 0);
|
|
|
|
if (using_sdfgi) {
|
|
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->sdfgi_uniform_set, 1);
|
|
}
|
|
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
|
|
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
|
|
|
// Copy fog to history buffer
|
|
if (RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env)) {
|
|
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, fog->copy_uniform_set, 0);
|
|
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->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, fog->process_uniform_set, 0);
|
|
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, 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);
|
|
|
|
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, fog->process_uniform_set2, 0);
|
|
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->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, fog->process_uniform_set, 0);
|
|
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, 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();
|
|
}
|