Re-implement subsurface scattering.

The size settings are more "just works", with default scale and depth scale
values that don't need much tweaking.

Additionally, a "skin" mode was added so skin looks better.
EDIT: Cleaned up SSR filter shader a bit.
This commit is contained in:
Juan Linietsky 2020-04-03 23:42:26 -03:00
parent aeb95ef006
commit c54f80d35c
18 changed files with 399 additions and 17 deletions

View File

@ -369,6 +369,11 @@ void EditorNode::_notification(int p_what) {
RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic); RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));
RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality); RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality);
RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));
RS::get_singleton()->sub_surface_scattering_set_quality(sss_quality);
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);
} }
ResourceImporterTexture::get_singleton()->update_imports(); ResourceImporterTexture::get_singleton()->update_imports();

View File

@ -444,6 +444,9 @@ void BaseMaterial3D::_update_shader() {
case DEPTH_DRAW_DISABLED: code += ",depth_draw_never"; break; case DEPTH_DRAW_DISABLED: code += ",depth_draw_never"; break;
} }
if (features[FEATURE_SUBSURACE_SCATTERING] && flags[FLAG_SUBSURFACE_MODE_SKIN]) {
code += ",sss_mode_skin";
}
if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) { if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) {
code += ",depth_prepass_alpha"; code += ",depth_prepass_alpha";
} }
@ -2284,6 +2287,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Subsurf Scatter", "subsurf_scatter_"); ADD_GROUP("Subsurf Scatter", "subsurf_scatter_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_enabled"), "set_feature", "get_feature", FEATURE_SUBSURACE_SCATTERING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_enabled"), "set_feature", "get_feature", FEATURE_SUBSURACE_SCATTERING);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_subsurface_scattering_strength", "get_subsurface_scattering_strength"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_subsurface_scattering_strength", "get_subsurface_scattering_strength");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_skin_mode"), "set_flag", "get_flag", FLAG_SUBSURFACE_MODE_SKIN);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "subsurf_scatter_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_SUBSURFACE_SCATTERING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "subsurf_scatter_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_SUBSURFACE_SCATTERING);
ADD_GROUP("Transmission", "transmission_"); ADD_GROUP("Transmission", "transmission_");
@ -2436,6 +2440,7 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_USE_SHADOW_TO_OPACITY); BIND_ENUM_CONSTANT(FLAG_USE_SHADOW_TO_OPACITY);
BIND_ENUM_CONSTANT(FLAG_USE_TEXTURE_REPEAT); BIND_ENUM_CONSTANT(FLAG_USE_TEXTURE_REPEAT);
BIND_ENUM_CONSTANT(FLAG_INVERT_HEIGHTMAP); BIND_ENUM_CONSTANT(FLAG_INVERT_HEIGHTMAP);
BIND_ENUM_CONSTANT(FLAG_SUBSURFACE_MODE_SKIN);
BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);

View File

@ -218,6 +218,7 @@ public:
FLAG_USE_SHADOW_TO_OPACITY, FLAG_USE_SHADOW_TO_OPACITY,
FLAG_USE_TEXTURE_REPEAT, FLAG_USE_TEXTURE_REPEAT,
FLAG_INVERT_HEIGHTMAP, FLAG_INVERT_HEIGHTMAP,
FLAG_SUBSURFACE_MODE_SKIN,
FLAG_MAX FLAG_MAX
}; };

View File

@ -266,6 +266,9 @@ public:
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0; virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0;
virtual bool screen_space_roughness_limiter_is_active() const = 0; virtual bool screen_space_roughness_limiter_is_active() const = 0;
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0;
virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0;
virtual bool free(RID p_rid) = 0; virtual bool free(RID p_rid) = 0;
virtual void update() = 0; virtual void update() = 0;

View File

