mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Added volumetric fog effect.
This commit is contained in:
parent
64d859df0c
commit
079ca220e1
@ -278,7 +278,7 @@ Vector2 CameraMatrix::get_viewport_half_extents() const {
|
||||
return Vector2(res.x, res.y);
|
||||
}
|
||||
|
||||
void CameraMatrix::get_far_plane_size(real_t &r_width, real_t &r_height) const {
|
||||
Vector2 CameraMatrix::get_far_plane_half_extents() const {
|
||||
const real_t *matrix = (const real_t *)this->matrix;
|
||||
///////--- Far Plane ---///////
|
||||
Plane far_plane = Plane(matrix[3] - matrix[2],
|
||||
@ -303,8 +303,7 @@ void CameraMatrix::get_far_plane_size(real_t &r_width, real_t &r_height) const {
|
||||
Vector3 res;
|
||||
far_plane.intersect_3(right_plane, top_plane, &res);
|
||||
|
||||
r_width = res.x;
|
||||
r_height = res.y;
|
||||
return Vector2(res.x, res.y);
|
||||
}
|
||||
|
||||
bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const {
|
||||
|
@ -74,7 +74,7 @@ struct CameraMatrix {
|
||||
|
||||
bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const;
|
||||
Vector2 get_viewport_half_extents() const;
|
||||
void get_far_plane_size(real_t &r_width, real_t &r_height) const;
|
||||
Vector2 get_far_plane_half_extents() const;
|
||||
|
||||
void invert();
|
||||
CameraMatrix inverse() const;
|
||||
|
@ -498,6 +498,10 @@ void EditorNode::_notification(int p_what) {
|
||||
RS::get_singleton()->environment_set_sdfgi_ray_count(ray_count);
|
||||
RS::GIProbeQuality gi_probe_quality = RS::GIProbeQuality(int(GLOBAL_GET("rendering/quality/gi_probes/quality")));
|
||||
RS::get_singleton()->gi_probe_set_quality(gi_probe_quality);
|
||||
RS::get_singleton()->environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/volumetric_fog/volume_size"), GLOBAL_GET("rendering/volumetric_fog/volume_depth"));
|
||||
RS::get_singleton()->environment_set_volumetric_fog_filter_active(bool(GLOBAL_GET("rendering/volumetric_fog/use_filter")));
|
||||
RS::get_singleton()->environment_set_volumetric_fog_directional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/directional_shadow_shrink"));
|
||||
RS::get_singleton()->environment_set_volumetric_fog_positional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/positional_shadow_shrink"));
|
||||
}
|
||||
|
||||
ResourceImporterTexture::get_singleton()->update_imports();
|
||||
|
@ -14,6 +14,7 @@ class RDHeaderStruct:
|
||||
|
||||
self.vertex_included_files = []
|
||||
self.fragment_included_files = []
|
||||
self.compute_included_files = []
|
||||
|
||||
self.reading = ""
|
||||
self.line_offset = 0
|
||||
|
@ -270,6 +270,7 @@ void Light3D::_bind_methods() {
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR);
|
||||
ADD_GROUP("Editor", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
|
||||
@ -292,6 +293,7 @@ void Light3D::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
|
||||
BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE);
|
||||
BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR);
|
||||
BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
|
||||
BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS);
|
||||
BIND_ENUM_CONSTANT(PARAM_MAX);
|
||||
|
||||
@ -345,6 +347,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
|
||||
set_param(PARAM_SHADOW_BIAS, 0.02);
|
||||
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
|
||||
set_param(PARAM_TRANSMITTANCE_BIAS, 0.05);
|
||||
set_param(PARAM_SHADOW_VOLUMETRIC_FOG_FADE, 1.0);
|
||||
set_param(PARAM_SHADOW_FADE_START, 1);
|
||||
set_disable_scale(true);
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS,
|
||||
PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
|
||||
PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR,
|
||||
PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
|
||||
PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS,
|
||||
PARAM_MAX = RS::LIGHT_PARAM_MAX
|
||||
};
|
||||
|
@ -840,6 +840,74 @@ void Environment::_update_fog_height() {
|
||||
fog_height_curve);
|
||||
}
|
||||
|
||||
// Volumetric Fog
|
||||
|
||||
void Environment::_update_volumetric_fog() {
|
||||
RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_light, volumetric_fog_light_energy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, RS::EnvVolumetricFogShadowFilter(volumetric_fog_shadow_filter));
|
||||
}
|
||||
|
||||
void Environment::set_volumetric_fog_enabled(bool p_enable) {
|
||||
volumetric_fog_enabled = p_enable;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
|
||||
bool Environment::is_volumetric_fog_enabled() const {
|
||||
return volumetric_fog_enabled;
|
||||
}
|
||||
void Environment::set_volumetric_fog_density(float p_density) {
|
||||
p_density = CLAMP(p_density, 0.0000001, 1.0);
|
||||
volumetric_fog_density = p_density;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
float Environment::get_volumetric_fog_density() const {
|
||||
return volumetric_fog_density;
|
||||
}
|
||||
void Environment::set_volumetric_fog_light(Color p_color) {
|
||||
volumetric_fog_light = p_color;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
Color Environment::get_volumetric_fog_light() const {
|
||||
return volumetric_fog_light;
|
||||
}
|
||||
void Environment::set_volumetric_fog_light_energy(float p_begin) {
|
||||
volumetric_fog_light_energy = p_begin;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
float Environment::get_volumetric_fog_light_energy() const {
|
||||
return volumetric_fog_light_energy;
|
||||
}
|
||||
void Environment::set_volumetric_fog_length(float p_length) {
|
||||
volumetric_fog_length = p_length;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
float Environment::get_volumetric_fog_length() const {
|
||||
return volumetric_fog_length;
|
||||
}
|
||||
void Environment::set_volumetric_fog_detail_spread(float p_detail_spread) {
|
||||
volumetric_fog_detail_spread = p_detail_spread;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
float Environment::get_volumetric_fog_detail_spread() const {
|
||||
return volumetric_fog_detail_spread;
|
||||
}
|
||||
|
||||
void Environment::set_volumetric_fog_gi_inject(float p_gi_inject) {
|
||||
volumetric_fog_gi_inject = p_gi_inject;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
float Environment::get_volumetric_fog_gi_inject() const {
|
||||
return volumetric_fog_gi_inject;
|
||||
}
|
||||
|
||||
void Environment::set_volumetric_fog_shadow_filter(VolumetricFogShadowFilter p_filter) {
|
||||
volumetric_fog_shadow_filter = p_filter;
|
||||
_update_volumetric_fog();
|
||||
}
|
||||
|
||||
Environment::VolumetricFogShadowFilter Environment::get_volumetric_fog_shadow_filter() const {
|
||||
return volumetric_fog_shadow_filter;
|
||||
}
|
||||
|
||||
// Adjustment
|
||||
|
||||
void Environment::set_adjustment_enabled(bool p_enabled) {
|
||||
@ -1251,7 +1319,7 @@ void Environment::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_fog_height_curve", "curve"), &Environment::set_fog_height_curve);
|
||||
ClassDB::bind_method(D_METHOD("get_fog_height_curve"), &Environment::get_fog_height_curve);
|
||||
|
||||
ADD_GROUP("Fog", "fog_");
|
||||
ADD_GROUP("Fixed Fog", "fog_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_color"), "set_fog_color", "get_fog_color");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_sun_color"), "set_fog_sun_color", "get_fog_sun_color");
|
||||
@ -1269,6 +1337,33 @@ void Environment::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_max", PROPERTY_HINT_RANGE, "-4000,4000,0.1,or_lesser,or_greater"), "set_fog_height_max", "get_fog_height_max");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_curve", PROPERTY_HINT_EXP_EASING), "set_fog_height_curve", "get_fog_height_curve");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_light", "color"), &Environment::set_volumetric_fog_light);
|
||||
ClassDB::bind_method(D_METHOD("get_volumetric_fog_light"), &Environment::get_volumetric_fog_light);
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_density", "density"), &Environment::set_volumetric_fog_density);
|
||||
ClassDB::bind_method(D_METHOD("get_volumetric_fog_density"), &Environment::get_volumetric_fog_density);
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_light_energy", "begin"), &Environment::set_volumetric_fog_light_energy);
|
||||
ClassDB::bind_method(D_METHOD("get_volumetric_fog_light_energy"), &Environment::get_volumetric_fog_light_energy);
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_length", "length"), &Environment::set_volumetric_fog_length);
|
||||
ClassDB::bind_method(D_METHOD("get_volumetric_fog_length"), &Environment::get_volumetric_fog_length);
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_detail_spread", "detail_spread"), &Environment::set_volumetric_fog_detail_spread);
|
||||
ClassDB::bind_method(D_METHOD("get_volumetric_fog_detail_spread"), &Environment::get_volumetric_fog_detail_spread);
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_gi_inject", "gi_inject"), &Environment::set_volumetric_fog_gi_inject);
|
||||
ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject);
|
||||
ClassDB::bind_method(D_METHOD("set_volumetric_fog_shadow_filter", "shadow_filter"), &Environment::set_volumetric_fog_shadow_filter);
|
||||
ClassDB::bind_method(D_METHOD("get_volumetric_fog_shadow_filter"), &Environment::get_volumetric_fog_shadow_filter);
|
||||
|
||||
ADD_GROUP("Volumetric Fog", "volumetric_fog_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_enabled"), "set_volumetric_fog_enabled", "is_volumetric_fog_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_volumetric_fog_density", "get_volumetric_fog_density");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_light", "get_volumetric_fog_light");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_light_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_light_energy", "get_volumetric_fog_light_energy");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "volumetric_fog_shadow_filter", PROPERTY_HINT_ENUM, "Disabled,Low,Medium,High"), "set_volumetric_fog_shadow_filter", "get_volumetric_fog_shadow_filter");
|
||||
|
||||
// Adjustment
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_adjustment_enabled", "enabled"), &Environment::set_adjustment_enabled);
|
||||
@ -1331,6 +1426,11 @@ void Environment::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_DISABLED);
|
||||
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_75_PERCENT);
|
||||
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_50_PERCENT);
|
||||
|
||||
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED);
|
||||
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_LOW);
|
||||
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM);
|
||||
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_HIGH);
|
||||
}
|
||||
|
||||
Environment::Environment() {
|
||||
@ -1347,7 +1447,7 @@ Environment::Environment() {
|
||||
_update_fog_depth();
|
||||
_update_fog_height();
|
||||
_update_adjustment();
|
||||
|
||||
_update_volumetric_fog();
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,13 @@ public:
|
||||
GLOW_BLEND_MODE_MIX,
|
||||
};
|
||||
|
||||
enum VolumetricFogShadowFilter {
|
||||
VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED,
|
||||
VOLUMETRIC_FOG_SHADOW_FILTER_LOW,
|
||||
VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM,
|
||||
VOLUMETRIC_FOG_SHADOW_FILTER_HIGH,
|
||||
};
|
||||
|
||||
private:
|
||||
RID environment;
|
||||
|
||||
@ -196,6 +203,17 @@ private:
|
||||
float fog_height_curve = 1.0;
|
||||
void _update_fog_height();
|
||||
|
||||
// Volumetric Fog
|
||||
bool volumetric_fog_enabled = false;
|
||||
float volumetric_fog_density = 0.01;
|
||||
Color volumetric_fog_light = Color(0.0, 0.0, 0.0);
|
||||
float volumetric_fog_light_energy = 1.0;
|
||||
float volumetric_fog_length = 64.0;
|
||||
float volumetric_fog_detail_spread = 2.0;
|
||||
VolumetricFogShadowFilter volumetric_fog_shadow_filter = VOLUMETRIC_FOG_SHADOW_FILTER_LOW;
|
||||
float volumetric_fog_gi_inject = 0.0;
|
||||
void _update_volumetric_fog();
|
||||
|
||||
// Adjustment
|
||||
bool adjustment_enabled = false;
|
||||
float adjustment_brightness = 1.0;
|
||||
@ -375,6 +393,24 @@ public:
|
||||
void set_fog_height_curve(float p_distance);
|
||||
float get_fog_height_curve() const;
|
||||
|
||||
// Volumetric Fog
|
||||
void set_volumetric_fog_enabled(bool p_enable);
|
||||
bool is_volumetric_fog_enabled() const;
|
||||
void set_volumetric_fog_density(float p_density);
|
||||
float get_volumetric_fog_density() const;
|
||||
void set_volumetric_fog_light(Color p_color);
|
||||
Color get_volumetric_fog_light() const;
|
||||
void set_volumetric_fog_light_energy(float p_begin);
|
||||
float get_volumetric_fog_light_energy() const;
|
||||
void set_volumetric_fog_length(float p_length);
|
||||
float get_volumetric_fog_length() const;
|
||||
void set_volumetric_fog_detail_spread(float p_detail_spread);
|
||||
float get_volumetric_fog_detail_spread() const;
|
||||
void set_volumetric_fog_shadow_filter(VolumetricFogShadowFilter p_filter);
|
||||
VolumetricFogShadowFilter get_volumetric_fog_shadow_filter() const;
|
||||
void set_volumetric_fog_gi_inject(float p_gi_inject);
|
||||
float get_volumetric_fog_gi_inject() const;
|
||||
|
||||
// Adjustment
|
||||
void set_adjustment_enabled(bool p_enabled);
|
||||
bool is_adjustment_enabled() const;
|
||||
@ -399,5 +435,6 @@ VARIANT_ENUM_CAST(Environment::SSAOBlur)
|
||||
VARIANT_ENUM_CAST(Environment::SDFGICascades)
|
||||
VARIANT_ENUM_CAST(Environment::SDFGIYScale)
|
||||
VARIANT_ENUM_CAST(Environment::GlowBlendMode)
|
||||
VARIANT_ENUM_CAST(Environment::VolumetricFogShadowFilter)
|
||||
|
||||
#endif // ENVIRONMENT_H
|
||||
|
@ -88,6 +88,13 @@ public:
|
||||
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
|
||||
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0;
|
||||
|
||||
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
|
||||
|
||||
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
|
||||
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
|
||||
virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0;
|
||||
virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0;
|
||||
|
||||
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0;
|
||||
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0;
|
||||
|
||||
|
@ -1229,6 +1229,50 @@ void RasterizerEffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_rou
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
void RasterizerEffectsRD::reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RD::ComputeListID compute_list) {
|
||||
uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, (uint32_t)p_shrink_limit, 0, 0, 0 };
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_REDUCE]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_source_shadow, p_dest_shadow), 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8);
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1);
|
||||
}
|
||||
void RasterizerEffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RenderingServer::EnvVolumetricFogShadowFilter p_filter, RD::ComputeListID compute_list, bool p_vertical, bool p_horizontal) {
|
||||
uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, 0, 0, 0, 0 };
|
||||
|
||||
switch (p_filter) {
|
||||
case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED:
|
||||
case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW: {
|
||||
push_constant[5] = 0;
|
||||
} break;
|
||||
case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM: {
|
||||
push_constant[5] = 9;
|
||||
} break;
|
||||
case RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_HIGH: {
|
||||
push_constant[5] = 18;
|
||||
} break;
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_FILTER]);
|
||||
if (p_vertical) {
|
||||
push_constant[6] = 1;
|
||||
push_constant[7] = 0;
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_shadow, p_backing_shadow), 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8);
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1);
|
||||
}
|
||||
if (p_vertical && p_horizontal) {
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
}
|
||||
if (p_horizontal) {
|
||||
push_constant[6] = 0;
|
||||
push_constant[7] = 1;
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_backing_shadow, p_shadow), 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(uint32_t) * 8);
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1);
|
||||
}
|
||||
}
|
||||
RasterizerEffectsRD::RasterizerEffectsRD() {
|
||||
{ // Initialize copy
|
||||
Vector<String> copy_modes;
|
||||
@ -1560,6 +1604,20 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Vector<String> shadow_reduce_modes;
|
||||
shadow_reduce_modes.push_back("\n#define MODE_REDUCE\n");
|
||||
shadow_reduce_modes.push_back("\n#define MODE_FILTER\n");
|
||||
|
||||
shadow_reduce.shader.initialize(shadow_reduce_modes);
|
||||
|
||||
shadow_reduce.shader_version = shadow_reduce.shader.version_create();
|
||||
|
||||
for (int i = 0; i < SHADOW_REDUCE_MAX; i++) {
|
||||
shadow_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(shadow_reduce.shader.version_get_shader(shadow_reduce.shader_version, i));
|
||||
}
|
||||
}
|
||||
|
||||
RD::SamplerState sampler;
|
||||
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
|
||||
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
|
||||
@ -1624,4 +1682,5 @@ RasterizerEffectsRD::~RasterizerEffectsRD() {
|
||||
ssr_scale.shader.version_free(ssr_scale.shader_version);
|
||||
sss.shader.version_free(sss.shader_version);
|
||||
tonemap.shader.version_free(tonemap.shader_version);
|
||||
shadow_reduce.shader.version_free(shadow_reduce.shader_version);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h"
|
||||
@ -534,6 +535,18 @@ class RasterizerEffectsRD {
|
||||
RID pipelines[RESOLVE_MODE_MAX]; //3 quality levels
|
||||
} resolve;
|
||||
|
||||
enum ShadowReduceMode {
|
||||
SHADOW_REDUCE_REDUCE,
|
||||
SHADOW_REDUCE_FILTER,
|
||||
SHADOW_REDUCE_MAX
|
||||
};
|
||||
|
||||
struct ShadowReduce {
|
||||
ShadowReduceShaderRD shader;
|
||||
RID shader_version;
|
||||
RID pipelines[2];
|
||||
} shadow_reduce;
|
||||
|
||||
RID default_sampler;
|
||||
RID default_mipmap_sampler;
|
||||
RID index_buffer;
|
||||
@ -633,6 +646,9 @@ public:
|
||||
|
||||
void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples);
|
||||
|
||||
void reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RenderingDevice::ComputeListID compute_list);
|
||||
void filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RS::EnvVolumetricFogShadowFilter p_filter, RenderingDevice::ComputeListID compute_list, bool p_vertical = true, bool p_horizontal = true);
|
||||
|
||||
RasterizerEffectsRD();
|
||||
~RasterizerEffectsRD();
|
||||
};
|
||||
|
@ -1145,12 +1145,19 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
|
||||
scene_state.ubo.time = time;
|
||||
|
||||
scene_state.ubo.gi_upscale_for_msaa = false;
|
||||
scene_state.ubo.volumetric_fog_enabled = false;
|
||||
|
||||
if (p_render_buffers.is_valid()) {
|
||||
RenderBufferDataHighEnd *render_buffers = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
|
||||
if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
|
||||
scene_state.ubo.gi_upscale_for_msaa = true;
|
||||
}
|
||||
|
||||
if (render_buffers_has_volumetric_fog(p_render_buffers)) {
|
||||
scene_state.ubo.volumetric_fog_enabled = true;
|
||||
scene_state.ubo.volumetric_fog_inv_length = 1.0 / render_buffers_get_volumetric_fog_end(p_render_buffers);
|
||||
scene_state.ubo.volumetric_fog_detail_spread = 1.0 / render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) {
|
||||
@ -1754,6 +1761,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
|
||||
RD::get_singleton()->draw_list_end();
|
||||
|
||||
if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
|
||||
RENDER_TIMESTAMP("Resolve Depth Pre-Pass");
|
||||
if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) {
|
||||
static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 };
|
||||
storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]);
|
||||
@ -2502,7 +2510,17 @@ void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_b
|
||||
u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.binding = 10;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
RID vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers);
|
||||
if (vfog.is_null()) {
|
||||
vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
|
||||
}
|
||||
u.ids.push_back(vfog);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
|
||||
}
|
||||
}
|
||||
@ -2815,6 +2833,13 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
|
||||
u.ids.push_back(render_buffers_get_default_gi_probe_buffer());
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.binding = 10;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
|
||||
}
|
||||
|
@ -359,6 +359,11 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
|
||||
|
||||
int32_t sdf_size[3];
|
||||
uint32_t gi_upscale_for_msaa;
|
||||
|
||||
uint32_t volumetric_fog_enabled;
|
||||
float volumetric_fog_inv_length;
|
||||
float volumetric_fog_detail_spread;
|
||||
uint32_t volumetric_fog_pad;
|
||||
};
|
||||
|
||||
UBO ubo;
|
||||
|
@ -227,6 +227,7 @@ void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) {
|
||||
RD::get_singleton()->free(rb->sdfgi->lightprobe_data);
|
||||
RD::get_singleton()->free(rb->sdfgi->lightprobe_history_scroll);
|
||||
RD::get_singleton()->free(rb->sdfgi->occlusion_data);
|
||||
RD::get_singleton()->free(rb->sdfgi->ambient_texture);
|
||||
|
||||
RD::get_singleton()->free(rb->sdfgi->cascades_ubo);
|
||||
|
||||
@ -371,6 +372,16 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co
|
||||
RD::TextureView tv;
|
||||
tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
|
||||
sdfgi->lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->lightprobe_data);
|
||||
|
||||
//texture handling ambient data, to integrate with volumetric foc
|
||||
RD::TextureFormat tf_ambient = tf_probes;
|
||||
tf_ambient.array_layers = sdfgi->cascades.size();
|
||||
tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE
|
||||
tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count;
|
||||
tf_ambient.height = sdfgi->probe_axis_count;
|
||||
tf_ambient.type = RD::TEXTURE_TYPE_2D_ARRAY;
|
||||
//lightprobe texture is an octahedral texture
|
||||
sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());
|
||||
}
|
||||
|
||||
sdfgi->cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES);
|
||||
@ -930,6 +941,13 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co
|
||||
u.ids.push_back(parent_average);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 14;
|
||||
u.ids.push_back(sdfgi->ambient_texture);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
sdfgi->cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 0);
|
||||
}
|
||||
@ -1282,6 +1300,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm
|
||||
push_constant.ray_bias = rb->sdfgi->probe_bias;
|
||||
push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
|
||||
push_constant.image_size[1] = rb->sdfgi->probe_axis_count;
|
||||
push_constant.store_ambient_texture = env->volumetric_fog_enabled;
|
||||
|
||||
RID sky_uniform_set = sdfgi_shader.integrate_default_sky_uniform_set;
|
||||
push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_DISABLED;
|
||||
@ -1375,6 +1394,96 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm
|
||||
RENDER_TIMESTAMP("<SDFGI Update Probes");
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used) {
|
||||
r_gi_probes_used = 0;
|
||||
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
|
||||
ERR_FAIL_COND(rb == nullptr);
|
||||
|
||||
RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers);
|
||||
GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES];
|
||||
|
||||
bool giprobes_changed = false;
|
||||
|
||||
Transform to_camera;
|
||||
to_camera.origin = p_transform.origin; //only translation, make local
|
||||
|
||||
for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
|
||||
RID texture;
|
||||
if (i < p_gi_probe_cull_count) {
|
||||
GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]);
|
||||
|
||||
if (gipi) {
|
||||
texture = gipi->texture;
|
||||
GI::GIProbeData &gipd = gi_probe_data[i];
|
||||
|
||||
RID base_probe = gipi->probe;
|
||||
|
||||
Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
|
||||
|
||||
gipd.xform[0] = to_cell.basis.elements[0][0];
|
||||
gipd.xform[1] = to_cell.basis.elements[1][0];
|
||||
gipd.xform[2] = to_cell.basis.elements[2][0];
|
||||
gipd.xform[3] = 0;
|
||||
gipd.xform[4] = to_cell.basis.elements[0][1];
|
||||
gipd.xform[5] = to_cell.basis.elements[1][1];
|
||||
gipd.xform[6] = to_cell.basis.elements[2][1];
|
||||
gipd.xform[7] = 0;
|
||||
gipd.xform[8] = to_cell.basis.elements[0][2];
|
||||
gipd.xform[9] = to_cell.basis.elements[1][2];
|
||||
gipd.xform[10] = to_cell.basis.elements[2][2];
|
||||
gipd.xform[11] = 0;
|
||||
gipd.xform[12] = to_cell.origin.x;
|
||||
gipd.xform[13] = to_cell.origin.y;
|
||||
gipd.xform[14] = to_cell.origin.z;
|
||||
gipd.xform[15] = 1;
|
||||
|
||||
Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
|
||||
|
||||
gipd.bounds[0] = bounds.x;
|
||||
gipd.bounds[1] = bounds.y;
|
||||
gipd.bounds[2] = bounds.z;
|
||||
|
||||
gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
|
||||
gipd.bias = storage->gi_probe_get_bias(base_probe);
|
||||
gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
|
||||
gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
|
||||
gipd.anisotropy_strength = 0;
|
||||
gipd.ao = storage->gi_probe_get_ao(base_probe);
|
||||
gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
|
||||
gipd.mipmaps = gipi->mipmaps.size();
|
||||
}
|
||||
|
||||
r_gi_probes_used++;
|
||||
}
|
||||
|
||||
if (texture == RID()) {
|
||||
texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
|
||||
}
|
||||
|
||||
if (texture != rb->giprobe_textures[i]) {
|
||||
giprobes_changed = true;
|
||||
rb->giprobe_textures[i] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
if (giprobes_changed) {
|
||||
RD::get_singleton()->free(rb->gi_uniform_set);
|
||||
rb->gi_uniform_set = RID();
|
||||
if (rb->volumetric_fog) {
|
||||
if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
|
||||
RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
|
||||
RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
|
||||
}
|
||||
rb->volumetric_fog->uniform_set = RID();
|
||||
rb->volumetric_fog->uniform_set2 = RID();
|
||||
}
|
||||
}
|
||||
|
||||
if (p_gi_probe_cull_count > 0) {
|
||||
RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) {
|
||||
RENDER_TIMESTAMP("Render GI");
|
||||
|
||||
@ -1490,81 +1599,6 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness
|
||||
RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, true);
|
||||
}
|
||||
|
||||
{
|
||||
RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers);
|
||||
GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES];
|
||||
|
||||
bool giprobes_changed = false;
|
||||
|
||||
Transform to_camera;
|
||||
to_camera.origin = p_transform.origin; //only translation, make local
|
||||
|
||||
for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
|
||||
RID texture;
|
||||
if (i < p_gi_probe_cull_count) {
|
||||
GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]);
|
||||
|
||||
if (gipi) {
|
||||
texture = gipi->texture;
|
||||
GI::GIProbeData &gipd = gi_probe_data[i];
|
||||
|
||||
RID base_probe = gipi->probe;
|
||||
|
||||
Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
|
||||
|
||||
gipd.xform[0] = to_cell.basis.elements[0][0];
|
||||
gipd.xform[1] = to_cell.basis.elements[1][0];
|
||||
gipd.xform[2] = to_cell.basis.elements[2][0];
|
||||
gipd.xform[3] = 0;
|
||||
gipd.xform[4] = to_cell.basis.elements[0][1];
|
||||
gipd.xform[5] = to_cell.basis.elements[1][1];
|
||||
gipd.xform[6] = to_cell.basis.elements[2][1];
|
||||
gipd.xform[7] = 0;
|
||||
gipd.xform[8] = to_cell.basis.elements[0][2];
|
||||
gipd.xform[9] = to_cell.basis.elements[1][2];
|
||||
gipd.xform[10] = to_cell.basis.elements[2][2];
|
||||
gipd.xform[11] = 0;
|
||||
gipd.xform[12] = to_cell.origin.x;
|
||||
gipd.xform[13] = to_cell.origin.y;
|
||||
gipd.xform[14] = to_cell.origin.z;
|
||||
gipd.xform[15] = 1;
|
||||
|
||||
Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
|
||||
|
||||
gipd.bounds[0] = bounds.x;
|
||||
gipd.bounds[1] = bounds.y;
|
||||
gipd.bounds[2] = bounds.z;
|
||||
|
||||
gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
|
||||
gipd.bias = storage->gi_probe_get_bias(base_probe);
|
||||
gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
|
||||
gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
|
||||
gipd.anisotropy_strength = 0;
|
||||
gipd.ao = storage->gi_probe_get_ao(base_probe);
|
||||
gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (texture == RID()) {
|
||||
texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
|
||||
}
|
||||
|
||||
if (texture != rb->giprobe_textures[i]) {
|
||||
giprobes_changed = true;
|
||||
rb->giprobe_textures[i] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
if (giprobes_changed) {
|
||||
RD::get_singleton()->free(rb->gi_uniform_set);
|
||||
rb->gi_uniform_set = RID();
|
||||
}
|
||||
|
||||
if (p_gi_probe_cull_count > 0) {
|
||||
RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
|
||||
Vector<RD::Uniform> uniforms;
|
||||
{
|
||||
@ -2880,6 +2914,48 @@ void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::Envi
|
||||
env->sdfgi_y_scale = p_y_scale;
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) {
|
||||
Environment *env = environment_owner.getornull(p_env);
|
||||
ERR_FAIL_COND(!env);
|
||||
|
||||
env->volumetric_fog_enabled = p_enable;
|
||||
env->volumetric_fog_density = p_density;
|
||||
env->volumetric_fog_light = p_light;
|
||||
env->volumetric_fog_light_energy = p_light_energy;
|
||||
env->volumetric_fog_length = p_lenght;
|
||||
env->volumetric_fog_detail_spread = p_detail_spread;
|
||||
env->volumetric_fog_shadow_filter = p_shadow_filter;
|
||||
env->volumetric_fog_gi_inject = p_gi_inject;
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) {
|
||||
volumetric_fog_size = p_size;
|
||||
volumetric_fog_depth = p_depth;
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::environment_set_volumetric_fog_filter_active(bool p_enable) {
|
||||
volumetric_fog_filter_active = p_enable;
|
||||
}
|
||||
void RasterizerSceneRD::environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) {
|
||||
p_shrink_size = nearest_power_of_2_templated(p_shrink_size);
|
||||
if (volumetric_fog_directional_shadow_shrink == (uint32_t)p_shrink_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
_clear_shadow_shrink_stages(directional_shadow.shrink_stages);
|
||||
}
|
||||
void RasterizerSceneRD::environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) {
|
||||
p_shrink_size = nearest_power_of_2_templated(p_shrink_size);
|
||||
if (volumetric_fog_positional_shadow_shrink == (uint32_t)p_shrink_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < shadow_atlas_owner.get_rid_count(); i++) {
|
||||
ShadowAtlas *sa = shadow_atlas_owner.get_ptr_by_index(i);
|
||||
_clear_shadow_shrink_stages(sa->shrink_stages);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) {
|
||||
sdfgi_ray_count = p_ray_count;
|
||||
}
|
||||
@ -3286,6 +3362,7 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) {
|
||||
if (shadow_atlas->depth.is_valid()) {
|
||||
RD::get_singleton()->free(shadow_atlas->depth);
|
||||
shadow_atlas->depth = RID();
|
||||
_clear_shadow_shrink_stages(shadow_atlas->shrink_stages);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
//clear subdivisions
|
||||
@ -3579,6 +3656,7 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) {
|
||||
|
||||
if (directional_shadow.depth.is_valid()) {
|
||||
RD::get_singleton()->free(directional_shadow.depth);
|
||||
_clear_shadow_shrink_stages(directional_shadow.shrink_stages);
|
||||
directional_shadow.depth = RID();
|
||||
}
|
||||
|
||||
@ -4951,6 +5029,8 @@ void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, R
|
||||
Environment *env = environment_owner.getornull(p_environment);
|
||||
ERR_FAIL_COND(!env);
|
||||
|
||||
RENDER_TIMESTAMP("Process SSAO");
|
||||
|
||||
if (rb->ssao.ao[0].is_valid() && rb->ssao.ao_full.is_valid() != ssao_half_size) {
|
||||
RD::get_singleton()->free(rb->ssao.depth);
|
||||
RD::get_singleton()->free(rb->ssao.ao[0]);
|
||||
@ -5463,6 +5543,30 @@ RID RasterizerSceneRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_b
|
||||
return rb->sdfgi->occlusion_texture;
|
||||
}
|
||||
|
||||
bool RasterizerSceneRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const {
|
||||
const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
|
||||
ERR_FAIL_COND_V(!rb, false);
|
||||
|
||||
return rb->volumetric_fog != nullptr;
|
||||
}
|
||||
RID RasterizerSceneRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) {
|
||||
const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
|
||||
ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID());
|
||||
|
||||
return rb->volumetric_fog->fog_map;
|
||||
}
|
||||
|
||||
float RasterizerSceneRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) {
|
||||
const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
|
||||
ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
|
||||
return rb->volumetric_fog->length;
|
||||
}
|
||||
float RasterizerSceneRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) {
|
||||
const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
|
||||
ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
|
||||
return rb->volumetric_fog->spread;
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) {
|
||||
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
|
||||
rb->width = p_width;
|
||||
@ -5679,9 +5783,10 @@ void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result,
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count) {
|
||||
void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {
|
||||
uint32_t light_count = 0;
|
||||
r_directional_light_count = 0;
|
||||
r_positional_light_count = 0;
|
||||
sky_scene_state.directional_light_count = 0;
|
||||
|
||||
for (int i = 0; i < p_light_cull_count; i++) {
|
||||
@ -5797,7 +5902,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
|
||||
light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale;
|
||||
light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j);
|
||||
light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale;
|
||||
light_data.shadow_transmittance_z_scale[j] = light_instance_get_shadow_range(li, j);
|
||||
light_data.shadow_z_range[j] = light_instance_get_shadow_range(li, j);
|
||||
light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j);
|
||||
RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrices[j]);
|
||||
|
||||
@ -5826,6 +5931,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
|
||||
float fade_start = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);
|
||||
light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
|
||||
light_data.fade_to = -light_data.shadow_split_offsets[3];
|
||||
light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);
|
||||
|
||||
light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
|
||||
light_data.softshadow_angle = angular_diameter;
|
||||
@ -5867,6 +5973,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
|
||||
Transform light_transform = light_instance_get_base_transform(li);
|
||||
|
||||
Cluster::LightData &light_data = cluster.lights[light_count];
|
||||
cluster.lights_instances[light_count] = li;
|
||||
|
||||
float sign = storage->light_is_negative(base) ? -1 : 1;
|
||||
Color linear_col = storage->light_get_color(base).to_linear();
|
||||
@ -5965,6 +6072,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
|
||||
light_data.atlas_rect[3] = rect.size.height;
|
||||
|
||||
light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
|
||||
light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);
|
||||
|
||||
if (type == RS::LIGHT_OMNI) {
|
||||
light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
|
||||
@ -6005,6 +6113,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
|
||||
cluster.builder.add_light(type == RS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
|
||||
|
||||
light_count++;
|
||||
r_positional_light_count++;
|
||||
} break;
|
||||
}
|
||||
|
||||
@ -6152,6 +6261,526 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) {
|
||||
ERR_FAIL_COND(!rb->volumetric_fog);
|
||||
|
||||
RD::get_singleton()->free(rb->volumetric_fog->light_density_map);
|
||||
RD::get_singleton()->free(rb->volumetric_fog->fog_map);
|
||||
memdelete(rb->volumetric_fog);
|
||||
rb->volumetric_fog = nullptr;
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size) {
|
||||
//create fog mipmaps
|
||||
uint32_t fog_texture_size = p_target_size;
|
||||
uint32_t base_texture_size = p_base_size;
|
||||
|
||||
ShadowShrinkStage first;
|
||||
first.size = base_texture_size;
|
||||
first.texture = p_base;
|
||||
shrink_stages.push_back(first); //put depth first in case we dont find smaller ones
|
||||
|
||||
while (fog_texture_size < base_texture_size) {
|
||||
base_texture_size = MAX(base_texture_size / 8, fog_texture_size);
|
||||
|
||||
ShadowShrinkStage s;
|
||||
s.size = base_texture_size;
|
||||
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
|
||||
tf.width = base_texture_size;
|
||||
tf.height = base_texture_size;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
||||
if (base_texture_size == fog_texture_size) {
|
||||
s.filter_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
|
||||
}
|
||||
|
||||
s.texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
|
||||
shrink_stages.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages) {
|
||||
for (int i = 1; i < shrink_stages.size(); i++) {
|
||||
RD::get_singleton()->free(shrink_stages[i].texture);
|
||||
if (shrink_stages[i].filter_texture.is_valid()) {
|
||||
RD::get_singleton()->free(shrink_stages[i].filter_texture);
|
||||
}
|
||||
}
|
||||
shrink_stages.clear();
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
|
||||
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
|
||||
ERR_FAIL_COND(!rb);
|
||||
Environment *env = environment_owner.getornull(p_environment);
|
||||
|
||||
float ratio = float(rb->width) / float((rb->width + rb->height) / 2);
|
||||
uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio);
|
||||
uint32_t target_height = uint32_t(float(volumetric_fog_size) / ratio);
|
||||
|
||||
if (rb->volumetric_fog) {
|
||||
//validate
|
||||
if (!env || !env->volumetric_fog_enabled || rb->volumetric_fog->width != target_width || rb->volumetric_fog->height != target_height || rb->volumetric_fog->depth != volumetric_fog_depth) {
|
||||
_volumetric_fog_erase(rb);
|
||||
_render_buffers_uniform_set_changed(p_render_buffers);
|
||||
}
|
||||
}
|
||||
|
||||
if (!env || !env->volumetric_fog_enabled) {
|
||||
//no reason to enable or update, bye
|
||||
return;
|
||||
}
|
||||
|
||||
if (env && env->volumetric_fog_enabled && !rb->volumetric_fog) {
|
||||
//required volumetric fog but not existing, create
|
||||
rb->volumetric_fog = memnew(VolumetricFog);
|
||||
rb->volumetric_fog->width = target_width;
|
||||
rb->volumetric_fog->height = target_height;
|
||||
rb->volumetric_fog->depth = volumetric_fog_depth;
|
||||
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
|
||||
tf.width = target_width;
|
||||
tf.height = target_height;
|
||||
tf.depth = volumetric_fog_depth;
|
||||
tf.type = RD::TEXTURE_TYPE_3D;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
||||
rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
|
||||
tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
|
||||
|
||||
rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
_render_buffers_uniform_set_changed(p_render_buffers);
|
||||
}
|
||||
|
||||
//update directional shadow
|
||||
|
||||
if (p_use_directional_shadows) {
|
||||
if (directional_shadow.shrink_stages.empty()) {
|
||||
if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
|
||||
//invalidate uniform set, we will need a new one
|
||||
RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
|
||||
rb->volumetric_fog->uniform_set = RID();
|
||||
}
|
||||
_allocate_shadow_shrink_stages(directional_shadow.depth, directional_shadow.size, directional_shadow.shrink_stages, volumetric_fog_directional_shadow_shrink);
|
||||
}
|
||||
|
||||
if (directional_shadow.shrink_stages.size() > 1) {
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
for (int i = 1; i < directional_shadow.shrink_stages.size(); i++) {
|
||||
int32_t src_size = directional_shadow.shrink_stages[i - 1].size;
|
||||
int32_t dst_size = directional_shadow.shrink_stages[i].size;
|
||||
Rect2i r(0, 0, src_size, src_size);
|
||||
int32_t shrink_limit = 8 / (src_size / dst_size);
|
||||
|
||||
storage->get_effects()->reduce_shadow(directional_shadow.shrink_stages[i - 1].texture, directional_shadow.shrink_stages[i].texture, Size2i(src_size, src_size), r, shrink_limit, compute_list);
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && directional_shadow.shrink_stages[i].filter_texture.is_valid()) {
|
||||
Rect2i rf(0, 0, dst_size, dst_size);
|
||||
storage->get_effects()->filter_shadow(directional_shadow.shrink_stages[i].texture, directional_shadow.shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), rf, env->volumetric_fog_shadow_filter, compute_list);
|
||||
}
|
||||
}
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
}
|
||||
|
||||
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
|
||||
|
||||
if (shadow_atlas) {
|
||||
//shrink shadows that need to be shrunk
|
||||
|
||||
bool force_shrink_shadows = false;
|
||||
|
||||
if (shadow_atlas->shrink_stages.empty()) {
|
||||
if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
|
||||
//invalidate uniform set, we will need a new one
|
||||
RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
|
||||
rb->volumetric_fog->uniform_set = RID();
|
||||
}
|
||||
_allocate_shadow_shrink_stages(shadow_atlas->depth, shadow_atlas->size, shadow_atlas->shrink_stages, volumetric_fog_positional_shadow_shrink);
|
||||
force_shrink_shadows = true;
|
||||
}
|
||||
|
||||
if (rb->volumetric_fog->last_shadow_filter != env->volumetric_fog_shadow_filter) {
|
||||
//if shadow filter changed, invalidate caches
|
||||
rb->volumetric_fog->last_shadow_filter = env->volumetric_fog_shadow_filter;
|
||||
force_shrink_shadows = true;
|
||||
}
|
||||
|
||||
cluster.lights_shadow_rect_cache_count = 0;
|
||||
|
||||
for (int i = 0; i < p_positional_light_count; i++) {
|
||||
if (cluster.lights[i].shadow_color_enabled[3] > 127) {
|
||||
RID li = cluster.lights_instances[i];
|
||||
|
||||
ERR_CONTINUE(!shadow_atlas->shadow_owners.has(li));
|
||||
|
||||
uint32_t key = shadow_atlas->shadow_owners[li];
|
||||
|
||||
uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
|
||||
uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
|
||||
|
||||
ERR_CONTINUE((int)shadow >= shadow_atlas->quadrants[quadrant].shadows.size());
|
||||
|
||||
ShadowAtlas::Quadrant::Shadow &s = shadow_atlas->quadrants[quadrant].shadows.write[shadow];
|
||||
|
||||
if (!force_shrink_shadows && s.fog_version == s.version) {
|
||||
continue; //do not update, no need
|
||||
}
|
||||
|
||||
s.fog_version = s.version;
|
||||
|
||||
uint32_t quadrant_size = shadow_atlas->size >> 1;
|
||||
|
||||
Rect2i atlas_rect;
|
||||
|
||||
atlas_rect.position.x = (quadrant & 1) * quadrant_size;
|
||||
atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
|
||||
|
||||
uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
|
||||
atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
|
||||
atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
|
||||
|
||||
atlas_rect.size.x = shadow_size;
|
||||
atlas_rect.size.y = shadow_size;
|
||||
|
||||
cluster.lights_shadow_rect_cache[cluster.lights_shadow_rect_cache_count] = atlas_rect;
|
||||
|
||||
cluster.lights_shadow_rect_cache_count++;
|
||||
|
||||
if (cluster.lights_shadow_rect_cache_count == cluster.max_lights) {
|
||||
break; //light limit reached
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cluster.lights_shadow_rect_cache_count > 0) {
|
||||
//there are shadows to be shrunk, try to do them in parallel
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
|
||||
for (int i = 1; i < shadow_atlas->shrink_stages.size(); i++) {
|
||||
int32_t base_size = shadow_atlas->shrink_stages[0].size;
|
||||
int32_t src_size = shadow_atlas->shrink_stages[i - 1].size;
|
||||
int32_t dst_size = shadow_atlas->shrink_stages[i].size;
|
||||
|
||||
uint32_t rect_divisor = base_size / src_size;
|
||||
|
||||
int32_t shrink_limit = 8 / (src_size / dst_size);
|
||||
|
||||
//shrink in parallel for more performance
|
||||
for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) {
|
||||
Rect2i src_rect = cluster.lights_shadow_rect_cache[j];
|
||||
|
||||
src_rect.position /= rect_divisor;
|
||||
src_rect.size /= rect_divisor;
|
||||
|
||||
storage->get_effects()->reduce_shadow(shadow_atlas->shrink_stages[i - 1].texture, shadow_atlas->shrink_stages[i].texture, Size2i(src_size, src_size), src_rect, shrink_limit, compute_list);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
if (env->volumetric_fog_shadow_filter != RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED && shadow_atlas->shrink_stages[i].filter_texture.is_valid()) {
|
||||
uint32_t filter_divisor = base_size / dst_size;
|
||||
|
||||
//filter in parallel for more performance
|
||||
for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) {
|
||||
Rect2i dst_rect = cluster.lights_shadow_rect_cache[j];
|
||||
|
||||
dst_rect.position /= filter_divisor;
|
||||
dst_rect.size /= filter_divisor;
|
||||
|
||||
storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, true, false);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
for (uint32_t j = 0; j < cluster.lights_shadow_rect_cache_count; j++) {
|
||||
Rect2i dst_rect = cluster.lights_shadow_rect_cache[j];
|
||||
|
||||
dst_rect.position /= filter_divisor;
|
||||
dst_rect.size /= filter_divisor;
|
||||
|
||||
storage->get_effects()->filter_shadow(shadow_atlas->shrink_stages[i].texture, shadow_atlas->shrink_stages[i].filter_texture, Size2i(dst_size, dst_size), dst_rect, env->volumetric_fog_shadow_filter, compute_list, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
}
|
||||
|
||||
//update volumetric fog
|
||||
|
||||
if (rb->volumetric_fog->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
|
||||
//re create uniform set if needed
|
||||
|
||||
Vector<RD::Uniform> uniforms;
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 1;
|
||||
if (shadow_atlas == nullptr || shadow_atlas->shrink_stages.size() == 0) {
|
||||
u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
|
||||
} else {
|
||||
u.ids.push_back(shadow_atlas->shrink_stages[shadow_atlas->shrink_stages.size() - 1].texture);
|
||||
}
|
||||
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 2;
|
||||
if (directional_shadow.shrink_stages.size() == 0) {
|
||||
u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
|
||||
} else {
|
||||
u.ids.push_back(directional_shadow.shrink_stages[directional_shadow.shrink_stages.size() - 1].texture);
|
||||
}
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
u.binding = 3;
|
||||
u.ids.push_back(get_positional_light_buffer());
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
|
||||
u.binding = 4;
|
||||
u.ids.push_back(get_directional_light_buffer());
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 5;
|
||||
u.ids.push_back(get_cluster_builder_texture());
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
u.binding = 6;
|
||||
u.ids.push_back(get_cluster_builder_indices_buffer());
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_SAMPLER;
|
||||
u.binding = 7;
|
||||
u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 8;
|
||||
u.ids.push_back(rb->volumetric_fog->light_density_map);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 9;
|
||||
u.ids.push_back(rb->volumetric_fog->fog_map);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_SAMPLER;
|
||||
u.binding = 10;
|
||||
u.ids.push_back(shadow_sampler);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
|
||||
u.binding = 11;
|
||||
u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 12;
|
||||
for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
|
||||
u.ids.push_back(rb->giprobe_textures[i]);
|
||||
}
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_SAMPLER;
|
||||
u.binding = 13;
|
||||
u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
|
||||
|
||||
SWAP(uniforms.write[7].ids.write[0], uniforms.write[8].ids.write[0]);
|
||||
|
||||
rb->volumetric_fog->uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
|
||||
}
|
||||
|
||||
bool using_sdfgi = env->volumetric_fog_gi_inject > 0.0001 && env->sdfgi_enabled && (rb->sdfgi != nullptr);
|
||||
|
||||
if (using_sdfgi) {
|
||||
if (rb->volumetric_fog->sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) {
|
||||
Vector<RD::Uniform> uniforms;
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
|
||||
u.binding = 0;
|
||||
u.ids.push_back(gi.sdfgi_ubo);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 1;
|
||||
u.ids.push_back(rb->sdfgi->ambient_texture);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 2;
|
||||
u.ids.push_back(rb->sdfgi->occlusion_texture);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
||||
rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI), 1);
|
||||
}
|
||||
}
|
||||
|
||||
rb->volumetric_fog->length = env->volumetric_fog_length;
|
||||
rb->volumetric_fog->spread = env->volumetric_fog_detail_spread;
|
||||
|
||||
VolumetricFogShader::PushConstant push_constant;
|
||||
|
||||
Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents();
|
||||
Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents();
|
||||
float z_near = p_cam_projection.get_z_near();
|
||||
float z_far = p_cam_projection.get_z_far();
|
||||
float fog_end = env->volumetric_fog_length;
|
||||
|
||||
Vector2 fog_far_size = frustum_near_size.lerp(frustum_far_size, (fog_end - z_near) / (z_far - z_near));
|
||||
Vector2 fog_near_size;
|
||||
if (p_cam_projection.is_orthogonal()) {
|
||||
fog_near_size = fog_far_size;
|
||||
} else {
|
||||
fog_near_size = Vector2();
|
||||
}
|
||||
|
||||
push_constant.fog_frustum_size_begin[0] = fog_near_size.x;
|
||||
push_constant.fog_frustum_size_begin[1] = fog_near_size.y;
|
||||
|
||||
push_constant.fog_frustum_size_end[0] = fog_far_size.x;
|
||||
push_constant.fog_frustum_size_end[1] = fog_far_size.y;
|
||||
|
||||
push_constant.z_near = z_near;
|
||||
push_constant.z_far = z_far;
|
||||
|
||||
push_constant.fog_frustum_end = fog_end;
|
||||
|
||||
push_constant.fog_volume_size[0] = rb->volumetric_fog->width;
|
||||
push_constant.fog_volume_size[1] = rb->volumetric_fog->height;
|
||||
push_constant.fog_volume_size[2] = rb->volumetric_fog->depth;
|
||||
|
||||
push_constant.directional_light_count = p_directional_light_count;
|
||||
|
||||
Color light = env->volumetric_fog_light.to_linear();
|
||||
push_constant.light_energy[0] = light.r * env->volumetric_fog_light_energy;
|
||||
push_constant.light_energy[1] = light.g * env->volumetric_fog_light_energy;
|
||||
push_constant.light_energy[2] = light.b * env->volumetric_fog_light_energy;
|
||||
push_constant.base_density = env->volumetric_fog_density;
|
||||
|
||||
push_constant.detail_spread = env->volumetric_fog_detail_spread;
|
||||
push_constant.gi_inject = env->volumetric_fog_gi_inject;
|
||||
|
||||
push_constant.cam_rotation[0] = p_cam_transform.basis[0][0];
|
||||
push_constant.cam_rotation[1] = p_cam_transform.basis[1][0];
|
||||
push_constant.cam_rotation[2] = p_cam_transform.basis[2][0];
|
||||
push_constant.cam_rotation[3] = 0;
|
||||
push_constant.cam_rotation[4] = p_cam_transform.basis[0][1];
|
||||
push_constant.cam_rotation[5] = p_cam_transform.basis[1][1];
|
||||
push_constant.cam_rotation[6] = p_cam_transform.basis[2][1];
|
||||
push_constant.cam_rotation[7] = 0;
|
||||
push_constant.cam_rotation[8] = p_cam_transform.basis[0][2];
|
||||
push_constant.cam_rotation[9] = p_cam_transform.basis[1][2];
|
||||
push_constant.cam_rotation[10] = p_cam_transform.basis[2][2];
|
||||
push_constant.cam_rotation[11] = 0;
|
||||
push_constant.filter_axis = 0;
|
||||
push_constant.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0;
|
||||
|
||||
/* Vector2 dssize = directional_shadow_get_size();
|
||||
push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x;
|
||||
push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y;
|
||||
*/
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
|
||||
bool use_filter = volumetric_fog_filter_active;
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]);
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
|
||||
if (using_sdfgi) {
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1);
|
||||
}
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 4, 4, 4);
|
||||
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
if (use_filter) {
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
|
||||
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1);
|
||||
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
|
||||
push_constant.filter_axis = 1;
|
||||
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1);
|
||||
|
||||
RD::get_singleton()->compute_list_add_barrier(compute_list);
|
||||
}
|
||||
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant));
|
||||
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1, 8, 8, 1);
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
|
||||
Color clear_color;
|
||||
if (p_render_buffers.is_valid()) {
|
||||
@ -6190,10 +6819,25 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca
|
||||
}
|
||||
|
||||
uint32_t directional_light_count = 0;
|
||||
_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count);
|
||||
uint32_t positional_light_count = 0;
|
||||
_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count, positional_light_count);
|
||||
_setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse());
|
||||
cluster.builder.bake_cluster(); //bake to cluster
|
||||
|
||||
uint32_t gi_probe_count = 0;
|
||||
_setup_giprobes(p_render_buffers, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count, gi_probe_count);
|
||||
|
||||
if (p_render_buffers.is_valid()) {
|
||||
bool directional_shadows = false;
|
||||
for (uint32_t i = 0; i < directional_light_count; i++) {
|
||||
if (cluster.directional_lights[i].shadow_enabled) {
|
||||
directional_shadows = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_update_volumetric_fog(p_render_buffers, p_environment, p_cam_projection, p_cam_transform, p_shadow_atlas, directional_light_count, directional_shadows, positional_light_count, gi_probe_count);
|
||||
}
|
||||
|
||||
_render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
|
||||
|
||||
if (p_render_buffers.is_valid()) {
|
||||
@ -6481,6 +7125,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc
|
||||
ipush_constant.sky_color[1] = 0;
|
||||
ipush_constant.sky_color[2] = 0;
|
||||
ipush_constant.y_mult = rb->sdfgi->y_mult;
|
||||
ipush_constant.store_ambient_texture = false;
|
||||
|
||||
ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
|
||||
ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count;
|
||||
@ -6836,6 +7481,9 @@ bool RasterizerSceneRD::free(RID p_rid) {
|
||||
if (rb->sdfgi) {
|
||||
_sdfgi_erase(rb);
|
||||
}
|
||||
if (rb->volumetric_fog) {
|
||||
_volumetric_fog_erase(rb);
|
||||
}
|
||||
render_buffers_owner.free(p_rid);
|
||||
} else if (environment_owner.owns(p_rid)) {
|
||||
//not much to delete, just free it
|
||||
@ -7406,6 +8054,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
|
||||
cluster.lights = memnew_arr(Cluster::LightData, cluster.max_lights);
|
||||
cluster.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
|
||||
//defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(cluster.max_lights) + "\n";
|
||||
cluster.lights_instances = memnew_arr(RID, cluster.max_lights);
|
||||
cluster.lights_shadow_rect_cache = memnew_arr(Rect2i, cluster.max_lights);
|
||||
|
||||
cluster.max_directional_lights = 8;
|
||||
uint32_t directional_light_buffer_size = cluster.max_directional_lights * sizeof(Cluster::DirectionalLightData);
|
||||
@ -7422,8 +8072,30 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
|
||||
|
||||
cluster.builder.setup(16, 8, 24);
|
||||
|
||||
{
|
||||
String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
|
||||
Vector<String> volumetric_fog_modes;
|
||||
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
|
||||
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n");
|
||||
volumetric_fog_modes.push_back("\n#define MODE_FILTER\n");
|
||||
volumetric_fog_modes.push_back("\n#define MODE_FOG\n");
|
||||
volumetric_fog.shader.initialize(volumetric_fog_modes, defines);
|
||||
volumetric_fog.shader_version = volumetric_fog.shader.version_create();
|
||||
for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) {
|
||||
volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i));
|
||||
}
|
||||
}
|
||||
default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES);
|
||||
|
||||
{
|
||||
RD::SamplerState sampler;
|
||||
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
|
||||
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
|
||||
sampler.enable_compare = true;
|
||||
sampler.compare_op = RD::COMPARE_OP_LESS;
|
||||
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
|
||||
}
|
||||
|
||||
camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape"))));
|
||||
camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter"));
|
||||
environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"));
|
||||
@ -7441,6 +8113,11 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
|
||||
soft_shadow_kernel = memnew_arr(float, 128);
|
||||
shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality"))));
|
||||
directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality"))));
|
||||
|
||||
environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/volumetric_fog/volume_size"), GLOBAL_GET("rendering/volumetric_fog/volume_depth"));
|
||||
environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/volumetric_fog/use_filter"));
|
||||
environment_set_volumetric_fog_directional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/directional_shadow_shrink"));
|
||||
environment_set_volumetric_fog_positional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/positional_shadow_shrink"));
|
||||
}
|
||||
|
||||
RasterizerSceneRD::~RasterizerSceneRD() {
|
||||
@ -7491,7 +8168,13 @@ RasterizerSceneRD::~RasterizerSceneRD() {
|
||||
RD::get_singleton()->free(cluster.decal_buffer);
|
||||
memdelete_arr(cluster.directional_lights);
|
||||
memdelete_arr(cluster.lights);
|
||||
memdelete_arr(cluster.lights_shadow_rect_cache);
|
||||
memdelete_arr(cluster.lights_instances);
|
||||
memdelete_arr(cluster.reflections);
|
||||
memdelete_arr(cluster.decals);
|
||||
}
|
||||
|
||||
RD::get_singleton()->free(shadow_sampler);
|
||||
|
||||
directional_shadow_atlas_set_size(0);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/sky.glsl.gen.h"
|
||||
#include "servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl.gen.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
class RasterizerSceneRD : public RasterizerScene {
|
||||
@ -78,9 +79,10 @@ protected:
|
||||
};
|
||||
virtual RenderBufferData *_create_render_buffer_data() = 0;
|
||||
|
||||
void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count);
|
||||
void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
|
||||
void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform);
|
||||
void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
|
||||
void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used);
|
||||
|
||||
virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0;
|
||||
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0;
|
||||
@ -490,6 +492,12 @@ private:
|
||||
|
||||
/* SHADOW ATLAS */
|
||||
|
||||
struct ShadowShrinkStage {
|
||||
RID texture;
|
||||
RID filter_texture;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct ShadowAtlas {
|
||||
enum {
|
||||
QUADRANT_SHIFT = 27,
|
||||
@ -503,10 +511,12 @@ private:
|
||||
struct Shadow {
|
||||
RID owner;
|
||||
uint64_t version;
|
||||
uint64_t fog_version; // used for fog
|
||||
uint64_t alloc_tick;
|
||||
|
||||
Shadow() {
|
||||
version = 0;
|
||||
fog_version = 0;
|
||||
alloc_tick = 0;
|
||||
}
|
||||
};
|
||||
@ -528,6 +538,8 @@ private:
|
||||
RID fb; //for copying
|
||||
|
||||
Map<RID, uint32_t> shadow_owners;
|
||||
|
||||
Vector<ShadowShrinkStage> shrink_stages;
|
||||
};
|
||||
|
||||
RID_Owner<ShadowAtlas> shadow_atlas_owner;
|
||||
@ -556,8 +568,14 @@ private:
|
||||
int light_count = 0;
|
||||
int size = 0;
|
||||
int current_light = 0;
|
||||
|
||||
Vector<ShadowShrinkStage> shrink_stages;
|
||||
|
||||
} directional_shadow;
|
||||
|
||||
void _allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size);
|
||||
void _clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages);
|
||||
|
||||
/* SHADOW CUBEMAPS */
|
||||
|
||||
struct ShadowCubemap {
|
||||
@ -656,6 +674,17 @@ private:
|
||||
float auto_exp_scale = 0.5;
|
||||
uint64_t auto_exposure_version = 0;
|
||||
|
||||
/// Volumetric Fog
|
||||
///
|
||||
bool volumetric_fog_enabled = false;
|
||||
float volumetric_fog_density = 0.01;
|
||||
Color volumetric_fog_light = Color(0, 0, 0);
|
||||
float volumetric_fog_light_energy = 0.0;
|
||||
float volumetric_fog_length = 64.0;
|
||||
float volumetric_fog_detail_spread = 2.0;
|
||||
RS::EnvVolumetricFogShadowFilter volumetric_fog_shadow_filter = RS::ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW;
|
||||
float volumetric_fog_gi_inject = 0.0;
|
||||
|
||||
/// Glow
|
||||
|
||||
bool glow_enabled = false;
|
||||
@ -739,6 +768,7 @@ private:
|
||||
/* RENDER BUFFERS */
|
||||
|
||||
struct SDFGI;
|
||||
struct VolumetricFog;
|
||||
|
||||
struct RenderBuffers {
|
||||
enum {
|
||||
@ -759,6 +789,7 @@ private:
|
||||
|
||||
RID gi_uniform_set;
|
||||
SDFGI *sdfgi = nullptr;
|
||||
VolumetricFog *volumetric_fog = nullptr;
|
||||
|
||||
//built-in textures used for ping pong image processing and blurring
|
||||
struct Blur {
|
||||
@ -885,6 +916,7 @@ private:
|
||||
RID lightprobe_data;
|
||||
RID occlusion_texture;
|
||||
RID occlusion_data;
|
||||
RID ambient_texture; //integrates with volumetric fog
|
||||
|
||||
RID lightprobe_history_scroll; //used for scrolling lightprobes
|
||||
RID lightprobe_average_scroll; //used for scrolling lightprobes
|
||||
@ -1077,6 +1109,9 @@ private:
|
||||
|
||||
float sky_color[3];
|
||||
float y_mult;
|
||||
|
||||
uint32_t store_ambient_texture;
|
||||
uint32_t pad[3];
|
||||
};
|
||||
|
||||
SdfgiIntegrateShaderRD integrate;
|
||||
@ -1141,7 +1176,7 @@ private:
|
||||
float anisotropy_strength;
|
||||
float ao;
|
||||
float ao_size;
|
||||
uint32_t pad[1];
|
||||
uint32_t mipmaps;
|
||||
};
|
||||
|
||||
struct PushConstant {
|
||||
@ -1219,7 +1254,8 @@ private:
|
||||
float soft_shadow_size;
|
||||
float soft_shadow_scale;
|
||||
uint32_t mask;
|
||||
uint32_t pad[2];
|
||||
float shadow_volumetric_fog_fade;
|
||||
uint32_t pad;
|
||||
float projector_rect[4];
|
||||
};
|
||||
|
||||
@ -1236,10 +1272,12 @@ private:
|
||||
uint32_t shadow_enabled;
|
||||
float fade_from;
|
||||
float fade_to;
|
||||
uint32_t pad[3];
|
||||
float shadow_volumetric_fog_fade;
|
||||
float shadow_bias[4];
|
||||
float shadow_normal_bias[4];
|
||||
float shadow_transmittance_bias[4];
|
||||
float shadow_transmittance_z_scale[4];
|
||||
float shadow_z_range[4];
|
||||
float shadow_range_begin[4];
|
||||
float shadow_split_offsets[4];
|
||||
float shadow_matrices[4][16];
|
||||
@ -1283,6 +1321,9 @@ private:
|
||||
LightData *lights;
|
||||
uint32_t max_lights;
|
||||
RID light_buffer;
|
||||
RID *lights_instances;
|
||||
Rect2i *lights_shadow_rect_cache;
|
||||
uint32_t lights_shadow_rect_cache_count = 0;
|
||||
|
||||
DirectionalLightData *directional_lights;
|
||||
uint32_t max_directional_lights;
|
||||
@ -1292,6 +1333,73 @@ private:
|
||||
|
||||
} cluster;
|
||||
|
||||
struct VolumetricFog {
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t depth = 0;
|
||||
|
||||
float length;
|
||||
float spread;
|
||||
|
||||
RID light_density_map;
|
||||
RID fog_map;
|
||||
RID uniform_set;
|
||||
RID uniform_set2;
|
||||
RID sdfgi_uniform_set;
|
||||
|
||||
int last_shadow_filter = -1;
|
||||
};
|
||||
|
||||
enum {
|
||||
VOLUMETRIC_FOG_SHADER_DENSITY,
|
||||
VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI,
|
||||
VOLUMETRIC_FOG_SHADER_FILTER,
|
||||
VOLUMETRIC_FOG_SHADER_FOG,
|
||||
VOLUMETRIC_FOG_SHADER_MAX,
|
||||
};
|
||||
|
||||
struct VolumetricFogShader {
|
||||
struct PushConstant {
|
||||
float fog_frustum_size_begin[2];
|
||||
float fog_frustum_size_end[2];
|
||||
|
||||
float fog_frustum_end;
|
||||
float z_near;
|
||||
float z_far;
|
||||
uint32_t filter_axis;
|
||||
|
||||
int32_t fog_volume_size[3];
|
||||
uint32_t directional_light_count;
|
||||
|
||||
float light_energy[3];
|
||||
float base_density;
|
||||
|
||||
float detail_spread;
|
||||
float gi_inject;
|
||||
uint32_t max_gi_probes;
|
||||
uint32_t pad;
|
||||
|
||||
float cam_rotation[12];
|
||||
};
|
||||
|
||||
VolumetricFogShaderRD shader;
|
||||
|
||||
RID shader_version;
|
||||
RID pipelines[VOLUMETRIC_FOG_SHADER_MAX];
|
||||
|
||||
} volumetric_fog;
|
||||
|
||||
uint32_t volumetric_fog_depth = 128;
|
||||
uint32_t volumetric_fog_size = 128;
|
||||
bool volumetric_fog_filter_active = false;
|
||||
uint32_t volumetric_fog_directional_shadow_shrink = 512;
|
||||
uint32_t volumetric_fog_positional_shadow_shrink = 512;
|
||||
|
||||
void _volumetric_fog_erase(RenderBuffers *rb);
|
||||
void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count);
|
||||
|
||||
RID shadow_sampler;
|
||||
|
||||
uint64_t scene_pass = 0;
|
||||
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
|
||||
|
||||
@ -1391,6 +1499,12 @@ public:
|
||||
void environment_glow_set_use_bicubic_upscale(bool p_enable);
|
||||
|
||||
void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {}
|
||||
void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter);
|
||||
|
||||
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth);
|
||||
virtual void environment_set_volumetric_fog_filter_active(bool p_enable);
|
||||
virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size);
|
||||
virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size);
|
||||
|
||||
void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance);
|
||||
void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
|
||||
@ -1708,6 +1822,11 @@ public:
|
||||
float render_buffers_get_sdfgi_energy(RID p_render_buffers) const;
|
||||
RID render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const;
|
||||
|
||||
bool render_buffers_has_volumetric_fog(RID p_render_buffers) const;
|
||||
RID render_buffers_get_volumetric_fog_texture(RID p_render_buffers);
|
||||
float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
|
||||
float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
|
||||
|
||||
void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
|
||||
|
||||
void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
|
||||
|
@ -3290,6 +3290,7 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) {
|
||||
light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0;
|
||||
light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;
|
||||
light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
|
||||
light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 1.0;
|
||||
|
||||
return light_owner.make_rid(light);
|
||||
}
|
||||
|
@ -1184,6 +1184,13 @@ public:
|
||||
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const {
|
||||
const Light *light = light_owner.getornull(p_light);
|
||||
ERR_FAIL_COND_V(!light, 0.0);
|
||||
|
||||
return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE];
|
||||
}
|
||||
|
||||
RS::LightBakeMode light_get_bake_mode(RID p_light);
|
||||
uint32_t light_get_max_sdfgi_cascade(RID p_light);
|
||||
uint64_t light_get_version(RID p_light) const;
|
||||
|
@ -35,3 +35,5 @@ if "RD_GLSL" in env["BUILDERS"]:
|
||||
env.RD_GLSL("sdfgi_direct_light.glsl")
|
||||
env.RD_GLSL("sdfgi_debug.glsl")
|
||||
env.RD_GLSL("sdfgi_debug_probes.glsl")
|
||||
env.RD_GLSL("volumetric_fog.glsl")
|
||||
env.RD_GLSL("shadow_reduce.glsl")
|
||||
|
@ -0,0 +1,95 @@
|
||||
|
||||
#define CLUSTER_COUNTER_SHIFT 20
|
||||
#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
|
||||
#define CLUSTER_COUNTER_MASK 0xfff
|
||||
|
||||
struct LightData { //this structure needs to be as packed as possible
|
||||
vec3 position;
|
||||
float inv_radius;
|
||||
vec3 direction;
|
||||
float size;
|
||||
uint attenuation_energy; //attenuation
|
||||
uint color_specular; //rgb color, a specular (8 bit unorm)
|
||||
uint cone_attenuation_angle; // attenuation and angle, (16bit float)
|
||||
uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
|
||||
vec4 atlas_rect; // rect in the shadow atlas
|
||||
mat4 shadow_matrix;
|
||||
float shadow_bias;
|
||||
float shadow_normal_bias;
|
||||
float transmittance_bias;
|
||||
float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
|
||||
float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
|
||||
uint mask;
|
||||
float shadow_volumetric_fog_fade;
|
||||
uint pad;
|
||||
vec4 projector_rect; //projector rect in srgb decal atlas
|
||||
};
|
||||
|
||||
#define REFLECTION_AMBIENT_DISABLED 0
|
||||
#define REFLECTION_AMBIENT_ENVIRONMENT 1
|
||||
#define REFLECTION_AMBIENT_COLOR 2
|
||||
|
||||
struct ReflectionData {
|
||||
vec3 box_extents;
|
||||
float index;
|
||||
vec3 box_offset;
|
||||
uint mask;
|
||||
vec4 params; // intensity, 0, interior , boxproject
|
||||
vec3 ambient; // ambient color
|
||||
uint ambient_mode;
|
||||
mat4 local_matrix; // up to here for spot and omni, rest is for directional
|
||||
// notes: for ambientblend, use distance to edge to blend between already existing global environment
|
||||
};
|
||||
|
||||
struct DirectionalLightData {
|
||||
vec3 direction;
|
||||
float energy;
|
||||
vec3 color;
|
||||
float size;
|
||||
float specular;
|
||||
uint mask;
|
||||
float softshadow_angle;
|
||||
float soft_shadow_scale;
|
||||
bool blend_splits;
|
||||
bool shadow_enabled;
|
||||
float fade_from;
|
||||
float fade_to;
|
||||
uvec3 pad;
|
||||
float shadow_volumetric_fog_fade;
|
||||
vec4 shadow_bias;
|
||||
vec4 shadow_normal_bias;
|
||||
vec4 shadow_transmittance_bias;
|
||||
vec4 shadow_z_range;
|
||||
vec4 shadow_range_begin;
|
||||
vec4 shadow_split_offsets;
|
||||
mat4 shadow_matrix1;
|
||||
mat4 shadow_matrix2;
|
||||
mat4 shadow_matrix3;
|
||||
mat4 shadow_matrix4;
|
||||
vec4 shadow_color1;
|
||||
vec4 shadow_color2;
|
||||
vec4 shadow_color3;
|
||||
vec4 shadow_color4;
|
||||
vec2 uv_scale1;
|
||||
vec2 uv_scale2;
|
||||
vec2 uv_scale3;
|
||||
vec2 uv_scale4;
|
||||
};
|
||||
|
||||
struct DecalData {
|
||||
mat4 xform; //to decal transform
|
||||
vec3 inv_extents;
|
||||
float albedo_mix;
|
||||
vec4 albedo_rect;
|
||||
vec4 normal_rect;
|
||||
vec4 orm_rect;
|
||||
vec4 emission_rect;
|
||||
vec4 modulate;
|
||||
float emission_energy;
|
||||
uint mask;
|
||||
float upper_fade;
|
||||
float lower_fade;
|
||||
mat3x4 normal_xform;
|
||||
vec3 normal;
|
||||
float normal_fade;
|
||||
};
|
@ -80,7 +80,7 @@ struct GIProbeData {
|
||||
float anisotropy_strength;
|
||||
float ambient_occlusion;
|
||||
float ambient_occlusion_size;
|
||||
uint pad2;
|
||||
uint mipmaps;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 16, std140) uniform GIProbes {
|
||||
|
@ -1237,7 +1237,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
|
||||
|
||||
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
|
||||
//reconstruct depth
|
||||
shadow_z / lights.data[idx].inv_radius;
|
||||
shadow_z /= lights.data[idx].inv_radius;
|
||||
//distance to light plane
|
||||
float z = dot(spot_dir, -light_rel_vec);
|
||||
transmittance_z = z - shadow_z;
|
||||
@ -1601,6 +1601,21 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
|
||||
|
||||
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
||||
|
||||
#ifndef MODE_RENDER_DEPTH
|
||||
|
||||
vec4 volumetric_fog_process(vec2 screen_uv, float z) {
|
||||
vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length);
|
||||
if (fog_pos.z < 0.0) {
|
||||
return vec4(0.0);
|
||||
} else if (fog_pos.z < 1.0) {
|
||||
fog_pos.z = pow(fog_pos.z, scene_data.volumetric_fog_detail_spread);
|
||||
}
|
||||
|
||||
return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
#ifdef MODE_DUAL_PARABOLOID
|
||||
|
||||
@ -2187,8 +2202,8 @@ FRAGMENT_SHADER_CODE
|
||||
trans_coord /= trans_coord.w;
|
||||
|
||||
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
|
||||
shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x;
|
||||
shadow_z *= directional_lights.data[i].shadow_z_range.x;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x;
|
||||
|
||||
transmittance_z = z - shadow_z;
|
||||
}
|
||||
@ -2219,8 +2234,8 @@ FRAGMENT_SHADER_CODE
|
||||
trans_coord /= trans_coord.w;
|
||||
|
||||
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
|
||||
shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y;
|
||||
shadow_z *= directional_lights.data[i].shadow_z_range.y;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y;
|
||||
|
||||
transmittance_z = z - shadow_z;
|
||||
}
|
||||
@ -2251,8 +2266,8 @@ FRAGMENT_SHADER_CODE
|
||||
trans_coord /= trans_coord.w;
|
||||
|
||||
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
|
||||
shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z;
|
||||
shadow_z *= directional_lights.data[i].shadow_z_range.z;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z;
|
||||
|
||||
transmittance_z = z - shadow_z;
|
||||
}
|
||||
@ -2285,8 +2300,8 @@ FRAGMENT_SHADER_CODE
|
||||
trans_coord /= trans_coord.w;
|
||||
|
||||
float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
|
||||
shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w;
|
||||
shadow_z *= directional_lights.data[i].shadow_z_range.w;
|
||||
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w;
|
||||
|
||||
transmittance_z = z - shadow_z;
|
||||
}
|
||||
@ -2662,8 +2677,6 @@ FRAGMENT_SHADER_CODE
|
||||
diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point
|
||||
ambient_light *= 1.0 - metallic;
|
||||
|
||||
//fog
|
||||
|
||||
#ifdef MODE_MULTIPLE_RENDER_TARGETS
|
||||
|
||||
#ifdef MODE_UNSHADED
|
||||
@ -2679,16 +2692,27 @@ FRAGMENT_SHADER_CODE
|
||||
specular_buffer = vec4(specular_light, metallic);
|
||||
#endif
|
||||
|
||||
if (scene_data.volumetric_fog_enabled) {
|
||||
vec4 fog = volumetric_fog_process(screen_uv, -vertex.z);
|
||||
diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a);
|
||||
specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a);
|
||||
;
|
||||
}
|
||||
|
||||
#else //MODE_MULTIPLE_RENDER_TARGETS
|
||||
|
||||
#ifdef MODE_UNSHADED
|
||||
frag_color = vec4(albedo, alpha);
|
||||
#else
|
||||
frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
|
||||
//frag_color = vec4(1.0);;;
|
||||
|
||||
//frag_color = vec4(1.0);
|
||||
#endif //USE_NO_SHADING
|
||||
|
||||
if (scene_data.volumetric_fog_enabled) {
|
||||
vec4 fog = volumetric_fog_process(screen_uv, -vertex.z);
|
||||
frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
|
||||
}
|
||||
|
||||
#endif //MODE_MULTIPLE_RENDER_TARGETS
|
||||
|
||||
#endif //MODE_RENDER_DEPTH
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#define MAX_GI_PROBES 8
|
||||
|
||||
#include "cluster_data_inc.glsl"
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform DrawCall {
|
||||
uint instance_index;
|
||||
uint pad; //16 bits minimum size
|
||||
@ -94,6 +96,10 @@ layout(set = 0, binding = 3, std140) uniform SceneData {
|
||||
ivec3 sdf_size;
|
||||
bool gi_upscale_for_msaa;
|
||||
|
||||
bool volumetric_fog_enabled;
|
||||
float volumetric_fog_inv_length;
|
||||
float volumetric_fog_detail_spread;
|
||||
uint volumetric_fog_pad;
|
||||
#if 0
|
||||
vec4 ambient_light_color;
|
||||
vec4 bg_color;
|
||||
@ -163,86 +169,16 @@ layout(set = 0, binding = 4, std430) restrict readonly buffer Instances {
|
||||
}
|
||||
instances;
|
||||
|
||||
struct LightData { //this structure needs to be as packed as possible
|
||||
vec3 position;
|
||||
float inv_radius;
|
||||
vec3 direction;
|
||||
float size;
|
||||
uint attenuation_energy; //attenuation
|
||||
uint color_specular; //rgb color, a specular (8 bit unorm)
|
||||
uint cone_attenuation_angle; // attenuation and angle, (16bit float)
|
||||
uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
|
||||
vec4 atlas_rect; // rect in the shadow atlas
|
||||
mat4 shadow_matrix;
|
||||
float shadow_bias;
|
||||
float shadow_normal_bias;
|
||||
float transmittance_bias;
|
||||
float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
|
||||
float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
|
||||
uint mask;
|
||||
uint pad[2];
|
||||
vec4 projector_rect; //projector rect in srgb decal atlas
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
|
||||
LightData data[];
|
||||
}
|
||||
lights;
|
||||
|
||||
#define REFLECTION_AMBIENT_DISABLED 0
|
||||
#define REFLECTION_AMBIENT_ENVIRONMENT 1
|
||||
#define REFLECTION_AMBIENT_COLOR 2
|
||||
|
||||
struct ReflectionData {
|
||||
vec3 box_extents;
|
||||
float index;
|
||||
vec3 box_offset;
|
||||
uint mask;
|
||||
vec4 params; // intensity, 0, interior , boxproject
|
||||
vec3 ambient; // ambient color
|
||||
uint ambient_mode;
|
||||
mat4 local_matrix; // up to here for spot and omni, rest is for directional
|
||||
// notes: for ambientblend, use distance to edge to blend between already existing global environment
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 6) buffer restrict readonly ReflectionProbeData {
|
||||
ReflectionData data[];
|
||||
}
|
||||
reflections;
|
||||
|
||||
struct DirectionalLightData {
|
||||
vec3 direction;
|
||||
float energy;
|
||||
vec3 color;
|
||||
float size;
|
||||
float specular;
|
||||
uint mask;
|
||||
float softshadow_angle;
|
||||
float soft_shadow_scale;
|
||||
bool blend_splits;
|
||||
bool shadow_enabled;
|
||||
float fade_from;
|
||||
float fade_to;
|
||||
vec4 shadow_bias;
|
||||
vec4 shadow_normal_bias;
|
||||
vec4 shadow_transmittance_bias;
|
||||
vec4 shadow_transmittance_z_scale;
|
||||
vec4 shadow_range_begin;
|
||||
vec4 shadow_split_offsets;
|
||||
mat4 shadow_matrix1;
|
||||
mat4 shadow_matrix2;
|
||||
mat4 shadow_matrix3;
|
||||
mat4 shadow_matrix4;
|
||||
vec4 shadow_color1;
|
||||
vec4 shadow_color2;
|
||||
vec4 shadow_color3;
|
||||
vec4 shadow_color4;
|
||||
vec2 uv_scale1;
|
||||
vec2 uv_scale2;
|
||||
vec2 uv_scale3;
|
||||
vec2 uv_scale4;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 7, std140) uniform DirectionalLights {
|
||||
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
|
||||
}
|
||||
@ -271,31 +207,9 @@ layout(set = 0, binding = 12, std140) restrict readonly buffer LightmapCaptures
|
||||
}
|
||||
lightmap_captures;
|
||||
|
||||
#define CLUSTER_COUNTER_SHIFT 20
|
||||
#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
|
||||
#define CLUSTER_COUNTER_MASK 0xfff
|
||||
|
||||
layout(set = 0, binding = 13) uniform texture2D decal_atlas;
|
||||
layout(set = 0, binding = 14) uniform texture2D decal_atlas_srgb;
|
||||
|
||||
struct DecalData {
|
||||
mat4 xform; //to decal transform
|
||||
vec3 inv_extents;
|
||||
float albedo_mix;
|
||||
vec4 albedo_rect;
|
||||
vec4 normal_rect;
|
||||
vec4 orm_rect;
|
||||
vec4 emission_rect;
|
||||
vec4 modulate;
|
||||
float emission_energy;
|
||||
uint mask;
|
||||
float upper_fade;
|
||||
float lower_fade;
|
||||
mat3x4 normal_xform;
|
||||
vec3 normal;
|
||||
float normal_fade;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 15, std430) restrict readonly buffer Decals {
|
||||
DecalData data[];
|
||||
}
|
||||
@ -394,9 +308,7 @@ layout(set = 3, binding = 2) uniform texture2D normal_roughness_buffer;
|
||||
layout(set = 3, binding = 4) uniform texture2D ao_buffer;
|
||||
layout(set = 3, binding = 5) uniform texture2D ambient_buffer;
|
||||
layout(set = 3, binding = 6) uniform texture2D reflection_buffer;
|
||||
|
||||
layout(set = 3, binding = 7) uniform texture2DArray sdfgi_lightprobe_texture;
|
||||
|
||||
layout(set = 3, binding = 8) uniform texture3D sdfgi_occlusion_cascades;
|
||||
|
||||
struct GIProbeData {
|
||||
@ -412,7 +324,7 @@ struct GIProbeData {
|
||||
float anisotropy_strength;
|
||||
float ambient_occlusion;
|
||||
float ambient_occlusion_size;
|
||||
uint pad2;
|
||||
uint mipmaps;
|
||||
};
|
||||
|
||||
layout(set = 3, binding = 9, std140) uniform GIProbes {
|
||||
@ -420,6 +332,8 @@ layout(set = 3, binding = 9, std140) uniform GIProbes {
|
||||
}
|
||||
gi_probes;
|
||||
|
||||
layout(set = 3, binding = 10) uniform texture3D volumetric_fog_texture;
|
||||
|
||||
#endif
|
||||
|
||||
/* Set 4 Skeleton & Instancing (Multimesh) */
|
||||
|
@ -37,6 +37,8 @@ layout(rgba32i, set = 0, binding = 12) uniform restrict iimage2D lightprobe_aver
|
||||
|
||||
layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_average_parent_texture;
|
||||
|
||||
layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture;
|
||||
|
||||
layout(set = 1, binding = 0) uniform textureCube sky_irradiance;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler linear_sampler_mipmaps;
|
||||
@ -68,6 +70,9 @@ layout(push_constant, binding = 0, std430) uniform Params {
|
||||
|
||||
vec3 sky_color;
|
||||
float y_mult;
|
||||
|
||||
bool store_ambient_texture;
|
||||
uint pad[3];
|
||||
}
|
||||
params;
|
||||
|
||||
@ -319,6 +324,13 @@ void main() {
|
||||
|
||||
imageStore(lightprobe_history_texture, prev_pos, ivalue);
|
||||
imageStore(lightprobe_average_texture, average_pos, average);
|
||||
|
||||
if (params.store_ambient_texture && i == 0) {
|
||||
ivec3 ambient_pos = ivec3(pos, int(params.cascade));
|
||||
vec4 ambient_light = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS);
|
||||
ambient_light *= 0.88622; // SHL0
|
||||
imageStore(lightprobe_ambient_texture, ambient_pos, ambient_light);
|
||||
}
|
||||
}
|
||||
#endif // MODE PROCESS
|
||||
|
||||
|
105
servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl
Normal file
105
servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl
Normal file
@ -0,0 +1,105 @@
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#define BLOCK_SIZE 8
|
||||
|
||||
layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in;
|
||||
|
||||
#ifdef MODE_REDUCE
|
||||
|
||||
shared float tmp_data[BLOCK_SIZE * BLOCK_SIZE];
|
||||
const uint swizzle_table[BLOCK_SIZE] = uint[](0, 4, 2, 6, 1, 5, 3, 7);
|
||||
const uint unswizzle_table[BLOCK_SIZE] = uint[](0, 0, 0, 1, 0, 2, 1, 3);
|
||||
|
||||
#endif
|
||||
|
||||
layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D source_depth;
|
||||
layout(r32f, set = 0, binding = 1) uniform restrict writeonly image2D dst_depth;
|
||||
|
||||
layout(push_constant, binding = 1, std430) uniform Params {
|
||||
ivec2 source_size;
|
||||
ivec2 source_offset;
|
||||
uint min_size;
|
||||
uint gaussian_kernel_version;
|
||||
ivec2 filter_dir;
|
||||
}
|
||||
params;
|
||||
|
||||
void main() {
|
||||
#ifdef MODE_REDUCE
|
||||
|
||||
uvec2 pos = gl_LocalInvocationID.xy;
|
||||
|
||||
ivec2 image_offset = params.source_offset;
|
||||
ivec2 image_pos = image_offset + ivec2(gl_GlobalInvocationID.xy);
|
||||
uint dst_t = swizzle_table[pos.y] * BLOCK_SIZE + swizzle_table[pos.x];
|
||||
tmp_data[dst_t] = imageLoad(source_depth, min(image_pos, params.source_size - ivec2(1))).r;
|
||||
ivec2 image_size = params.source_size;
|
||||
|
||||
uint t = pos.y * BLOCK_SIZE + pos.x;
|
||||
|
||||
//neighbours
|
||||
uint size = BLOCK_SIZE;
|
||||
|
||||
do {
|
||||
groupMemoryBarrier();
|
||||
barrier();
|
||||
|
||||
size >>= 1;
|
||||
image_size >>= 1;
|
||||
image_offset >>= 1;
|
||||
|
||||
if (all(lessThan(pos, uvec2(size)))) {
|
||||
uint nx = t + size;
|
||||
uint ny = t + (BLOCK_SIZE * size);
|
||||
uint nxy = ny + size;
|
||||
|
||||
tmp_data[t] += tmp_data[nx];
|
||||
tmp_data[t] += tmp_data[ny];
|
||||
tmp_data[t] += tmp_data[nxy];
|
||||
tmp_data[t] /= 4.0;
|
||||
}
|
||||
|
||||
} while (size > params.min_size);
|
||||
|
||||
if (all(lessThan(pos, uvec2(size)))) {
|
||||
image_pos = ivec2(unswizzle_table[size + pos.x], unswizzle_table[size + pos.y]);
|
||||
image_pos += image_offset + ivec2(gl_WorkGroupID.xy) * int(size);
|
||||
|
||||
image_size = max(ivec2(1), image_size); //in case image size became 0
|
||||
|
||||
if (all(lessThan(image_pos, uvec2(image_size)))) {
|
||||
imageStore(dst_depth, image_pos, vec4(tmp_data[t]));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MODE_FILTER
|
||||
|
||||
ivec2 image_pos = params.source_offset + ivec2(gl_GlobalInvocationID.xy);
|
||||
if (any(greaterThanEqual(image_pos, params.source_size))) {
|
||||
return;
|
||||
}
|
||||
|
||||
ivec2 clamp_min = ivec2(params.source_offset);
|
||||
ivec2 clamp_max = ivec2(params.source_size) - 1;
|
||||
|
||||
//gaussian kernel, size 9, sigma 4
|
||||
const int kernel_size = 9;
|
||||
const float gaussian_kernel[kernel_size * 3] = float[](
|
||||
0.000229, 0.005977, 0.060598, 0.241732, 0.382928, 0.241732, 0.060598, 0.005977, 0.000229,
|
||||
0.028532, 0.067234, 0.124009, 0.179044, 0.20236, 0.179044, 0.124009, 0.067234, 0.028532,
|
||||
0.081812, 0.101701, 0.118804, 0.130417, 0.134535, 0.130417, 0.118804, 0.101701, 0.081812);
|
||||
float accum = 0.0;
|
||||
for (int i = 0; i < kernel_size; i++) {
|
||||
ivec2 ofs = clamp(image_pos + params.filter_dir * (i - kernel_size / 2), clamp_min, clamp_max);
|
||||
accum += imageLoad(source_depth, ofs).r * gaussian_kernel[params.gaussian_kernel_version + i];
|
||||
}
|
||||
|
||||
imageStore(dst_depth, image_pos, vec4(accum));
|
||||
|
||||
#endif
|
||||
}
|
530
servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl
Normal file
530
servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl
Normal file
@ -0,0 +1,530 @@
|
||||
#[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#if defined(MODE_FOG) || defined(MODE_FILTER)
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DENSITY)
|
||||
|
||||
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||
|
||||
#endif
|
||||
|
||||
#include "cluster_data_inc.glsl"
|
||||
|
||||
#define M_PI 3.14159265359
|
||||
|
||||
layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
|
||||
layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
|
||||
|
||||
layout(set = 0, binding = 3, std430) restrict readonly buffer Lights {
|
||||
LightData data[];
|
||||
}
|
||||
lights;
|
||||
|
||||
layout(set = 0, binding = 4, std140) uniform DirectionalLights {
|
||||
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
|
||||
}
|
||||
directional_lights;
|
||||
|
||||
layout(set = 0, binding = 5) uniform utexture3D cluster_texture;
|
||||
|
||||
layout(set = 0, binding = 6, std430) restrict readonly buffer ClusterData {
|
||||
uint indices[];
|
||||
}
|
||||
cluster_data;
|
||||
|
||||
layout(set = 0, binding = 7) uniform sampler linear_sampler;
|
||||
|
||||
#ifdef MODE_DENSITY
|
||||
layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
|
||||
layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
|
||||
#endif
|
||||
|
||||
#ifdef MODE_FOG
|
||||
layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
|
||||
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
|
||||
#endif
|
||||
|
||||
#ifdef MODE_FILTER
|
||||
layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
|
||||
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
|
||||
#endif
|
||||
|
||||
layout(set = 0, binding = 10) uniform sampler shadow_sampler;
|
||||
|
||||
#define MAX_GI_PROBES 8
|
||||
|
||||
struct GIProbeData {
|
||||
mat4 xform;
|
||||
vec3 bounds;
|
||||
float dynamic_range;
|
||||
|
||||
float bias;
|
||||
float normal_bias;
|
||||
bool blend_ambient;
|
||||
uint texture_slot;
|
||||
|
||||
float anisotropy_strength;
|
||||
float ambient_occlusion;
|
||||
float ambient_occlusion_size;
|
||||
uint mipmaps;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 11, std140) uniform GIProbes {
|
||||
GIProbeData data[MAX_GI_PROBES];
|
||||
}
|
||||
gi_probes;
|
||||
|
||||
layout(set = 0, binding = 12) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
|
||||
|
||||
layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
|
||||
|
||||
#ifdef ENABLE_SDFGI
|
||||
|
||||
// SDFGI Integration on set 1
|
||||
#define SDFGI_MAX_CASCADES 8
|
||||
|
||||
struct SDFGIProbeCascadeData {
|
||||
vec3 position;
|
||||
float to_probe;
|
||||
ivec3 probe_world_offset;
|
||||
float to_cell; // 1/bounds * grid_size
|
||||
};
|
||||
|
||||
layout(set = 1, binding = 0, std140) uniform SDFGI {
|
||||
vec3 grid_size;
|
||||
uint max_cascades;
|
||||
|
||||
bool use_occlusion;
|
||||
int probe_axis_size;
|
||||
float probe_to_uvw;
|
||||
float normal_bias;
|
||||
|
||||
vec3 lightprobe_tex_pixel_size;
|
||||
float energy;
|
||||
|
||||
vec3 lightprobe_uv_offset;
|
||||
float y_mult;
|
||||
|
||||
vec3 occlusion_clamp;
|
||||
uint pad3;
|
||||
|
||||
vec3 occlusion_renormalize;
|
||||
uint pad4;
|
||||
|
||||
vec3 cascade_probe_size;
|
||||
uint pad5;
|
||||
|
||||
SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
|
||||
}
|
||||
sdfgi;
|
||||
|
||||
layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
|
||||
|
||||
layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
|
||||
|
||||
#endif //SDFGI
|
||||
|
||||
layout(push_constant, binding = 0, std430) uniform Params {
|
||||
vec2 fog_frustum_size_begin;
|
||||
vec2 fog_frustum_size_end;
|
||||
|
||||
float fog_frustum_end;
|
||||
float z_near;
|
||||
float z_far;
|
||||
int filter_axis;
|
||||
|
||||
ivec3 fog_volume_size;
|
||||
uint directional_light_count;
|
||||
|
||||
vec3 light_color;
|
||||
float base_density;
|
||||
|
||||
float detail_spread;
|
||||
float gi_inject;
|
||||
uint max_gi_probes;
|
||||
uint pad;
|
||||
|
||||
mat3x4 cam_rotation;
|
||||
}
|
||||
params;
|
||||
|
||||
float get_depth_at_pos(float cell_depth_size, int z) {
|
||||
float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
|
||||
d = pow(d, params.detail_spread);
|
||||
return params.fog_frustum_end * d;
|
||||
}
|
||||
|
||||
vec3 hash3f(uvec3 x) {
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = (x >> 16) ^ x;
|
||||
return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
|
||||
|
||||
#ifdef MODE_DENSITY
|
||||
|
||||
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
|
||||
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
|
||||
return; //do not compute
|
||||
}
|
||||
|
||||
vec3 posf = vec3(pos);
|
||||
|
||||
//posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
|
||||
|
||||
vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
|
||||
fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
|
||||
|
||||
vec3 view_pos;
|
||||
view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
|
||||
view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
|
||||
view_pos.y = -view_pos.y;
|
||||
|
||||
vec3 total_light = params.light_color;
|
||||
|
||||
float total_density = params.base_density;
|
||||
float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
|
||||
//compute directional lights
|
||||
|
||||
for (uint i = 0; i < params.directional_light_count; i++) {
|
||||
vec3 shadow_attenuation = vec3(1.0);
|
||||
|
||||
if (directional_lights.data[i].shadow_enabled) {
|
||||
float depth_z = -view_pos.z;
|
||||
|
||||
vec4 pssm_coord;
|
||||
vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
|
||||
vec3 light_dir = directional_lights.data[i].direction;
|
||||
vec4 v = vec4(view_pos, 1.0);
|
||||
float z_range;
|
||||
|
||||
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
|
||||
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
|
||||
pssm_coord /= pssm_coord.w;
|
||||
z_range = directional_lights.data[i].shadow_z_range.x;
|
||||
|
||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
|
||||
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
|
||||
pssm_coord /= pssm_coord.w;
|
||||
z_range = directional_lights.data[i].shadow_z_range.y;
|
||||
|
||||
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
|
||||
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
|
||||
pssm_coord /= pssm_coord.w;
|
||||
z_range = directional_lights.data[i].shadow_z_range.z;
|
||||
|
||||
} else {
|
||||
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
|
||||
pssm_coord /= pssm_coord.w;
|
||||
z_range = directional_lights.data[i].shadow_z_range.w;
|
||||
}
|
||||
|
||||
float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
|
||||
float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
|
||||
|
||||
/*
|
||||
//float shadow = textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord);
|
||||
float shadow = 0.0;
|
||||
for(float xi=-1;xi<=1;xi++) {
|
||||
for(float yi=-1;yi<=1;yi++) {
|
||||
vec2 ofs = vec2(xi,yi) * 1.5 * params.directional_shadow_pixel_size;
|
||||
shadow += textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord + vec4(ofs,0.0,0.0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
shadow /= 3.0 * 3.0;
|
||||
|
||||
*/
|
||||
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
|
||||
|
||||
shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
|
||||
}
|
||||
|
||||
total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy / M_PI;
|
||||
}
|
||||
|
||||
//compute lights from cluster
|
||||
|
||||
vec3 cluster_pos;
|
||||
cluster_pos.xy = fog_unit_pos.xy;
|
||||
cluster_pos.z = clamp((abs(view_pos.z) - params.z_near) / (params.z_far - params.z_near), 0.0, 1.0);
|
||||
|
||||
uvec4 cluster_cell = texture(usampler3D(cluster_texture, linear_sampler), cluster_pos);
|
||||
|
||||
uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT;
|
||||
uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK;
|
||||
|
||||
for (uint i = 0; i < omni_light_count; i++) {
|
||||
uint light_index = cluster_data.indices[omni_light_pointer + i];
|
||||
|
||||
vec3 light_pos = lights.data[i].position;
|
||||
float d = distance(lights.data[i].position, view_pos) * lights.data[i].inv_radius;
|
||||
vec3 shadow_attenuation = vec3(1.0);
|
||||
|
||||
if (d < 1.0) {
|
||||
vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy);
|
||||
vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular);
|
||||
|
||||
float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x);
|
||||
|
||||
vec3 light = attenuation_energy.y * color_specular.rgb / M_PI;
|
||||
|
||||
vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled);
|
||||
|
||||
if (shadow_color_enabled.a > 0.5) {
|
||||
//has shadow
|
||||
vec4 v = vec4(view_pos, 1.0);
|
||||
|
||||
vec4 splane = (lights.data[i].shadow_matrix * v);
|
||||
float shadow_len = length(splane.xyz); //need to remember shadow len from here
|
||||
|
||||
splane.xyz = normalize(splane.xyz);
|
||||
vec4 clamp_rect = lights.data[i].atlas_rect;
|
||||
|
||||
if (splane.z >= 0.0) {
|
||||
splane.z += 1.0;
|
||||
|
||||
clamp_rect.y += clamp_rect.w;
|
||||
|
||||
} else {
|
||||
splane.z = 1.0 - splane.z;
|
||||
}
|
||||
|
||||
splane.xy /= splane.z;
|
||||
|
||||
splane.xy = splane.xy * 0.5 + 0.5;
|
||||
splane.z = shadow_len * lights.data[i].inv_radius;
|
||||
splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
|
||||
splane.w = 1.0; //needed? i think it should be 1 already
|
||||
|
||||
float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
|
||||
float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade);
|
||||
|
||||
shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
|
||||
}
|
||||
total_light += light * attenuation * shadow_attenuation;
|
||||
}
|
||||
}
|
||||
|
||||
uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT;
|
||||
uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK;
|
||||
|
||||
for (uint i = 0; i < spot_light_count; i++) {
|
||||
uint light_index = cluster_data.indices[spot_light_pointer + i];
|
||||
|
||||
vec3 light_pos = lights.data[i].position;
|
||||
vec3 light_rel_vec = lights.data[i].position - view_pos;
|
||||
float d = length(light_rel_vec) * lights.data[i].inv_radius;
|
||||
vec3 shadow_attenuation = vec3(1.0);
|
||||
|
||||
if (d < 1.0) {
|
||||
vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy);
|
||||
vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular);
|
||||
|
||||
float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x);
|
||||
|
||||
vec3 spot_dir = lights.data[i].direction;
|
||||
vec2 spot_att_angle = unpackHalf2x16(lights.data[i].cone_attenuation_angle);
|
||||
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y);
|
||||
float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y));
|
||||
attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x);
|
||||
|
||||
vec3 light = attenuation_energy.y * color_specular.rgb / M_PI;
|
||||
|
||||
vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled);
|
||||
|
||||
if (shadow_color_enabled.a > 0.5) {
|
||||
//has shadow
|
||||
vec4 v = vec4(view_pos, 1.0);
|
||||
|
||||
vec4 splane = (lights.data[i].shadow_matrix * v);
|
||||
splane /= splane.w;
|
||||
|
||||
float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
|
||||
float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade);
|
||||
|
||||
shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
|
||||
}
|
||||
|
||||
total_light += light * attenuation * shadow_attenuation;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 world_pos = mat3(params.cam_rotation) * view_pos;
|
||||
|
||||
for (uint i = 0; i < params.max_gi_probes; i++) {
|
||||
vec3 position = (gi_probes.data[i].xform * vec4(world_pos, 1.0)).xyz;
|
||||
|
||||
//this causes corrupted pixels, i have no idea why..
|
||||
if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, gi_probes.data[i].bounds))))) {
|
||||
position /= gi_probes.data[i].bounds;
|
||||
|
||||
vec4 light = vec4(0.0);
|
||||
for (uint j = 0; j < gi_probes.data[i].mipmaps; j++) {
|
||||
vec4 slight = textureLod(sampler3D(gi_probe_textures[i], linear_sampler_with_mipmaps), position, float(j));
|
||||
float a = (1.0 - light.a);
|
||||
light += a * slight;
|
||||
}
|
||||
|
||||
light.rgb *= gi_probes.data[i].dynamic_range * params.gi_inject;
|
||||
|
||||
total_light += light.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
//sdfgi
|
||||
#ifdef ENABLE_SDFGI
|
||||
|
||||
{
|
||||
float blend = -1.0;
|
||||
vec3 ambient_total = vec3(0.0);
|
||||
|
||||
for (uint i = 0; i < sdfgi.max_cascades; i++) {
|
||||
vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
|
||||
|
||||
if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
|
||||
continue; //skip cascade
|
||||
}
|
||||
|
||||
vec3 base_pos = floor(cascade_pos);
|
||||
ivec3 probe_base_pos = ivec3(base_pos);
|
||||
|
||||
vec4 ambient_accum = vec4(0.0);
|
||||
|
||||
ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
|
||||
tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
|
||||
|
||||
for (uint j = 0; j < 8; j++) {
|
||||
ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
|
||||
ivec3 probe_posi = probe_base_pos;
|
||||
probe_posi += offset;
|
||||
|
||||
// Compute weight
|
||||
|
||||
vec3 probe_pos = vec3(probe_posi);
|
||||
vec3 probe_to_pos = cascade_pos - probe_pos;
|
||||
|
||||
vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
|
||||
float weight = trilinear.x * trilinear.y * trilinear.z;
|
||||
|
||||
// Compute lightprobe occlusion
|
||||
|
||||
if (sdfgi.use_occlusion) {
|
||||
ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
|
||||
vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
|
||||
|
||||
vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
|
||||
occ_pos.z += float(i);
|
||||
if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
|
||||
occ_pos.x += 1.0;
|
||||
}
|
||||
|
||||
occ_pos *= sdfgi.occlusion_renormalize;
|
||||
float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
|
||||
|
||||
weight *= max(occlusion, 0.01);
|
||||
}
|
||||
|
||||
// Compute ambient texture position
|
||||
|
||||
ivec3 uvw = tex_pos;
|
||||
uvw.xy += offset.xy;
|
||||
uvw.x += offset.z * sdfgi.probe_axis_size;
|
||||
|
||||
vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
|
||||
|
||||
ambient_accum.rgb += ambient * weight;
|
||||
ambient_accum.a += weight;
|
||||
}
|
||||
|
||||
if (ambient_accum.a > 0) {
|
||||
ambient_accum.rgb /= ambient_accum.a;
|
||||
}
|
||||
ambient_total = ambient_accum.rgb;
|
||||
break;
|
||||
}
|
||||
|
||||
total_light += ambient_total * params.gi_inject;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
imageStore(density_map, pos, vec4(total_light, total_density));
|
||||
#endif
|
||||
|
||||
#ifdef MODE_FOG
|
||||
|
||||
ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
|
||||
|
||||
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
|
||||
return; //do not compute
|
||||
}
|
||||
|
||||
vec4 fog_accum = vec4(0.0);
|
||||
float prev_z = 0.0;
|
||||
|
||||
float t = 1.0;
|
||||
|
||||
for (int i = 0; i < params.fog_volume_size.z; i++) {
|
||||
//compute fog position
|
||||
ivec3 fog_pos = pos + ivec3(0, 0, i);
|
||||
//get fog value
|
||||
vec4 fog = imageLoad(density_map, fog_pos);
|
||||
|
||||
//get depth at cell pos
|
||||
float z = get_depth_at_pos(fog_cell_size.z, i);
|
||||
//get distance from previos pos
|
||||
float d = abs(prev_z - z);
|
||||
//compute exinction based on beer's
|
||||
float extinction = t * exp(-d * fog.a);
|
||||
//compute alpha based on different of extinctions
|
||||
float alpha = t - extinction;
|
||||
//update extinction
|
||||
t = extinction;
|
||||
|
||||
fog_accum += vec4(fog.rgb * alpha, alpha);
|
||||
prev_z = z;
|
||||
|
||||
vec4 fog_value;
|
||||
|
||||
if (fog_accum.a > 0.0) {
|
||||
fog_value = vec4(fog_accum.rgb / fog_accum.a, 1.0 - t);
|
||||
} else {
|
||||
fog_value = vec4(0.0);
|
||||
}
|
||||
|
||||
imageStore(fog_map, fog_pos, fog_value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODE_FILTER
|
||||
|
||||
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
|
||||
|
||||
const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
|
||||
|
||||
const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
|
||||
ivec3 offset = filter_dir[params.filter_axis];
|
||||
|
||||
vec4 accum = vec4(0.0);
|
||||
for (int i = -3; i <= 3; i++) {
|
||||
accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
|
||||
}
|
||||
|
||||
imageStore(dest_map, pos, accum);
|
||||
|
||||
#endif
|
||||
}
|
@ -565,6 +565,12 @@ public:
|
||||
BIND5(environment_set_fog, RID, bool, const Color &, const Color &, float)
|
||||
BIND7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
|
||||
BIND5(environment_set_fog_height, RID, bool, float, float, float)
|
||||
BIND9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter)
|
||||
|
||||
BIND2(environment_set_volumetric_fog_volume_size, int, int)
|
||||
BIND1(environment_set_volumetric_fog_filter_active, bool)
|
||||
BIND1(environment_set_volumetric_fog_directional_shadow_shrink_size, int)
|
||||
BIND1(environment_set_volumetric_fog_positional_shadow_shrink_size, int)
|
||||
|
||||
BIND11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float)
|
||||
BIND1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount)
|
||||
|
@ -482,6 +482,12 @@ public:
|
||||
FUNC5(environment_set_fog, RID, bool, const Color &, const Color &, float)
|
||||
FUNC7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
|
||||
FUNC5(environment_set_fog_height, RID, bool, float, float, float)
|
||||
FUNC9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter)
|
||||
|
||||
FUNC2(environment_set_volumetric_fog_volume_size, int, int)
|
||||
FUNC1(environment_set_volumetric_fog_filter_active, bool)
|
||||
FUNC1(environment_set_volumetric_fog_directional_shadow_shrink_size, int)
|
||||
FUNC1(environment_set_volumetric_fog_positional_shadow_shrink_size, int)
|
||||
|
||||
FUNC3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &)
|
||||
|
||||
|
@ -2411,6 +2411,17 @@ RenderingServer::RenderingServer() {
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/probe_ray_count", PropertyInfo(Variant::INT, "rendering/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)"));
|
||||
GLOBAL_DEF("rendering/sdfgi/frames_to_converge", 1);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/frames_to_converge", PropertyInfo(Variant::INT, "rendering/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)"));
|
||||
|
||||
GLOBAL_DEF("rendering/volumetric_fog/volume_size", 64);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1"));
|
||||
GLOBAL_DEF("rendering/volumetric_fog/volume_depth", 128);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/volume_depth", PropertyInfo(Variant::INT, "rendering/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1"));
|
||||
GLOBAL_DEF("rendering/volumetric_fog/use_filter", 0);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/use_filter", PropertyInfo(Variant::INT, "rendering/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)"));
|
||||
GLOBAL_DEF("rendering/volumetric_fog/directional_shadow_shrink", 512);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/directional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/directional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1"));
|
||||
GLOBAL_DEF("rendering/volumetric_fog/positional_shadow_shrink", 512);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/positional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/positional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1"));
|
||||
}
|
||||
|
||||
RenderingServer::~RenderingServer() {
|
||||
|
@ -390,6 +390,7 @@ public:
|
||||
LIGHT_PARAM_SHADOW_BIAS,
|
||||
LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
|
||||
LIGHT_PARAM_SHADOW_BLUR,
|
||||
LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
|
||||
LIGHT_PARAM_TRANSMITTANCE_BIAS,
|
||||
LIGHT_PARAM_MAX
|
||||
};
|
||||
@ -865,6 +866,19 @@ public:
|
||||
virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0;
|
||||
virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0;
|
||||
|
||||
enum EnvVolumetricFogShadowFilter {
|
||||
ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED,
|
||||
ENV_VOLUMETRIC_FOG_SHADOW_FILTER_LOW,
|
||||
ENV_VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM,
|
||||
ENV_VOLUMETRIC_FOG_SHADOW_FILTER_HIGH,
|
||||
};
|
||||
|
||||
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
|
||||
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
|
||||
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
|
||||
virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0;
|
||||
virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0;
|
||||
|
||||
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0;
|
||||
|
||||
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user