Skip to content

Commit 8a3f12a

Browse files
committed
add microshadows
1 parent eb3d6d8 commit 8a3f12a

File tree

12 files changed

+92
-10
lines changed

12 files changed

+92
-10
lines changed

doc/classes/BaseMaterial3D.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@
102102
<member name="ao_light_affect" type="float" setter="set_ao_light_affect" getter="get_ao_light_affect" default="0.0">
103103
Amount that ambient occlusion affects lighting from lights. If [code]0[/code], ambient occlusion only affects ambient light. If [code]1[/code], ambient occlusion affects lights just as much as it affects ambient light. This can be used to impact the strength of the ambient occlusion effect, but typically looks unrealistic.
104104
</member>
105+
<member name="ao_micro_shadows" type="float" setter="set_micro_shadows" getter="get_micro_shadows" default="0.85">
106+
Amount of micro shadowing applied to ambient occlusion. Higher values result in more shadowing in crevices and corners, while lower values result in less shadowing. This can help improve the appearance of ambient occlusion by simulating small details embedded in the materials.
107+
[b]Note:[/b] This setting only has an effect if directional lights are present in the scene. It does not work with [OmniLight3D] and [SpotLight3D].
108+
[b]Note:[/b] For best results, this setting requires an [member ao_texture] and a [member normal_texture] generated with the same pipeline.
109+
[b]Note:[/b] This setting can serve as a PBR alternative to [member ao_light_affect].
110+
</member>
105111
<member name="ao_on_uv2" type="bool" setter="set_flag" getter="get_flag" default="false">
106112
If [code]true[/code], use [code]UV2[/code] coordinates to look up from the [member ao_texture].
107113
</member>

drivers/gles3/shaders/scene.glsl

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,13 @@ float SchlickFresnel(float u) {
14931493
return m2 * m2 * m; // pow(m,5)
14941494
}
14951495