@ -461,6 +461,53 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal, R
RD::get_singleton()->compute_list_end(); RD::get_singleton()->compute_list_end();
} }
void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) {
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
int32_t x_groups = (p_screen_size.width - 1) / 8 + 1;
int32_t y_groups = (p_screen_size.height - 1) / 8 + 1;
Plane p = p_camera.xform4(Plane(1, 0, -1, 1));
p.normal /= p.d;
float unit_size = p.normal.x;
{ //scale color and depth to half
sss.push_constant.camera_z_far = p_camera.get_z_far();
sss.push_constant.camera_z_near = p_camera.get_z_near();
sss.push_constant.orthogonal = p_camera.is_orthogonal();
sss.push_constant.unit_size = unit_size;
sss.push_constant.screen_size[0] = p_screen_size.x;
sss.push_constant.screen_size[1] = p_screen_size.y;
sss.push_constant.vertical = false;
sss.push_constant.scale = p_scale;
sss.push_constant.depth_scale = p_depth_scale;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse2), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse2), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2);
sss.push_constant.vertical = true;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
RD::get_singleton()->compute_list_end();
}
}
void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) { void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) {
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>());
@ -1063,8 +1110,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_
RasterizerEffectsRD::RasterizerEffectsRD() { RasterizerEffectsRD::RasterizerEffectsRD() {
{ { // Initialize blur
// Initialize blur
Vector<String> blur_modes; Vector<String> blur_modes;
blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n");
blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n");
@ -1356,6 +1402,21 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0)); ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0));
} }
{
Vector<String> sss_modes;
sss_modes.push_back("\n#define USE_11_SAMPLES\n");
sss_modes.push_back("\n#define USE_17_SAMPLES\n");
sss_modes.push_back("\n#define USE_25_SAMPLES\n");
sss.shader.initialize(sss_modes);
sss.shader_version = sss.shader.version_create();
for (int i = 0; i < sss_modes.size(); i++) {
sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
}
}
RD::SamplerState sampler; RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
@ -1412,4 +1473,8 @@ RasterizerEffectsRD::~RasterizerEffectsRD() {
roughness_limiter.shader.version_free(roughness_limiter.shader_version); roughness_limiter.shader.version_free(roughness_limiter.shader_version);
cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version); cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version);
filter.shader.version_free(filter.shader_version); filter.shader.version_free(filter.shader_version);
ssr.shader.version_free(ssr.shader_version);
ssr_scale.shader.version_free(ssr_scale.shader_version);
ssr_filter.shader.version_free(ssr_filter.shader_version);
sss.shader.version_free(sss.shader_version);
} }

View File

@ -48,6 +48,7 @@
#include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/tonemap.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/tonemap.glsl.gen.h"
#include "servers/rendering_server.h" #include "servers/rendering_server.h"
@ -480,6 +481,29 @@ class RasterizerEffectsRD {
RID pipeline; RID pipeline;
} ssr_scale; } ssr_scale;
struct SubSurfaceScatteringPushConstant {
int32_t screen_size[2];
float camera_z_far;
float camera_z_near;
uint32_t vertical;
uint32_t orthogonal;
float unit_size;
float scale;
float depth_scale;
uint32_t pad[3];
};
struct SubSurfaceScattering {
SubSurfaceScatteringPushConstant push_constant;
SubsurfaceScatteringShaderRD shader;
RID shader_version;
RID pipelines[3]; //3 quality levels
} sss;
RID default_sampler; RID default_sampler;
RID default_mipmap_sampler; RID default_mipmap_sampler;
RID index_buffer; RID index_buffer;
@ -571,6 +595,7 @@ public:
void screen_space_reflection(RID p_diffuse, RID p_normal, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_roughness, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera); void screen_space_reflection(RID p_diffuse, RID p_normal, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_roughness, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
RasterizerEffectsRD(); RasterizerEffectsRD();
~RasterizerEffectsRD(); ~RasterizerEffectsRD();

View File

@ -1795,6 +1795,14 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
render_list.clear(); render_list.clear();
_fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr); _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
if (using_sss) {
using_separate_specular = true;
render_buffer->ensure_specular();
using_separate_specular = true;
opaque_specular_framebuffer = render_buffer->color_specular_fb;
}
RID radiance_uniform_set; RID radiance_uniform_set;
bool draw_sky = false; bool draw_sky = false;
@ -1894,8 +1902,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
RENDER_TIMESTAMP("Render Opaque Pass"); RENDER_TIMESTAMP("Render Opaque Pass");
bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !scene_state.used_sss; bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr; bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
{ {
@ -1904,10 +1912,15 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
//regular forward for now //regular forward for now
Vector<Color> c; Vector<Color> c;
c.push_back(clear_color.to_linear());
if (using_separate_specular) { if (using_separate_specular) {
Color cc = clear_color.to_linear();
cc.a = 0; //subsurf scatter must be 0
c.push_back(cc);
c.push_back(Color(0, 0, 0, 0)); c.push_back(Color(0, 0, 0, 0));
} else {
c.push_back(clear_color.to_linear());
} }
RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (using_ssao ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (using_ssao ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set);
@ -1950,10 +1963,9 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
if (using_separate_specular) { if (using_separate_specular) {
if (scene_state.used_sss) { if (using_sss) {
RENDER_TIMESTAMP("Sub Surface Scattering"); RENDER_TIMESTAMP("Sub Surface Scattering");
_process_sss(p_render_buffer, p_cam_projection);
//_process_sss()
} }
if (using_ssr) { if (using_ssr) {
@ -2620,6 +2632,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx");
if (!force_blinn) { if (!force_blinn) {

View File

@ -3203,6 +3203,26 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) {
} }
} }
void RasterizerSceneRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
bool can_use_effects = rb->width >= 8 && rb->height >= 8;
if (!can_use_effects) {
//just copy
return;
}
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
_render_buffers_uniform_set_changed(p_render_buffers);
}
storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality);
}
void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_roughness_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) { void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_roughness_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
@ -3547,6 +3567,19 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren
_render_buffers_uniform_set_changed(p_render_buffers); _render_buffers_uniform_set_changed(p_render_buffers);
} }
void RasterizerSceneRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
sss_quality = p_quality;
}
RS::SubSurfaceScatteringQuality RasterizerSceneRD::sub_surface_scattering_get_quality() const {
return sss_quality;
}
void RasterizerSceneRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) {
sss_scale = p_scale;
sss_depth_scale = p_depth_scale;
}
int RasterizerSceneRD::get_roughness_layers() const { int RasterizerSceneRD::get_roughness_layers() const {
return roughness_layers; return roughness_layers;
} }
@ -4101,6 +4134,9 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve"); screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve");
glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));
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");
} }
RasterizerSceneRD::~RasterizerSceneRD() { RasterizerSceneRD::~RasterizerSceneRD() {

View File

@ -93,6 +93,7 @@ protected:
void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection); void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection);
void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_roughness_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive); void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_roughness_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);
void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera);
void _setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size); void _setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size);
void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
@ -698,6 +699,9 @@ private:
RS::DOFBlurQuality dof_blur_quality = RS::DOF_BLUR_QUALITY_MEDIUM; RS::DOFBlurQuality dof_blur_quality = RS::DOF_BLUR_QUALITY_MEDIUM;
RS::DOFBokehShape dof_blur_bokeh_shape = RS::DOF_BOKEH_HEXAGON; RS::DOFBokehShape dof_blur_bokeh_shape = RS::DOF_BOKEH_HEXAGON;
bool dof_blur_use_jitter = false; bool dof_blur_use_jitter = false;
RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
float sss_scale = 0.05;
float sss_depth_scale = 0.01;
mutable RID_Owner<CameraEffects> camera_effects_owner; mutable RID_Owner<CameraEffects> camera_effects_owner;
@ -1110,6 +1114,10 @@ public:
virtual bool screen_space_roughness_limiter_is_active() const; virtual bool screen_space_roughness_limiter_is_active() const;
virtual float screen_space_roughness_limiter_get_curve() const; virtual float screen_space_roughness_limiter_get_curve() const;
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality);
RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const;
virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale);
int get_roughness_layers() const; int get_roughness_layers() const;
bool is_using_radiance_cubemap_array() const; bool is_using_radiance_cubemap_array() const;

