Merge pull request #52918 from Calinou/add-new-light-attenuation-3.x

This commit is contained in:
Rémi Verschelde 2021-10-08 23:08:49 +02:00 committed by GitHub
commit 302ad4e600
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 120 additions and 4 deletions

View file

@ -1377,6 +1377,10 @@
<member name="rendering/quality/shading/force_vertex_shading.mobile" type="bool" setter="" getter="" default="true">
Lower-end override for [member rendering/quality/shading/force_vertex_shading] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/shading/use_physical_light_attenuation" type="bool" setter="" getter="" default="false">
If [code]true[/code], enables new physical light attenuation for [OmniLight]s and [SpotLight]s. This results in more realistic lighting appearance with a very small performance cost. When physical light attenuation is enabled, lights will appear to be darker as a result of the new attenuation formula. This can be compensated by adjusting the lights' energy or attenuation values.
Changes to this setting will only be applied upon restarting the application.
</member>
<member name="rendering/quality/shadow_atlas/cubemap_size" type="int" setter="" getter="" default="512">
Size for cubemap into which the shadow is rendered before being copied into the shadow atlas. A higher number can result in higher resolution shadows when used with a higher [member rendering/quality/shadow_atlas/size]. Setting higher than a quarter of the [member rendering/quality/shadow_atlas/size] will not result in a perceptible increase in visual quality.
</member>

View file

@ -2427,6 +2427,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
storage->info.render.surface_switch_count++;
}
state.scene_shader.set_conditional(SceneShaderGLES2::USE_PHYSICAL_LIGHT_ATTENUATION, storage->config.use_physical_light_attenuation);
bool octahedral_compression = ((RasterizerStorageGLES2::Surface *)e->geometry)->format & VisualServer::ArrayFormat::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION;
if (octahedral_compression != prev_octahedral_compression) {
state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_OCTAHEDRAL_COMPRESSION, octahedral_compression);

View file