1496+
// Brinck and Maximov 2016, "The Technical Art of Uncharted 4"
1497+
float compute_micro_shadowing(float NoL, float ao, float opacity) {
1498+
float aperture = 2.0 * ao * ao;
1499+
float microshadow = clamp(NoL + aperture - 1.0, 0.0, 1.0);
1500+
return mix(1.0, microshadow, opacity);
1501+
}
1502+
14961503
void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha, vec2 screen_uv,
14971504
#ifdef LIGHT_BACKLIGHT_USED
14981505
vec3 backlight,
@@ -2013,7 +2020,9 @@ void main() {
20132020
#endif
20142021

20152022
float ao = 1.0;
2023+
float direct_ao = 0.0;
20162024
float ao_light_affect = 0.0;
2025+
float micro_shadows = 0.0;
20172026

20182027
float alpha = 1.0;
20192028

@@ -2349,7 +2358,7 @@ void main() {
23492358
#endif // !AMBIENT_LIGHT_DISABLED
23502359

23512360
// convert ao to direct light ao
2352-
ao = mix(1.0, ao, ao_light_affect);
2361+
direct_ao = mix(1.0, ao, ao_light_affect);
23532362
#ifndef AMBIENT_LIGHT_DISABLED
23542363
{
23552364
#if defined(DIFFUSE_TOON)
@@ -2503,7 +2512,7 @@ void main() {
25032512
normal_output_buffer.rgb = normal * 0.5 + 0.5;
25042513
normal_output_buffer.a = 0.0;
25052514

2506-
orm_output_buffer.r = ao;
2515+
orm_output_buffer.r = direct_ao;
25072516
orm_output_buffer.g = roughness;
25082517
orm_output_buffer.b = metallic;
25092518
orm_output_buffer.a = 1.0;
@@ -2701,6 +2710,12 @@ void main() {
27012710
float directional_shadow = 1.0f;
27022711
#endif // SHADOWS_DISABLED
27032712

2713+
#ifdef MICRO_SHADOWS_USED
2714+
float NdotL = dot(normal, directional_lights[directional_shadow_index].direction);
2715+
// Disable microshadowing when facing away from light.
2716+
directional_shadow *= NdotL >= 0.0 ? compute_micro_shadowing(NdotL, ao, micro_shadows) : 1.0;
2717+
#endif
2718+
27042719
#ifndef USE_VERTEX_LIGHTING
27052720
if (bool(directional_lights[directional_shadow_index].mask & layer_mask)) {
27062721
light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, directional_lights[directional_shadow_index].specular, albedo, alpha, screen_uv,

drivers/gles3/storage/material_storage.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,7 @@ MaterialStorage::MaterialStorage() {
13061306
actions.renames["BACKLIGHT"] = "backlight";
13071307
actions.renames["AO"] = "ao";
13081308
actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
1309+
actions.renames["MICRO_SHADOWS"] = "micro_shadows";
13091310
actions.renames["EMISSION"] = "emission";
13101311
actions.renames["POINT_COORD"] = "gl_PointCoord";
13111312
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
@@ -1354,6 +1355,7 @@ MaterialStorage::MaterialStorage() {
13541355
actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
13551356
actions.usage_defines["AO"] = "#define AO_USED\n";
13561357
actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
1358+
actions.usage_defines["MICRO_SHADOWS"] = "#define MICRO_SHADOWS_USED\n";
13571359
actions.usage_defines["UV"] = "#define UV_USED\n";
13581360
actions.usage_defines["UV2"] = "#define UV2_USED\n";
13591361
actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";

scene/resources/material.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ void BaseMaterial3D::init_shaders() {
623623
shader_names->grow = "grow";
624624

625625
shader_names->ao_light_affect = "ao_light_affect";
626+
shader_names->micro_shadows = "micro_shadows";
626627

627628
shader_names->proximity_fade_distance = "proximity_fade_distance";
628629
shader_names->distance_fade_min = "distance_fade_min";
@@ -1128,6 +1129,7 @@ uniform sampler2D texture_flowmap : hint_anisotropy, %s;
11281129
uniform sampler2D texture_ambient_occlusion : hint_default_white, %s;
11291130
uniform vec4 ao_texture_channel;
11301131
uniform float ao_light_affect : hint_range(0.0, 1.0, 0.01);
1132+
uniform float micro_shadows : hint_range(0.0, 1.0, 0.01);
11311133
)",
11321134
texfilter_str);
11331135
}
@@ -1949,6 +1951,7 @@ void fragment() {)";
19491951
}
19501952

19511953
code += " AO_LIGHT_AFFECT = ao_light_affect;\n";
1954+
code += " MICRO_SHADOWS = micro_shadows;\n";
19521955
}
19531956

19541957
if (features[FEATURE_SUBSURFACE_SCATTERING]) {
@@ -2245,6 +2248,15 @@ float BaseMaterial3D::get_ao_light_affect() const {
22452248
return ao_light_affect;
22462249
}
22472250

2251+
void BaseMaterial3D::set_micro_shadows(float p_micro_shadows) {
2252+
micro_shadows = p_micro_shadows;
2253+
_material_set_param(shader_names->micro_shadows, p_micro_shadows);
2254+
}
2255+
2256+
float BaseMaterial3D::get_micro_shadows() const {
2257+
return micro_shadows;
2258+
}
2259+
22482260
void BaseMaterial3D::set_clearcoat(float p_clearcoat) {
22492261
clearcoat = p_clearcoat;
22502262
_material_set_param(shader_names->clearcoat, p_clearcoat);
@@ -3508,6 +3520,9 @@ void BaseMaterial3D::_bind_methods() {
35083520
ClassDB::bind_method(D_METHOD("set_ao_light_affect", "amount"), &BaseMaterial3D::set_ao_light_affect);
35093521
ClassDB::bind_method(D_METHOD("get_ao_light_affect"), &BaseMaterial3D::get_ao_light_affect);
35103522

3523+
ClassDB::bind_method(D_METHOD("set_micro_shadows", "amount"), &BaseMaterial3D::set_micro_shadows);
3524+
ClassDB::bind_method(D_METHOD("get_micro_shadows"), &BaseMaterial3D::get_micro_shadows);
3525+
35113526
ClassDB::bind_method(D_METHOD("set_alpha_scissor_threshold", "threshold"), &BaseMaterial3D::set_alpha_scissor_threshold);
35123527
ClassDB::bind_method(D_METHOD("get_alpha_scissor_threshold"), &BaseMaterial3D::get_alpha_scissor_threshold);
35133528

@@ -3657,6 +3672,7 @@ void BaseMaterial3D::_bind_methods() {
36573672
ADD_GROUP("Ambient Occlusion", "ao_");
36583673
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "ao_enabled", PROPERTY_HINT_GROUP_ENABLE), "set_feature", "get_feature", FEATURE_AMBIENT_OCCLUSION);
36593674
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_light_affect", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ao_light_affect", "get_ao_light_affect");
3675+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_micro_shadows", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_micro_shadows", "get_micro_shadows");
36603676
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "ao_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_AMBIENT_OCCLUSION);
36613677
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "ao_on_uv2"), "set_flag", "get_flag", FLAG_AO_ON_UV2);
36623678
ADD_PROPERTY(PropertyInfo(Variant::INT, "ao_texture_channel", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Gray"), "set_ao_texture_channel", "get_ao_texture_channel");
@@ -3971,6 +3987,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
39713987
set_distance_fade_max_distance(10);
39723988

39733989
set_ao_light_affect(0.0);
3990+
set_micro_shadows(0.85);
39743991

39753992
set_metallic_texture_channel(TEXTURE_CHANNEL_RED);
39763993
set_roughness_texture_channel(TEXTURE_CHANNEL_RED);

scene/resources/material.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ class BaseMaterial3D : public Material {
502502
StringName distance_fade_min;
503503
StringName distance_fade_max;
504504
StringName ao_light_affect;
505+
StringName micro_shadows;
505506

506507
StringName metallic_texture_channel;
507508
StringName ao_texture_channel;
@@ -564,6 +565,7 @@ class BaseMaterial3D : public Material {
564565
float alpha_antialiasing_edge = 0.0f;
565566
bool grow_enabled = false;
566567
float ao_light_affect = 0.0f;
568+
float micro_shadows = 0.85f;
567569
float grow = 0.0f;
568570
int particles_anim_h_frames = 0;
569571
int particles_anim_v_frames = 0;
@@ -677,6 +679,9 @@ class BaseMaterial3D : public Material {
677679
void set_ao_light_affect(float p_ao_light_affect);
678680
float get_ao_light_affect() const;
679681

682+
void set_micro_shadows(float p_micro_shadows);
683+
float get_micro_shadows() const;
684+
680685
void set_clearcoat(float p_clearcoat);
681686
float get_clearcoat() const;
682687

servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,7 @@ void SceneShaderForwardClustered::init(const String p_defines) {
747747
actions.renames["BACKLIGHT"] = "backlight";
748748
actions.renames["AO"] = "ao";
749749
actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
750+
actions.renames["MICRO_SHADOWS"] = "micro_shadows";
750751
actions.renames["EMISSION"] = "emission";
751752
actions.renames["POINT_COORD"] = "gl_PointCoord";
752753
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
@@ -795,6 +796,7 @@ void SceneShaderForwardClustered::init(const String p_defines) {
795796
actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
796797
actions.usage_defines["AO"] = "#define AO_USED\n";
797798
actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
799+
actions.usage_defines["MICRO_SHADOWS"] = "#define MICRO_SHADOWS_USED\n";
798800
actions.usage_defines["UV"] = "#define UV_USED\n";
799801
actions.usage_defines["UV2"] = "#define UV2_USED\n";
800802
actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";

servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
682682
actions.renames["BACKLIGHT"] = "backlight_highp";
683683
actions.renames["AO"] = "ao_highp";
684684
actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect_highp";
685+
actions.renames["MICRO_SHADOWS"] = "micro_shadows_highp";
685686
actions.renames["EMISSION"] = "emission_highp";
686687
actions.renames["POINT_COORD"] = "gl_PointCoord";
687688
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
@@ -730,6 +731,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
730731
actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
731732
actions.usage_defines["AO"] = "#define AO_USED\n";
732733
actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
734+
actions.usage_defines["MICRO_SHADOWS"] = "#define MICRO_SHADOWS_USED\n";
733735
actions.usage_defines["UV"] = "#define UV_USED\n";
734736
actions.usage_defines["UV2"] = "#define UV2_USED\n";
735737
actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";

servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,9 @@ void fragment_shader(in SceneData scene_data) {
12031203
#endif
12041204

12051205
float ao = 1.0;
1206+
float direct_ao = 0.0;
12061207
float ao_light_affect = 0.0;
1208+
float micro_shadows = 0.0;
12071209

12081210
float alpha_highp = float(instances.data[instance_index].flags >> INSTANCE_FLAGS_FADE_SHIFT) / float(255.0);
12091211

@@ -2130,7 +2132,7 @@ void fragment_shader(in SceneData scene_data) {
21302132
#endif // AMBIENT_LIGHT_DISABLED
21312133

21322134
// convert ao to direct light ao
2133-
ao = mix(1.0, ao, ao_light_affect);
2135+
direct_ao = mix(1.0, ao, ao_light_affect);
21342136

21352137
//this saves some VGPRs
21362138
vec3 f0 = F0(metallic, specular, albedo);
@@ -2534,6 +2536,12 @@ void fragment_shader(in SceneData scene_data) {
25342536
shadow = 1.0;
25352537
#endif
25362538

2539+
#ifdef MICRO_SHADOWS_USED
2540+
float NdotL = dot(normal, directional_lights.data[i].direction);
2541+
// Disable microshadowing when facing away from light.
2542+
shadow *= NdotL >= 0.0 ? compute_micro_shadowing(NdotL, ao, micro_shadows) : 1.0;
2543+
#endif
2544+
25372545
float size_A = sc_use_directional_soft_shadows() ? directional_lights.data[i].size : 0.0;
25382546

25392547
light_compute(normal, directional_lights.data[i].direction, normalize(view), size_A,
@@ -2820,7 +2828,7 @@ void fragment_shader(in SceneData scene_data) {
28202828
normal_output_buffer.a = 0.0;
28212829
depth_output_buffer.r = -vertex.z;
28222830

2823-
orm_output_buffer.r = ao;
2831+
orm_output_buffer.r = direct_ao;
28242832
orm_output_buffer.g = roughness;
28252833
orm_output_buffer.b = metallic;
28262834
orm_output_buffer.a = sss_strength;
@@ -2861,8 +2869,8 @@ void fragment_shader(in SceneData scene_data) {
28612869
diffuse_light *= albedo; // ambient must be multiplied by albedo at the end
28622870

28632871
// apply direct light AO
2864-
diffuse_light *= ao;
2865-
direct_specular_light *= ao;
2872+
diffuse_light *= direct_ao;
2873+
direct_specular_light *= direct_ao;
28662874

28672875
// apply metallic
28682876
diffuse_light *= 1.0 - metallic;

servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,13 @@ vec3 get_energy_compensation(vec3 f0, float env) {
470470
return 1.0 + f0 * (1.0 / env - 1.0);
471471
}
472472

473+
// Brinck and Maximov 2016, "The Technical Art of Uncharted 4"
474+
float compute_micro_shadowing(float NoL, float ao, float opacity) {
475+
float aperture = 2.0 * ao * ao;
476+
float microshadow = clamp(NoL + aperture - 1.0, 0.0, 1.0);
477+
return mix(1.0, microshadow, opacity);
478+
}
479+
473480
/* Set 2 Skeleton & Instancing (can change per item) */
474481

475482
layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {

servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,9 @@ void main() {
11231123
#endif
11241124

11251125
float ao_highp = 1.0;
1126+
float direct_ao_highp = 0.0;
11261127
float ao_light_affect_highp = 0.0;
1128+
float micro_shadows_highp = 0.0;
11271129

11281130
float alpha_highp = 1.0;
11291131

@@ -1234,6 +1236,8 @@ void main() {
12341236
hvec2 anisotropy_flow = hvec2(anisotropy_flow_highp);
12351237
half ao = half(ao_highp);
12361238
half ao_light_affect = half(ao_light_affect_highp);
1239+
half direct_ao = half(direct_ao_highp);
1240+
half micro_shadows = half(micro_shadows_highp);
12371241
half alpha = half(alpha_highp);
12381242
half normal_map_depth = half(normal_map_depth_highp);
12391243
half sss_strength = half(sss_strength_highp);
@@ -1786,7 +1790,7 @@ void main() {
17861790
#endif // !AMBIENT_LIGHT_DISABLED
17871791

17881792
// convert ao to direct light ao
1789-
ao = mix(half(1.0), ao, ao_light_affect);
1793+
direct_ao = mix(half(1.0), ao, ao_light_affect);
17901794

17911795
//this saves some VGPRs
17921796
hvec3 f0 = F0(metallic, specular, albedo);
@@ -2029,6 +2033,12 @@ void main() {
20292033
shadow = half(1.0);
20302034
#endif
20312035

2036+
#ifdef MICRO_SHADOWS_USED
2037+
float NdotL = dot(normal, directional_lights.data[i].direction);
2038+
// Disable microshadowing when facing away from light.
2039+
shadow *= NdotL >= 0.0 ? compute_micro_shadowing(NdotL, ao, micro_shadows) : 1.0;
2040+
#endif
2041+
20322042
float size_A = sc_use_light_soft_shadows() ? directional_lights.data[i].size : 0.0;
20332043

20342044
light_compute(normal, hvec3(directional_lights.data[i].direction), view, saturateHalf(size_A),
@@ -2161,7 +2171,7 @@ void main() {
21612171
normal_output_buffer.a = 0.0;
21622172
depth_output_buffer.r = -vertex.z;
21632173

2164-
orm_output_buffer.r = ao;
2174+
orm_output_buffer.r = direct_ao;
21652175
orm_output_buffer.g = roughness;
21662176
orm_output_buffer.b = metallic;
21672177
orm_output_buffer.a = sss_strength;
@@ -2176,8 +2186,8 @@ void main() {
21762186
diffuse_light *= albedo; // ambient must be multiplied by albedo at the end
21772187

21782188
// apply direct light AO
2179-
diffuse_light *= ao;
2180-
direct_specular_light *= ao;
2189+
diffuse_light *= direct_ao;
2190+
direct_specular_light *= direct_ao;
21812191

21822192
// apply metallic
21832193
diffuse_light *= half(1.0) - metallic;

0 commit comments

Comments
 (0)