View File

@ -25,4 +25,5 @@ if "RD_GLSL" in env["BUILDERS"]:
env.RD_GLSL("screen_space_reflection.glsl") env.RD_GLSL("screen_space_reflection.glsl")
env.RD_GLSL("screen_space_reflection_filter.glsl") env.RD_GLSL("screen_space_reflection_filter.glsl")
env.RD_GLSL("screen_space_reflection_scale.glsl") env.RD_GLSL("screen_space_reflection_scale.glsl")
env.RD_GLSL("subsurface_scattering.glsl")
env.RD_GLSL("specular_merge.glsl") env.RD_GLSL("specular_merge.glsl")

View File

@ -1697,6 +1697,9 @@ FRAGMENT_SHADER_CODE
#else #else
#ifdef SSS_MODE_SKIN
sss_strength = -sss_strength;
#endif
diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength);
specular_buffer = vec4(specular_light, metallic); specular_buffer = vec4(specular_light, metallic);

View File

@ -69,8 +69,6 @@ float gauss_weight(float p_val) {
return mix(gauss_table[idx], gauss_table[idx + 1], c); return mix(gauss_table[idx], gauss_table[idx + 1], c);
} }
#define GAUSS_WEIGHT(m_val) gauss_table[clamp(int(m_val * float(GAUSS_TABLE_SIZE - 1)), 0, GAUSS_TABLE_SIZE - 1)]
#define M_PI 3.14159265359 #define M_PI 3.14159265359
vec3 reconstructCSPosition(vec2 S, float z) { vec3 reconstructCSPosition(vec2 S, float z) {
@ -105,17 +103,14 @@ void do_filter(inout vec4 accum, inout float accum_radius, inout float divisor,
break; break;
} }
float contrib = 0.0;
if (d < radius) { if (d < radius) {
contrib += gauss_weight(d / radius);
}
if (contrib > 0.0) { float w = gauss_weight(d / radius);
accum += imageLoad(source_ssr, tc) * contrib; accum += imageLoad(source_ssr, tc) * w;
#ifndef VERTICAL_PASS #ifndef VERTICAL_PASS
accum_radius += r * contrib; accum_radius += r * w;
#endif #endif
divisor += contrib; divisor += w;
} }
} }
} }

View File