@ -6508,6 +6508,8 @@ void RasterizerStorageGLES2::initialize() {
GLOBAL_DEF_RST("rendering/quality/lightmapping/use_bicubic_sampling.mobile", false);
config.use_lightmap_filter_bicubic = GLOBAL_GET("rendering/quality/lightmapping/use_bicubic_sampling");
config.use_physical_light_attenuation = GLOBAL_GET("rendering/quality/shading/use_physical_light_attenuation");
int orphan_mode = GLOBAL_GET("rendering/2d/opengl/legacy_orphan_buffers");
switch (orphan_mode) {
default: {

View file

@ -58,6 +58,7 @@ public:
bool use_anisotropic_filter;
bool use_skeleton_software;
bool use_lightmap_filter_bicubic;
bool use_physical_light_attenuation;
int max_vertex_texture_image_units;
int max_texture_image_units;

View file

@ -206,6 +206,15 @@ uniform highp float light_spot_attenuation;
uniform highp float light_spot_range;
uniform highp float light_spot_angle;
float get_omni_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
nd = max(1.0 - nd, 0.0);
nd *= nd; // nd^2
return nd * pow(max(distance, 0.0001), -decay);
}
void light_compute(
vec3 N,
vec3 L,
@ -546,9 +555,12 @@ VERTEX_SHADER_CODE
float normalized_distance = light_length / light_range;
if (normalized_distance < 1.0) {
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
float omni_attenuation = get_omni_attenuation(light_length, 1.0 / light_range, light_attenuation);
#else
float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation);
#endif
vec3 attenuation = vec3(omni_attenuation);
light_att = vec3(omni_attenuation);
} else {
light_att = vec3(0.0);
@ -565,7 +577,12 @@ VERTEX_SHADER_CODE
float normalized_distance = light_length / light_range;
if (normalized_distance < 1.0) {
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
float spot_attenuation = get_omni_attenuation(light_length, 1.0 / light_range, light_attenuation);
#else
float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation);
#endif
vec3 spot_dir = light_direction;
float spot_cutoff = light_spot_angle;
@ -1222,6 +1239,17 @@ float GTR1(float NdotH, float a) {
return (a2 - 1.0) / (M_PI * log(a2) * t);
}
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
float get_omni_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
nd = max(1.0 - nd, 0.0);
nd *= nd; // nd^2
return nd * pow(max(distance, 0.0001), -decay);
}
#endif
void light_compute(
vec3 N,
vec3 L,
@ -1852,7 +1880,11 @@ FRAGMENT_SHADER_CODE
float normalized_distance = light_length / light_range;
if (normalized_distance < 1.0) {
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
float omni_attenuation = get_omni_attenuation(light_length, 1.0 / light_range, light_attenuation);
#else
float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation);
#endif
light_att = vec3(omni_attenuation);
} else {
@ -2134,7 +2166,12 @@ FRAGMENT_SHADER_CODE
float normalized_distance = light_length / light_range;
if (normalized_distance < 1.0) {
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
float spot_attenuation = get_omni_attenuation(light_length, 1.0 / light_range, light_attenuation);
#else
float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation);
#endif
vec3 spot_dir = light_direction;
float spot_cutoff = light_spot_angle;

View file

@ -2112,6 +2112,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
}
}
state.scene_shader.set_conditional(SceneShaderGLES3::USE_PHYSICAL_LIGHT_ATTENUATION, storage->config.use_physical_light_attenuation);
bool octahedral_compression = ((RasterizerStorageGLES3::Surface *)e->geometry)->format & VisualServer::ArrayFormat::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION;
if (octahedral_compression != prev_octahedral_compression) {
state.scene_shader.set_conditional(SceneShaderGLES3::ENABLE_OCTAHEDRAL_COMPRESSION, octahedral_compression);

View file

@ -8252,6 +8252,8 @@ void RasterizerStorageGLES3::initialize() {
GLOBAL_DEF("rendering/quality/lightmapping/use_bicubic_sampling.mobile", false);
config.use_lightmap_filter_bicubic = GLOBAL_GET("rendering/quality/lightmapping/use_bicubic_sampling");
config.use_physical_light_attenuation = GLOBAL_GET("rendering/quality/shading/use_physical_light_attenuation");
config.use_depth_prepass = bool(GLOBAL_GET("rendering/quality/depth_prepass/enable"));
if (config.use_depth_prepass) {
String vendors = GLOBAL_GET("rendering/quality/depth_prepass/disable_for_vendors");

View file

@ -74,6 +74,7 @@ public:
bool use_fast_texture_filter;
bool use_anisotropic_filter;
bool use_lightmap_filter_bicubic;
bool use_physical_light_attenuation;
bool s3tc_supported;
bool latc_supported;

View file

@ -234,11 +234,27 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float roughness, in
}
}
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
float get_omni_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
nd = max(1.0 - nd, 0.0);
nd *= nd; // nd^2
return nd * pow(max(distance, 0.0001), -decay);
}
#endif
void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) {
vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex;
float light_length = length(light_rel_vec);
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
vec3 light_attenuation = vec3(get_omni_attenuation(light_length, omni_lights[idx].light_pos_inv_radius.w, omni_lights[idx].light_direction_attenuation.w));
#else
float normalized_distance = light_length * omni_lights[idx].light_pos_inv_radius.w;
vec3 light_attenuation = vec3(pow(max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w));
#endif
light_compute(normal, normalize(light_rel_vec), eye_vec, omni_lights[idx].light_color_energy.rgb * light_attenuation, roughness, diffuse, specular);
}
@ -246,8 +262,14 @@ void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float r
void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) {
vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex;
float light_length = length(light_rel_vec);
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
vec3 light_attenuation = vec3(get_omni_attenuation(light_length, spot_lights[idx].light_pos_inv_radius.w, spot_lights[idx].light_direction_attenuation.w));
#else
float normalized_distance = light_length * spot_lights[idx].light_pos_inv_radius.w;
vec3 light_attenuation = vec3(pow(max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w));
#endif
vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz;
float spot_cutoff = spot_lights[idx].light_params.y;
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff);
@ -1250,13 +1272,28 @@ in highp float dp_clip;
#endif
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
float get_omni_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
nd = max(1.0 - nd, 0.0);
nd *= nd; // nd^2
return nd * pow(max(distance, 0.0001), -decay);
}
#endif
void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) {
vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex;
float light_length = length(light_rel_vec);
float normalized_distance = light_length * omni_lights[idx].light_pos_inv_radius.w;
float omni_attenuation;
if (normalized_distance < 1.0) {
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
omni_attenuation = get_omni_attenuation(light_length, omni_lights[idx].light_pos_inv_radius.w, omni_lights[idx].light_direction_attenuation.w);
#else
omni_attenuation = pow(1.0 - normalized_distance, omni_lights[idx].light_direction_attenuation.w);
#endif
} else {
omni_attenuation = 0.0;
}
@ -1316,7 +1353,11 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi
float normalized_distance = light_length * spot_lights[idx].light_pos_inv_radius.w;
float spot_attenuation;
if (normalized_distance < 1.0) {
spot_attenuation = pow(1.0 - normalized_distance, spot_lights[idx].light_direction_attenuation.w);
#ifdef USE_PHYSICAL_LIGHT_ATTENUATION
spot_attenuation = get_omni_attenuation(light_length, spot_lights[idx].light_pos_inv_radius.w, spot_lights[idx].light_direction_attenuation.w);
#else
spot_attenuation = pow(1.0 - normalized_distance, omni_lights[idx].light_direction_attenuation.w);
#endif
} else {
spot_attenuation = 0.0;
}

View file

@ -704,6 +704,15 @@ _ALWAYS_INLINE_ float uniform_rand() {
return float(state) / float(UINT32_MAX);
}
float LightmapperCPU::_get_omni_attenuation(float distance, float inv_range, float decay) const {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
nd = MAX(1.0 - nd, 0.0);
nd *= nd; // nd^2
return nd * powf(MAX(distance, 0.0001f), -decay);
}
void LightmapperCPU::_compute_direct_light(uint32_t p_idx, void *r_lightmap) {
LightmapTexel *lightmap = (LightmapTexel *)r_lightmap;
for (unsigned int i = 0; i < lights.size(); ++i) {
@ -734,7 +743,11 @@ void LightmapperCPU::_compute_direct_light(uint32_t p_idx, void *r_lightmap) {
soft_shadowing_disk_size = light.size / dist;
if (light.type == LIGHT_TYPE_OMNI) {
attenuation = powf(1.0 - dist / light.range, light.attenuation);
if (parameters.use_physical_light_attenuation) {
attenuation = _get_omni_attenuation(dist, 1.0f / light.range, light.attenuation);
} else {
attenuation = powf(1.0 - dist / light.range, light.attenuation);
}
} else /* (light.type == LIGHT_TYPE_SPOT) */ {
float angle = Math::acos(light.direction.dot(light_to_point));
@ -743,7 +756,12 @@ void LightmapperCPU::_compute_direct_light(uint32_t p_idx, void *r_lightmap) {
}
float normalized_dist = dist * (1.0f / MAX(0.001f, light.range));
float norm_light_attenuation = Math::pow(MAX(1.0f - normalized_dist, 0.001f), light.attenuation);
float norm_light_attenuation;
if (parameters.use_physical_light_attenuation) {
norm_light_attenuation = _get_omni_attenuation(dist, 1.0f / light.range, light.attenuation);
} else {
norm_light_attenuation = Math::pow(MAX(1.0f - normalized_dist, 0.001f), light.attenuation);
}
float spot_cutoff = Math::cos(light.spot_angle);
float scos = MAX(light_to_point.dot(light.direction), spot_cutoff);
@ -1279,6 +1297,7 @@ LightmapperCPU::BakeError LightmapperCPU::bake(BakeQuality p_quality, bool p_use
// Collect parameters
parameters.use_denoiser = p_use_denoiser;
parameters.use_physical_light_attenuation = bool(GLOBAL_GET("rendering/quality/shading/use_physical_light_attenuation"));
parameters.bias = p_bias;
parameters.bounces = p_bounces;
parameters.bounce_indirect_energy = p_bounce_indirect_energy;

View file

@ -85,6 +85,7 @@ class LightmapperCPU : public Lightmapper {
float bounce_indirect_energy;
int samples;
bool use_denoiser = true;
bool use_physical_light_attenuation = false;
Ref<Image> environment_panorama;
Basis environment_transform;
};
@ -151,6 +152,8 @@ class LightmapperCPU : public Lightmapper {
Vector3 _fix_sample_position(const Vector3 &p_position, const Vector3 &p_texel_center, const Vector3 &p_normal, const Vector3 &p_tangent, const Vector3 &p_bitangent, const Vector2 &p_texel_size);
void _plot_triangle(const Vector2 *p_vertices, const Vector3 *p_positions, const Vector3 *p_normals, const Vector2 *p_uvs, const Ref<Image> &p_albedo_texture, const Ref<Image> &p_emission_texture, Vector2i p_size, LocalVector<LightmapTexel> &r_texels, LocalVector<int> &r_lightmap_indices);
float _get_omni_attenuation(float distance, float inv_range, float decay) const;
void _compute_direct_light(uint32_t p_idx, void *r_lightmap);
void _compute_indirect_light(uint32_t p_idx, void *r_lightmap);

View file

@ -2636,6 +2636,8 @@ VisualServer::VisualServer() {
GLOBAL_DEF_RST("rendering/misc/mesh_storage/split_stream", false);
GLOBAL_DEF_RST("rendering/quality/shading/use_physical_light_attenuation", false);
GLOBAL_DEF("rendering/quality/depth_prepass/enable", true);
GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple");