Skip to content

Commit

Permalink
Merge pull request #37749 from clayjohn/Vulkan-improved-ss
Browse files Browse the repository at this point in the history
Add vogel filter and settings to soft shadows
  • Loading branch information
akien-mga authored Apr 12, 2020
2 parents 451d5bd + 621f6f0 commit 06748a2
Show file tree
Hide file tree
Showing 17 changed files with 339 additions and 146 deletions.
9 changes: 9 additions & 0 deletions doc/classes/Light3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
<member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false">
If [code]true[/code], the light only appears in the editor and will not be visible at runtime.
</member>
<member name="light_angular_distance" type="float" setter="set_param" getter="get_param" default="0.0">
Angular size of the light in degrees. Only available for [DirectionalLight3D]s. For reference, the sun from earth is approximately [code]0.5[/code].
</member>
<member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light3D.BakeMode" default="1">
The light's bake mode. See [enum BakeMode].
</member>
Expand All @@ -53,12 +56,18 @@
<member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false">
If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
</member>
<member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0">
The size of the light in Godot units. Only available for [OmniLight3D]s and [SpotLight3D]s.
</member>
<member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
The intensity of the specular blob in objects affected by the light. At [code]0[/code] the light becomes a pure diffuse light.
</member>
<member name="shadow_bias" type="float" setter="set_param" getter="get_param" default="0.15">
Used to adjust shadow appearance. Too small a value results in self-shadowing, while too large a value causes shadows to separate from casters. Adjust as needed.
</member>
<member name="shadow_blur" type="float" setter="set_param" getter="get_param" default="1.0">
Blurs the edges of the shadow. Can be used to hide pixel artifacts in low resolution shadow maps. A high value can make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible.
</member>
<member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color( 0, 0, 0, 1 )">
The color of shadows cast by this light.
</member>
Expand Down
14 changes: 10 additions & 4 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,12 @@
<member name="rendering/quality/directional_shadow/size.mobile" type="int" setter="" getter="" default="2048">
Lower-end override for [member rendering/quality/directional_shadow/size] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/directional_shadow/soft_shadow_quality" type="int" setter="" getter="" default="2">
Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
</member>
<member name="rendering/quality/directional_shadow/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0">
Lower-end override for [member rendering/quality/directional_shadow/soft_shadow_quality] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/driver/driver_name" type="String" setter="" getter="" default="&quot;Vulkan&quot;">
The video driver to use ("GLES2" or "Vulkan").
[b]Note:[/b] The backend in use can be overridden at runtime via the [code]--rendering-driver[/code] command line argument.
Expand Down Expand Up @@ -1098,11 +1104,11 @@
<member name="rendering/quality/shadow_atlas/size.mobile" type="int" setter="" getter="" default="2048">
Lower-end override for [member rendering/quality/shadow_atlas/size] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/shadows/filter_mode" type="int" setter="" getter="" default="1">
Shadow filter mode. Higher-quality settings result in smoother shadows that flicker less when moving. "Disabled" is the fastest option, but also has the lowest quality. "PCF5" is smoother but is also slower. "PCF13" is the smoothest option, but is also the slowest.
<member name="rendering/quality/shadows/soft_shadow_quality" type="int" setter="" getter="" default="2">
Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
</member>
<member name="rendering/quality/shadows/filter_mode.mobile" type="int" setter="" getter="" default="0">
Lower-end override for [member rendering/quality/shadows/filter_mode] on mobile devices, due to performance concerns or driver support.
<member name="rendering/quality/shadows/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0">
Lower-end override for [member rendering/quality/shadows/soft_shadow_quality] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/ssao/half_size" type="bool" setter="" getter="" default="false">
</member>
Expand Down
12 changes: 6 additions & 6 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3282,18 +3282,18 @@
<constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam">
The light's range.
</constant>
<constant name="LIGHT_PARAM_ATTENUATION" value="4" enum="LightParam">
<constant name="LIGHT_PARAM_SIZE" value="4" enum="LightParam">
The size of the light when using spot light or omni light. The angular size of the light when using directional light.
</constant>
<constant name="LIGHT_PARAM_ATTENUATION" value="5" enum="LightParam">
The light's attenuation.
</constant>
<constant name="LIGHT_PARAM_SPOT_ANGLE" value="5" enum="LightParam">
<constant name="LIGHT_PARAM_SPOT_ANGLE" value="6" enum="LightParam">
The spotlight's angle.
</constant>
<constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="6" enum="LightParam">
<constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="7" enum="LightParam">
The spotlight's attenuation.
</constant>
<constant name="LIGHT_PARAM_CONTACT_SHADOW_SIZE" value="7" enum="LightParam">
Scales the shadow color.
</constant>
<constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="8" enum="LightParam">
Max distance that shadows will be rendered.
</constant>
Expand Down
6 changes: 4 additions & 2 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,10 @@ void EditorNode::_notification(int p_what) {
float sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale");
float sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale");
RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale);
RS::ShadowFilter shadow_filter = RS::ShadowFilter(int(GLOBAL_GET("rendering/quality/shadows/filter_mode")));
RS::get_singleton()->shadow_filter_set(shadow_filter);
RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality")));
RS::get_singleton()->shadows_quality_set(shadows_quality);
RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality")));
RS::get_singleton()->directional_shadow_quality_set(directional_shadow_quality);
}

ResourceImporterTexture::get_singleton()->update_imports();
Expand Down
3 changes: 3 additions & 0 deletions scene/3d/light_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,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_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");
ADD_GROUP("", "");
Expand All @@ -291,6 +292,7 @@ void Light3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR);
BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS);
BIND_ENUM_CONSTANT(PARAM_MAX);

Expand Down Expand Up @@ -335,6 +337,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
set_param(PARAM_SHADOW_FADE_START, 0.8);
set_param(PARAM_SHADOW_PANCAKE_SIZE, 20.0);
set_param(PARAM_SHADOW_BLUR, 1.0);
set_param(PARAM_SHADOW_BIAS, 0.02);
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
set_param(PARAM_TRANSMITTANCE_BIAS, 0.05);
Expand Down
1 change: 1 addition & 0 deletions scene/3d/light_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class Light3D : public VisualInstance3D {
PARAM_SHADOW_NORMAL_BIAS = RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
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_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS,
PARAM_MAX = RS::LIGHT_PARAM_MAX
};
Expand Down
3 changes: 2 additions & 1 deletion servers/rendering/rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ class RasterizerScene {
virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;

virtual void shadow_filter_set(RS::ShadowFilter p_filter) = 0;
virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0;
virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0;

struct InstanceBase;

Expand Down
26 changes: 24 additions & 2 deletions servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_arra
}
}

static _FORCE_INLINE_ void store_soft_shadow_kernel(const float *p_kernel, float *p_array) {

for (int i = 0; i < 128; i++) {
p_array[i] = p_kernel[i];
}
}

/* SCENE SHADER */
void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) {
//compile
Expand Down Expand Up @@ -1099,10 +1106,18 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer

scene_state.ubo.z_far = p_zfar;
scene_state.ubo.z_near = p_znear;
scene_state.ubo.shadow_filter_mode = shadow_filter_get();

scene_state.ubo.pancake_shadows = p_pancake_shadows;
scene_state.ubo.shadow_blocker_count = 16;

store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);

scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get();
scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get();
scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get();
scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get();

scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y;
Expand Down Expand Up @@ -1722,6 +1737,8 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
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.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);

float softshadow_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
if (softshadow_angle > 0.0) {
// I know tan(0) is 0, but let's not risk it with numerical precision.
Expand All @@ -1730,6 +1747,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.softshadow_angle = Math::tan(Math::deg2rad(softshadow_angle));
} else {
light_data.softshadow_angle = 0;
light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
}
}

Expand Down Expand Up @@ -1840,6 +1858,8 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.atlas_rect[2] = rect.size.width;
light_data.atlas_rect[3] = rect.size.height;

light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);

if (type == RS::LIGHT_OMNI) {

light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
Expand All @@ -1852,6 +1872,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.soft_shadow_size = size;
} else {
light_data.soft_shadow_size = 0.0;
light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
}

} else if (type == RS::LIGHT_SPOT) {
Expand All @@ -1875,6 +1896,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
} else {
light_data.soft_shadow_size = 0.0;
light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
}
}
} else {
Expand Down
18 changes: 13 additions & 5 deletions servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,9 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float shadow_normal_bias;
float transmittance_bias;
float soft_shadow_size;
float soft_shadow_scale;
uint32_t mask;
uint32_t pad[3];
uint32_t pad[2];
};

struct DirectionalLightData {
Expand All @@ -289,7 +290,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float specular;
uint32_t mask;
float softshadow_angle;
uint32_t pad[1];
float soft_shadow_scale;
uint32_t blend_splits;
uint32_t shadow_enabled;
float fade_from;
Expand Down Expand Up @@ -361,10 +362,17 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float reflection_multiplier;

uint32_t pancake_shadows;
uint32_t shadow_filter_mode;
uint32_t pad;

float directional_penumbra_shadow_kernel[128]; //32 vec4s
float directional_soft_shadow_kernel[128];
float penumbra_shadow_kernel[128];
float soft_shadow_kernel[128];

uint32_t shadow_blocker_count;
uint32_t shadow_pad[3];
uint32_t directional_penumbra_shadow_samples;
uint32_t directional_soft_shadow_samples;
uint32_t penumbra_shadow_samples;
uint32_t soft_shadow_samples;

float ambient_light_color_energy[4];

Expand Down
105 changes: 102 additions & 3 deletions servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@

uint64_t RasterizerSceneRD::auto_exposure_counter = 2;

void get_vogel_disk(float *r_kernel, int p_sample_count) {
const float golden_angle = 2.4;

for (int i = 0; i < p_sample_count; i++) {
float r = Math::sqrt(float(i) + 0.5) / Math::sqrt(float(p_sample_count));
float theta = float(i) * golden_angle;

r_kernel[i * 4] = Math::cos(theta) * r;
r_kernel[i * 4 + 1] = Math::sin(theta) * r;
}
}

void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) {

rd.layers.clear();
Expand Down Expand Up @@ -3578,8 +3590,86 @@ void RasterizerSceneRD::sub_surface_scattering_set_scale(float p_scale, float p_
sss_depth_scale = p_depth_scale;
}

void RasterizerSceneRD::shadow_filter_set(RS::ShadowFilter p_filter) {
shadow_filter = p_filter;
void RasterizerSceneRD::shadows_quality_set(RS::ShadowQuality p_quality) {

ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum");

if (shadows_quality != p_quality) {
shadows_quality = p_quality;

switch (shadows_quality) {
case RS::SHADOW_QUALITY_HARD: {
penumbra_shadow_samples = 4;
soft_shadow_samples = 1;
shadows_quality_radius = 1.0;
} break;
case RS::SHADOW_QUALITY_SOFT_LOW: {
penumbra_shadow_samples = 8;
soft_shadow_samples = 4;
shadows_quality_radius = 2.0;
} break;
case RS::SHADOW_QUALITY_SOFT_MEDIUM: {
penumbra_shadow_samples = 12;
soft_shadow_samples = 8;
shadows_quality_radius = 2.0;
} break;
case RS::SHADOW_QUALITY_SOFT_HIGH: {
penumbra_shadow_samples = 24;
soft_shadow_samples = 16;
shadows_quality_radius = 3.0;
} break;
case RS::SHADOW_QUALITY_SOFT_ULTRA: {
penumbra_shadow_samples = 32;
soft_shadow_samples = 32;
shadows_quality_radius = 4.0;
} break;
case RS::SHADOW_QUALITY_MAX:
break;
}
get_vogel_disk(penumbra_shadow_kernel, penumbra_shadow_samples);
get_vogel_disk(soft_shadow_kernel, soft_shadow_samples);
}
}

void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) {

ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum");

if (directional_shadow_quality != p_quality) {
directional_shadow_quality = p_quality;

switch (directional_shadow_quality) {
case RS::SHADOW_QUALITY_HARD: {
directional_penumbra_shadow_samples = 4;
directional_soft_shadow_samples = 1;
directional_shadow_quality_radius = 1.0;
} break;
case RS::SHADOW_QUALITY_SOFT_LOW: {
directional_penumbra_shadow_samples = 8;
directional_soft_shadow_samples = 4;
directional_shadow_quality_radius = 2.0;
} break;
case RS::SHADOW_QUALITY_SOFT_MEDIUM: {
directional_penumbra_shadow_samples = 12;
directional_soft_shadow_samples = 8;
directional_shadow_quality_radius = 2.0;
} break;
case RS::SHADOW_QUALITY_SOFT_HIGH: {
directional_penumbra_shadow_samples = 24;
directional_soft_shadow_samples = 16;
directional_shadow_quality_radius = 3.0;
} break;
case RS::SHADOW_QUALITY_SOFT_ULTRA: {
directional_penumbra_shadow_samples = 32;
directional_soft_shadow_samples = 32;
directional_shadow_quality_radius = 4.0;
} break;
case RS::SHADOW_QUALITY_MAX:
break;
}
get_vogel_disk(directional_penumbra_shadow_kernel, directional_penumbra_shadow_samples);
get_vogel_disk(directional_soft_shadow_kernel, directional_soft_shadow_samples);
}
}

int RasterizerSceneRD::get_roughness_layers() const {
Expand Down Expand Up @@ -4150,7 +4240,12 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));
sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale");
sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale");
shadow_filter = RS::ShadowFilter(int(GLOBAL_GET("rendering/quality/shadows/filter_mode")));
directional_penumbra_shadow_kernel = memnew_arr(float, 128);
directional_soft_shadow_kernel = memnew_arr(float, 128);
penumbra_shadow_kernel = memnew_arr(float, 128);
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"))));
}

RasterizerSceneRD::~RasterizerSceneRD() {
Expand Down Expand Up @@ -4179,4 +4274,8 @@ RasterizerSceneRD::~RasterizerSceneRD() {
memdelete_arr(sky_scene_state.last_frame_directional_lights);
storage->free(sky_shader.default_shader);
storage->free(sky_shader.default_material);
memdelete_arr(directional_penumbra_shadow_kernel);
memdelete_arr(directional_soft_shadow_kernel);
memdelete_arr(penumbra_shadow_kernel);
memdelete_arr(soft_shadow_kernel);
}
Loading

0 comments on commit 06748a2

Please sign in to comment.