@ -0,0 +1,198 @@
/* clang-format off */
[compute]
#version 450
VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
/* clang-format on */
#ifdef USE_25_SAMPLES
const int kernel_size = 13;
const vec2 kernel[kernel_size] = vec2[](
vec2(0.530605, 0.0),
vec2(0.0211412, 0.0208333),
vec2(0.0402784, 0.0833333),
vec2(0.0493588, 0.1875),
vec2(0.0410172, 0.333333),
vec2(0.0263642, 0.520833),
vec2(0.017924, 0.75),
vec2(0.0128496, 1.02083),
vec2(0.0094389, 1.33333),
vec2(0.00700976, 1.6875),
vec2(0.00500364, 2.08333),
vec2(0.00333804, 2.52083),
vec2(0.000973794, 3.0));
const vec4 skin_kernel[kernel_size] = vec4[](
vec4(0.530605, 0.613514, 0.739601, 0),
vec4(0.0211412, 0.0459286, 0.0378196, 0.0208333),
vec4(0.0402784, 0.0657244, 0.04631, 0.0833333),
vec4(0.0493588, 0.0367726, 0.0219485, 0.1875),
vec4(0.0410172, 0.0199899, 0.0118481, 0.333333),
vec4(0.0263642, 0.0119715, 0.00684598, 0.520833),
vec4(0.017924, 0.00711691, 0.00347194, 0.75),
vec4(0.0128496, 0.00356329, 0.00132016, 1.02083),
vec4(0.0094389, 0.00139119, 0.000416598, 1.33333),
vec4(0.00700976, 0.00049366, 0.000151938, 1.6875),
vec4(0.00500364, 0.00020094, 5.28848e-005, 2.08333),
vec4(0.00333804, 7.85443e-005, 1.2945e-005, 2.52083),
vec4(0.000973794, 1.11862e-005, 9.43437e-007, 3));
#endif //USE_25_SAMPLES
#ifdef USE_17_SAMPLES
const int kernel_size = 9;
const vec2 kernel[kernel_size] = vec2[](
vec2(0.536343, 0.0),
vec2(0.0324462, 0.03125),
vec2(0.0582416, 0.125),
vec2(0.0571056, 0.28125),
vec2(0.0347317, 0.5),
vec2(0.0216301, 0.78125),
vec2(0.0144609, 1.125),
vec2(0.0100386, 1.53125),
vec2(0.00317394, 2.0));
const vec4 skin_kernel[kernel_size] = vec4[](
vec4(0.536343, 0.624624, 0.748867, 0),
vec4(0.0324462, 0.0656718, 0.0532821, 0.03125),
vec4(0.0582416, 0.0659959, 0.0411329, 0.125),
vec4(0.0571056, 0.0287432, 0.0172844, 0.28125),
vec4(0.0347317, 0.0151085, 0.00871983, 0.5),
vec4(0.0216301, 0.00794618, 0.00376991, 0.78125),
vec4(0.0144609, 0.00317269, 0.00106399, 1.125),
vec4(0.0100386, 0.000914679, 0.000275702, 1.53125),
vec4(0.00317394, 0.000134823, 3.77269e-005, 2));
#endif //USE_17_SAMPLES
#ifdef USE_11_SAMPLES
const int kernel_size = 6;
const vec2 kernel[kernel_size] = vec2[](
vec2(0.560479, 0.0),
vec2(0.0771802, 0.08),
vec2(0.0821904, 0.32),
vec2(0.03639, 0.72),
vec2(0.0192831, 1.28),
vec2(0.00471691, 2.0));
const vec4 skin_kernel[kernel_size] = vec4[](
vec4(0.560479, 0.669086, 0.784728, 0),
vec4(0.0771802, 0.113491, 0.0793803, 0.08),
vec4(0.0821904, 0.0358608, 0.0209261, 0.32),
vec4(0.03639, 0.0130999, 0.00643685, 0.72),
vec4(0.0192831, 0.00282018, 0.00084214, 1.28),
vec4(0.00471691, 0.000184771, 5.07565e-005, 2));
#endif //USE_11_SAMPLES
layout(push_constant, binding = 1, std430) uniform Params {
ivec2 screen_size;
float camera_z_far;
float camera_z_near;
bool vertical;
bool orthogonal;
float unit_size;
float scale;
float depth_scale;
uint pad[3];
}
params;
layout(set = 0, binding = 0) uniform sampler2D source_image;
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D dest_image;
layout(set = 2, binding = 0) uniform sampler2D source_depth;
void do_filter(inout vec3 color_accum, inout vec3 divisor, vec2 uv, vec2 step, bool p_skin) {
// Accumulate the other samples:
for (int i = 1; i < kernel_size; i++) {
// Fetch color and depth for current sample:
vec2 offset = uv + kernel[i].y * step;
vec4 color = texture(source_image, offset);
if (abs(color.a) < 0.001) {
break; //mix no more
}
vec3 w;
if (p_skin) {
//skin
w = skin_kernel[i].rgb;
} else {
w = vec3(kernel[i].x);
}
color_accum += color.rgb * w;
divisor += w;
}
}
void main() {
// Pixel being shaded
ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing
return;
}
vec2 uv = (vec2(ssC) + 0.5) / vec2(params.screen_size);
// Fetch color of current pixel:
vec4 base_color = texture(source_image, uv);
float strength = abs(base_color.a);
if (strength > 0.0) {
vec2 dir = params.vertical ? vec2(0.0, 1.0) : vec2(1.0, 0.0);
// Fetch linear depth of current pixel:
float depth = texture(source_depth, uv).r * 2.0 - 1.0;
float depth_scale;
if (params.orthogonal) {
depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
depth_scale = params.unit_size; //remember depth is negative by default in OpenGL
} else {
depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
depth_scale = params.unit_size / depth; //remember depth is negative by default in OpenGL
}
float scale = mix(params.scale, depth_scale, params.depth_scale);
// Calculate the final step to fetch the surrounding pixels:
vec2 step = scale * dir;
step *= strength;
step /= 3.0;
// Accumulate the center sample:
vec3 divisor;
bool skin = bool(base_color.a < 0.0);
if (skin) {
//skin
divisor = skin_kernel[0].rgb;
} else {
divisor = vec3(kernel[0].x);
}
vec3 color = base_color.rgb * divisor;
do_filter(color, divisor, uv, step, skin);
do_filter(color, divisor, uv, -step, skin);
base_color.rgb = color / divisor;
}
imageStore(dest_image, ssC, base_color);
}

View File

@ -541,6 +541,8 @@ public:
BIND5(environment_set_fog_height, RID, bool, float, float, float) BIND5(environment_set_fog_height, RID, bool, float, float, float)
BIND2(screen_space_roughness_limiter_set_active, bool, float) BIND2(screen_space_roughness_limiter_set_active, bool, float)
BIND1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality)
BIND2(sub_surface_scattering_set_scale, float, float)
/* CAMERA EFFECTS */ /* CAMERA EFFECTS */

View File

@ -456,6 +456,8 @@ public:
FUNC5(environment_set_fog_height, RID, bool, float, float, float) FUNC5(environment_set_fog_height, RID, bool, float, float, float)
FUNC2(screen_space_roughness_limiter_set_active, bool, float) FUNC2(screen_space_roughness_limiter_set_active, bool, float)
FUNC1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality)
FUNC2(sub_surface_scattering_set_scale, float, float)
FUNCRID(camera_effects) FUNCRID(camera_effects)

View File

@ -168,6 +168,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_test_disabled"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_test_disabled");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("sss_mode_skin");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_back"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_back");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_front"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_front");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_disabled"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_disabled");

View File

@ -2362,6 +2362,13 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/quality/screen_space_reflection/roughness_quality", 1); GLOBAL_DEF("rendering/quality/screen_space_reflection/roughness_quality", 1);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/quality/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low, Medium, High (Slowest)")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/quality/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low, Medium, High (Slowest)"));
GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_quality", 1);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_quality", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/subsurface_scattering_quality", PROPERTY_HINT_ENUM, "Disabled, Low (Fastest),Medium, High (Slowest)"));
GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_scale", 0.05);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"));
GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", 0.01);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"));
} }
RenderingServer::~RenderingServer() { RenderingServer::~RenderingServer() {

View File

@ -782,6 +782,16 @@ public:
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0; virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0;
enum SubSurfaceScatteringQuality {
SUB_SURFACE_SCATTERING_QUALITY_DISABLED,
SUB_SURFACE_SCATTERING_QUALITY_LOW,
SUB_SURFACE_SCATTERING_QUALITY_MEDIUM,
SUB_SURFACE_SCATTERING_QUALITY_HIGH,
};
virtual void sub_surface_scattering_set_quality(SubSurfaceScatteringQuality p_quality) = 0;
virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0;
/* CAMERA EFFECTS */ /* CAMERA EFFECTS */
virtual RID camera_effects_create() = 0; virtual RID camera_effects_create() = 0;