diff options
Diffstat (limited to 'servers/rendering')
25 files changed, 1689 insertions, 318 deletions
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h index 6676b00723..cf0afe6097 100644 --- a/servers/rendering/rasterizer.h +++ b/servers/rendering/rasterizer.h @@ -106,6 +106,8 @@ public: 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; + struct InstanceBase; struct InstanceDependency { @@ -229,7 +231,7 @@ public: virtual RID light_instance_create(RID p_light) = 0; virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0) = 0; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; virtual void light_instance_mark_visible(RID p_light_instance) = 0; virtual bool light_instances_can_render_shadow_cube() const { return true; @@ -266,6 +268,9 @@ public: 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 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 void update() = 0; diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.h b/servers/rendering/rasterizer_rd/light_cluster_builder.h index 3411ed07a0..50a68e03cb 100644 --- a/servers/rendering/rasterizer_rd/light_cluster_builder.h +++ b/servers/rendering/rasterizer_rd/light_cluster_builder.h @@ -170,17 +170,15 @@ public: _add_item(aabb, ITEM_TYPE_OMNI_LIGHT, light_count); } break; case LIGHT_TYPE_SPOT: { - Vector3 v(0, 0, -1); - v.rotated(Vector3(0, 1, 0), Math::deg2rad(ld.spot_aperture)); //rotate in x-z - v.normalize(); - v *= ld.radius; - v.y = v.x; + + float r = ld.radius; + real_t len = Math::tan(Math::deg2rad(ld.spot_aperture)) * r; aabb.position = xform.origin; - aabb.expand_to(xform.xform(v)); - aabb.expand_to(xform.xform(Vector3(-v.x, v.y, v.z))); - aabb.expand_to(xform.xform(Vector3(-v.x, -v.y, v.z))); - aabb.expand_to(xform.xform(Vector3(v.x, -v.y, v.z))); + aabb.expand_to(xform.xform(Vector3(len, len, -r))); + aabb.expand_to(xform.xform(Vector3(-len, len, -r))); + aabb.expand_to(xform.xform(Vector3(-len, -len, -r))); + aabb.expand_to(xform.xform(Vector3(len, -len, -r))); _add_item(aabb, ITEM_TYPE_SPOT_LIGHT, light_count); } break; } diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index 3b22cb4d9d..79b1686232 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -204,6 +204,25 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1 return uniform_set; } +void RasterizerEffectsRD::copy_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { + + zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + if (p_flip_y) { + blur.push_constant.flags |= BLUR_FLAG_FLIP_Y; + } + + blur.push_constant.camera_z_near = p_z_near; + blur.push_constant.camera_z_far = p_z_far; + + 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>(), 1.0, 0, p_rect); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_LINEARIZE_DEPTH].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y, bool p_force_luminance) { zeromem(&blur.push_constant, sizeof(BlurPushConstant)); @@ -461,6 +480,53 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal, R 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) { 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 +1129,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_ RasterizerEffectsRD::RasterizerEffectsRD() { - { - // Initialize blur + { // Initialize blur Vector<String> blur_modes; blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); @@ -1081,6 +1146,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() { blur_modes.push_back("\n#define MODE_SSAO_MERGE\n"); blur_modes.push_back("\n#define MODE_SIMPLE_COPY\n"); blur_modes.push_back("\n#define MODE_MIPMAP\n"); + blur_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n"); blur.shader.initialize(blur_modes); zeromem(&blur.push_constant, sizeof(BlurPushConstant)); @@ -1356,6 +1422,21 @@ RasterizerEffectsRD::RasterizerEffectsRD() { 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; sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; @@ -1400,16 +1481,22 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { RD::get_singleton()->free(default_mipmap_sampler); RD::get_singleton()->free(index_buffer); //array gets freed as dependency RD::get_singleton()->free(filter.coefficient_buffer); + blur.shader.version_free(blur.shader_version); - roughness.shader.version_free(roughness.shader_version); - tonemap.shader.version_free(tonemap.shader_version); - luminance_reduce.shader.version_free(luminance_reduce.shader_version); - copy.shader.version_free(copy.shader_version); bokeh.shader.version_free(bokeh.shader_version); - ssao.minify_shader.version_free(ssao.minify_shader_version); - ssao.gather_shader.version_free(ssao.gather_shader_version); - ssao.blur_shader.version_free(ssao.blur_shader_version); - roughness_limiter.shader.version_free(roughness_limiter.shader_version); + copy.shader.version_free(copy.shader_version); cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version); filter.shader.version_free(filter.shader_version); + luminance_reduce.shader.version_free(luminance_reduce.shader_version); + roughness.shader.version_free(roughness.shader_version); + roughness_limiter.shader.version_free(roughness_limiter.shader_version); + specular_merge.shader.version_free(specular_merge.shader_version); + ssao.blur_shader.version_free(ssao.blur_shader_version); + ssao.gather_shader.version_free(ssao.gather_shader_version); + ssao.minify_shader.version_free(ssao.minify_shader_version); + ssr.shader.version_free(ssr.shader_version); + ssr_filter.shader.version_free(ssr_filter.shader_version); + ssr_scale.shader.version_free(ssr_scale.shader_version); + sss.shader.version_free(sss.shader_version); + tonemap.shader.version_free(tonemap.shader_version); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h index 32eb8c8cda..c0c62eb0be 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -48,6 +48,7 @@ #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_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_server.h" @@ -70,6 +71,7 @@ class RasterizerEffectsRD { BLUR_MODE_SSAO_MERGE, BLUR_MODE_SIMPLY_COPY, BLUR_MODE_MIPMAP, + BLUR_MODE_LINEARIZE_DEPTH, BLUR_MODE_MAX, }; @@ -480,6 +482,29 @@ class RasterizerEffectsRD { RID pipeline; } 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_mipmap_sampler; RID index_buffer; @@ -516,6 +541,7 @@ public: void region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region); void copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y = false, bool p_force_luminance = false); + void copy_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y, float p_z_near, float p_z_far); void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region); void gaussian_glow(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); @@ -571,6 +597,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 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(); diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index 6094fbb36f..ec05c9e964 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -109,6 +109,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { unshaded = false; uses_vertex = false; uses_sss = false; + uses_transmittance = false; uses_screen_texture = false; uses_depth_texture = false; uses_normal_texture = false; @@ -142,6 +143,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; + actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; @@ -944,7 +946,7 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l } } -void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers) { +void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows) { //CameraMatrix projection = p_cam_projection; //projection.flip_y(); // Vulkan and modern APIs use Y-Down @@ -960,6 +962,10 @@ 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; scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x; scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y; @@ -1479,11 +1485,49 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.specular = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR); light_data.mask = storage->light_get_cull_mask(base); + float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + + light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset + Color shadow_col = storage->light_get_shadow_color(base).to_linear(); - light_data.shadow_color[0] = shadow_col.r; - light_data.shadow_color[1] = shadow_col.g; - light_data.shadow_color[2] = shadow_col.b; + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) { + light_data.shadow_color1[0] = 1.0; + light_data.shadow_color1[1] = 0.0; + light_data.shadow_color1[2] = 0.0; + light_data.shadow_color1[3] = 1.0; + light_data.shadow_color2[0] = 0.0; + light_data.shadow_color2[1] = 1.0; + light_data.shadow_color2[2] = 0.0; + light_data.shadow_color2[3] = 1.0; + light_data.shadow_color3[0] = 0.0; + light_data.shadow_color3[1] = 0.0; + light_data.shadow_color3[2] = 1.0; + light_data.shadow_color3[3] = 1.0; + light_data.shadow_color4[0] = 1.0; + light_data.shadow_color4[1] = 1.0; + light_data.shadow_color4[2] = 0.0; + light_data.shadow_color4[3] = 1.0; + + } else { + + light_data.shadow_color1[0] = shadow_col.r; + light_data.shadow_color1[1] = shadow_col.g; + light_data.shadow_color1[2] = shadow_col.b; + light_data.shadow_color1[3] = 1.0; + light_data.shadow_color2[0] = shadow_col.r; + light_data.shadow_color2[1] = shadow_col.g; + light_data.shadow_color2[2] = shadow_col.b; + light_data.shadow_color2[3] = 1.0; + light_data.shadow_color3[0] = shadow_col.r; + light_data.shadow_color3[1] = shadow_col.g; + light_data.shadow_color3[2] = shadow_col.b; + light_data.shadow_color3[3] = 1.0; + light_data.shadow_color4[0] = shadow_col.r; + light_data.shadow_color4[1] = shadow_col.g; + light_data.shadow_color4[2] = shadow_col.b; + light_data.shadow_color4[3] = 1.0; + } light_data.shadow_enabled = p_using_shadows && storage->light_has_shadow(base); @@ -1507,12 +1551,49 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig CameraMatrix shadow_mtx = rectm * bias * matrix * modelview; light_data.shadow_split_offsets[j] = split; + float bias_scale = light_instance_get_shadow_bias_scale(li, j); + 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_range_begin[j] = light_instance_get_shadow_range_begin(li, j); store_camera(shadow_mtx, light_data.shadow_matrices[j]); + + Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j); + uv_scale *= atlas_rect.size; //adapt to atlas size + switch (j) { + case 0: { + light_data.uv_scale1[0] = uv_scale.x; + light_data.uv_scale1[1] = uv_scale.y; + } break; + case 1: { + light_data.uv_scale2[0] = uv_scale.x; + light_data.uv_scale2[1] = uv_scale.y; + } break; + case 2: { + light_data.uv_scale3[0] = uv_scale.x; + light_data.uv_scale3[1] = uv_scale.y; + } break; + case 3: { + light_data.uv_scale4[0] = uv_scale.x; + light_data.uv_scale4[1] = uv_scale.y; + } break; + } } 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]; + + 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. + // technically this will keep expanding until reaching the sun, but all we care + // is expand until we reach the radius of the near plane (there can't be more occluders than that) + light_data.softshadow_angle = Math::tan(Math::deg2rad(softshadow_angle)); + } else { + light_data.softshadow_angle = 0; + } } // Copy to SkyDirectionalLightData @@ -1575,20 +1656,16 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.direction[1] = direction.y; light_data.direction[2] = direction.z; + float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + + light_data.size = size; + light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION)); float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE); light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle))); light_data.mask = storage->light_get_cull_mask(base); - Color shadow_color = storage->light_get_shadow_color(base); - - bool has_shadow = p_using_shadows && storage->light_has_shadow(base); - light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255); - light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255); - light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255); - light_data.shadow_color_enabled[3] = has_shadow ? 255 : 0; - light_data.atlas_rect[0] = 0; light_data.atlas_rect[1] = 0; light_data.atlas_rect[2] = 0; @@ -1597,20 +1674,55 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) { // fill in the shadow information + Color shadow_color = storage->light_get_shadow_color(base); + + light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255); + light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255); + light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255); + light_data.shadow_color_enabled[3] = 255; + + if (type == RS::LIGHT_SPOT) { + light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0); + float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0; + shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas); + + light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size; + + } else { //omni + light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0; + float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas); + light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space + } + + light_data.transmittance_bias = storage->light_get_transmittance_bias(base); + Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas); - if (type == RS::LIGHT_OMNI) { + light_data.atlas_rect[0] = rect.position.x; + light_data.atlas_rect[1] = rect.position.y; + light_data.atlas_rect[2] = rect.size.width; + light_data.atlas_rect[3] = rect.size.height; - light_data.atlas_rect[0] = rect.position.x; - light_data.atlas_rect[1] = rect.position.y; - light_data.atlas_rect[2] = rect.size.width; - light_data.atlas_rect[3] = rect.size.height * 0.5; + if (type == RS::LIGHT_OMNI) { + light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another Transform proj = (p_camera_inverse_transform * light_transform).inverse(); store_transform(proj, light_data.shadow_matrix); + + if (size > 0.0) { + + light_data.soft_shadow_size = size; + } else { + light_data.soft_shadow_size = 0.0; + } + } else if (type == RS::LIGHT_SPOT) { + //used for clamping in this light type + light_data.atlas_rect[2] += light_data.atlas_rect[0]; + light_data.atlas_rect[3] += light_data.atlas_rect[1]; + Transform modelview = (p_camera_inverse_transform * light_transform).inverse(); CameraMatrix bias; bias.set_light_bias(); @@ -1619,7 +1731,17 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview; store_camera(shadow_mtx, light_data.shadow_matrix); + + if (size > 0.0) { + CameraMatrix cm = light_instance_get_shadow_camera(li, 0); + float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle)); + 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; + } } + } else { + light_data.shadow_color_enabled[3] = 0; } light_instance_set_index(li, light_count); @@ -1698,9 +1820,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; - scene_state.ubo.shadow_z_offset = 0; - scene_state.ubo.shadow_z_slope_scale = 0; - Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); scene_state.ubo.viewport_size[0] = vp_he.x; scene_state.ubo.viewport_size[1] = vp_he.y; @@ -1795,6 +1914,14 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor render_list.clear(); _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; bool draw_sky = false; @@ -1894,8 +2021,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor RENDER_TIMESTAMP("Render Opaque Pass"); - bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !scene_state.used_sss; - bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr; + bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; + bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; { @@ -1904,10 +2031,15 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor //regular forward for now Vector<Color> c; - c.push_back(clear_color.to_linear()); 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)); + } else { + c.push_back(clear_color.to_linear()); } + 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); _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 +2082,9 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor if (using_separate_specular) { - if (scene_state.used_sss) { + if (using_sss) { RENDER_TIMESTAMP("Sub Surface Scattering"); - - //_process_sss() + _process_sss(p_render_buffer, p_cam_projection); } if (using_ssr) { @@ -2051,7 +2182,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor //disable all stuff #endif } -void RasterizerSceneHighEndRD::_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 p_use_dp_flip) { +void RasterizerSceneHighEndRD::_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 p_use_dp_flip, bool p_use_pancake) { RENDER_TIMESTAMP("Setup Rendering Shadow"); @@ -2059,11 +2190,9 @@ void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase ** render_pass++; - scene_state.ubo.shadow_z_offset = p_bias; - scene_state.ubo.shadow_z_slope_scale = p_normal_bias; scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - _setup_environment(RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_zfar); + _setup_environment(RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_zfar, false, p_use_pancake); render_list.clear(); @@ -2094,8 +2223,6 @@ void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform render_pass++; - scene_state.ubo.shadow_z_offset = 0; - scene_state.ubo.shadow_z_slope_scale = 0; scene_state.ubo.dual_paraboloid_side = 0; _setup_environment(RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); @@ -2192,7 +2319,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.light_buffer); uniforms.push_back(u); } @@ -2451,11 +2578,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag } { //lights - scene_state.max_lights = MIN(65536, uniform_max_size) / sizeof(LightData); + scene_state.max_lights = MIN(1024 * 1024, uniform_max_size) / sizeof(LightData); //1mb of lights uint32_t light_buffer_size = scene_state.max_lights * sizeof(LightData); scene_state.lights = memnew_arr(LightData, scene_state.max_lights); - scene_state.light_buffer = RD::get_singleton()->uniform_buffer_create(light_buffer_size); - defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n"; + scene_state.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n"; scene_state.max_directional_lights = 8; uint32_t directional_light_buffer_size = scene_state.max_directional_lights * sizeof(DirectionalLightData); @@ -2557,7 +2684,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["ANISOTROPY"] = "anisotropy"; actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; actions.renames["SSS_STRENGTH"] = "sss_strength"; - actions.renames["TRANSMISSION"] = "transmission"; + actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; + actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; + actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; + actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; + actions.renames["BACKLIGHT"] = "backlight"; actions.renames["AO"] = "ao"; actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; actions.renames["EMISSION"] = "emission"; @@ -2597,7 +2728,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions.usage_defines["TRANSMISSION"] = "#define LIGHT_TRANSMISSION_USED\n"; + actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; + actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; @@ -2620,6 +2752,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag 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["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); if (!force_blinn) { diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h index e79bf2b378..b4f5d25afd 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h @@ -138,6 +138,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { bool unshaded; bool uses_vertex; bool uses_sss; + bool uses_transmittance; bool uses_screen_texture; bool uses_depth_texture; bool uses_normal_texture; @@ -253,13 +254,19 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float position[3]; float inv_radius; float direction[3]; + float size; uint16_t attenuation_energy[2]; //16 bits attenuation, then energy uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm) uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float) - uint32_t mask; uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm) float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv float shadow_matrix[16]; + float shadow_bias; + float shadow_normal_bias; + float transmittance_bias; + float soft_shadow_size; + uint32_t mask; + uint32_t pad[3]; }; struct DirectionalLightData { @@ -267,15 +274,30 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float direction[3]; float energy; float color[3]; + float size; float specular; - float shadow_color[3]; uint32_t mask; + float softshadow_angle; + uint32_t pad[1]; uint32_t blend_splits; uint32_t shadow_enabled; float fade_from; float fade_to; + float shadow_bias[4]; + float shadow_normal_bias[4]; + float shadow_transmittance_bias[4]; + float shadow_transmittance_z_scale[4]; + float shadow_range_begin[4]; float shadow_split_offsets[4]; float shadow_matrices[4][16]; + float shadow_color1[4]; + float shadow_color2[4]; + float shadow_color3[4]; + float shadow_color4[4]; + float uv_scale1[2]; + float uv_scale2[2]; + float uv_scale3[2]; + float uv_scale4[2]; }; struct GIProbeData { @@ -324,12 +346,15 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float viewport_size[2]; float screen_pixel_size[2]; - float shadow_z_offset; - float shadow_z_slope_scale; - float time; float reflection_multiplier; + uint32_t pancake_shadows; + uint32_t shadow_filter_mode; + + uint32_t shadow_blocker_count; + uint32_t shadow_pad[3]; + float ambient_light_color_energy[4]; float ambient_color_sky_mix; @@ -558,7 +583,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { PASS_MODE_DEPTH_MATERIAL, }; - void _setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false); + void _setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false); 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); 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_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform); @@ -572,7 +597,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { protected: 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, 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_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_bg_color); - 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 p_use_dp_flip); + 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 p_use_dp_flip, bool p_use_pancake); virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); public: diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp index af86d145ad..a0bbf8bd43 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -2032,7 +2032,7 @@ void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const light_instance->transform = p_transform; } -void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale) { +void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); @@ -2048,6 +2048,9 @@ void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance light_instance->shadow_transform[p_pass].farplane = p_far; light_instance->shadow_transform[p_pass].split = p_split; light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; + light_instance->shadow_transform[p_pass].range_begin = p_range_begin; + light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size; + light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; } void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) { @@ -3203,6 +3206,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) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); @@ -3547,6 +3570,23 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren _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; +} + +void RasterizerSceneRD::shadow_filter_set(RS::ShadowFilter p_filter) { + shadow_filter = p_filter; +} + int RasterizerSceneRD::get_roughness_layers() const { return roughness_layers; } @@ -3592,12 +3632,15 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas bool using_dual_paraboloid = false; bool using_dual_paraboloid_flip = false; + float znear = 0; float zfar = 0; RID render_fb; RID render_texture; float bias = 0; float normal_bias = 0; + bool use_pancake = false; + bool use_linear_depth = false; bool render_cubemap = false; bool finalize_cubemap = false; @@ -3612,6 +3655,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas light_instance->last_scene_shadow_pass = scene_pass; } + use_pancake = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0; light_projection = light_instance->shadow_transform[p_pass].camera; light_transform = light_instance->shadow_transform[p_pass].transform; @@ -3650,7 +3694,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size; light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size; - float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE)); + float bias_mult = light_instance->shadow_transform[p_pass].bias_scale; zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult; normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * bias_mult; @@ -3729,26 +3773,33 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); render_fb = shadow_map->fb; render_texture = shadow_map->depth; + + znear = light_instance->shadow_transform[0].camera.get_z_near(); + use_linear_depth = true; } } if (render_cubemap) { //rendering to cubemap - _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false); + _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake); if (finalize_cubemap) { //reblit atlas_rect.size.height /= 2; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), bias, false); + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, false); atlas_rect.position.y += atlas_rect.size.height; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), bias, true); + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, true); } } else { //render shadow - _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip); + _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake); //copy to atlas - storage->get_effects()->copy_to_rect(render_texture, atlas_fb, atlas_rect, true); + if (use_linear_depth) { + storage->get_effects()->copy_to_rect_and_linearize(render_texture, atlas_fb, atlas_rect, true, znear, zfar); + } else { + storage->get_effects()->copy_to_rect(render_texture, atlas_fb, atlas_rect, true); + } //does not work from depth to color //RD::get_singleton()->texture_copy(render_texture, atlas_texture, Vector3(0, 0, 0), Vector3(atlas_rect.position.x, atlas_rect.position.y, 0), Vector3(atlas_rect.size.x, atlas_rect.size.y, 1), 0, 0, 0, 0, true); @@ -4101,6 +4152,10 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { 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; 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"); + shadow_filter = RS::ShadowFilter(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); } RasterizerSceneRD::~RasterizerSceneRD() { diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h index 11a8555d22..3478c05fb1 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h @@ -79,7 +79,7 @@ protected: virtual RenderBufferData *_create_render_buffer_data() = 0; 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, 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_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) = 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; virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); @@ -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_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 _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); @@ -526,6 +527,8 @@ private: bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); + RS::ShadowFilter shadow_filter = RS::SHADOW_FILTER_NONE; + /* DIRECTIONAL SHADOW */ struct DirectionalShadow { @@ -569,7 +572,10 @@ private: float farplane; float split; float bias_scale; + float shadow_texel_size; + float range_begin; Rect2 atlas_rect; + Vector2 uv_scale; }; RS::LightType light_type = RS::LIGHT_DIRECTIONAL; @@ -698,6 +704,9 @@ private: RS::DOFBlurQuality dof_blur_quality = RS::DOF_BLUR_QUALITY_MEDIUM; RS::DOFBokehShape dof_blur_bokeh_shape = RS::DOF_BOKEH_HEXAGON; 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; @@ -876,7 +885,7 @@ public: RID light_instance_create(RID p_light); void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); - void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0); + void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()); void light_instance_mark_visible(RID p_light_instance); _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { @@ -922,11 +931,55 @@ public: return li->shadow_transform[p_index].camera; } - _FORCE_INLINE_ Transform light_instance_get_shadow_transform(RID p_light_instance, int p_index) { + _FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) { + +#ifdef DEBUG_ENABLED + LightInstance *li = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0); +#endif + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ERR_FAIL_COND_V(!shadow_atlas, 0); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0); +#endif + uint32_t key = shadow_atlas->shadow_owners[p_light_instance]; + + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + + uint32_t quadrant_size = shadow_atlas->size >> 1; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + + return float(1.0) / shadow_size; + } + + _FORCE_INLINE_ Transform + light_instance_get_shadow_transform(RID p_light_instance, int p_index) { LightInstance *li = light_instance_owner.getornull(p_light_instance); return li->shadow_transform[p_index].transform; } + _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].bias_scale; + } + _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].farplane; + } + _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].range_begin; + } + + _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].uv_scale; + } _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) { @@ -940,6 +993,12 @@ public: return li->shadow_transform[p_index].split; } + _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) { + + LightInstance *li = light_instance_owner.getornull(p_light_instance); + return li->shadow_transform[p_index].shadow_texel_size; + } + _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) { LightInstance *li = light_instance_owner.getornull(p_light_instance); li->last_pass = p_pass; @@ -1103,13 +1162,24 @@ public: void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); - virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; } - _FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; } + virtual void set_scene_pass(uint64_t p_pass) { + scene_pass = p_pass; + } + _FORCE_INLINE_ uint64_t get_scene_pass() { + return scene_pass; + } virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve); virtual bool screen_space_roughness_limiter_is_active() 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); + + virtual void shadow_filter_set(RS::ShadowFilter p_filter); + _FORCE_INLINE_ RS::ShadowFilter shadow_filter_get() const { return shadow_filter; } + int get_roughness_layers() const; bool is_using_radiance_cubemap_array() const; @@ -1118,7 +1188,9 @@ public: virtual void update(); virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw); - _FORCE_INLINE_ RS::ViewportDebugDraw get_debug_draw_mode() const { return debug_draw; } + _FORCE_INLINE_ RS::ViewportDebugDraw get_debug_draw_mode() const { + return debug_draw; + } virtual void set_time(double p_time, double p_step); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index 322e89ef9a..0b26ec1be6 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -3104,15 +3104,17 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) { light.param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0; light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5; light.param[RS::LIGHT_PARAM_RANGE] = 1.0; + light.param[RS::LIGHT_PARAM_SIZE] = 0.0; light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45; - light.param[RS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45; light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8; - light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1; - light.param[RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1; + light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; + 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; return light_owner.make_rid(light); } @@ -3138,6 +3140,7 @@ void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, f case RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: case RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: case RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: + case RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE: case RS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index 49f77e49e1..7573a0d70c 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -926,6 +926,14 @@ public: return light->negative; } + _FORCE_INLINE_ float light_get_transmittance_bias(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_TRANSMITTANCE_BIAS]; + } + bool light_get_use_gi(RID p_light); uint64_t light_get_version(RID p_light) const; diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index ade0418bd2..04a43e3251 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -25,4 +25,5 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("screen_space_reflection.glsl") env.RD_GLSL("screen_space_reflection_filter.glsl") env.RD_GLSL("screen_space_reflection_scale.glsl") + env.RD_GLSL("subsurface_scattering.glsl") env.RD_GLSL("specular_merge.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/blur.glsl b/servers/rendering/rasterizer_rd/shaders/blur.glsl index 87c20ebaef..5dfdc614a4 100644 --- a/servers/rendering/rasterizer_rd/shaders/blur.glsl +++ b/servers/rendering/rasterizer_rd/shaders/blur.glsl @@ -285,6 +285,13 @@ void main() { frag_color = color; #endif +#ifdef MODE_LINEARIZE_DEPTH_COPY + float depth = texture(source_color, uv_interp, 0.0).r; + depth = depth * 2.0 - 1.0; + depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); + frag_color = vec4(depth / blur.camera_z_far); +#endif + #ifdef MODE_SSAO_MERGE vec4 color = texture(source_color, uv_interp, 0.0); float ssao = texture(source_ssao, uv_interp, 0.0).r; diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index cbb9b546a3..2b541f2660 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -57,6 +57,7 @@ void main() { } float depth = texture(source_cube, normal).r; + depth_buffer = depth; // absolute values for direction cosines, bigger value equals closer to basis axis vec3 unorm = abs(normal); @@ -80,7 +81,7 @@ void main() { depth = 2.0 * depth - 1.0; float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - depth_buffer = (linear_depth * depth_fix + params.bias) / params.z_far; + depth_buffer = (linear_depth * depth_fix) / params.z_far; #endif } diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 07f4770b14..70ce8d61e4 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -244,19 +244,13 @@ VERTEX_SHADER_CODE //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges - vec3 vtx = vertex_interp + normalize(vertex_interp) * scene_data.z_offset; + vec3 vtx = vertex_interp; float distance = length(vtx); vtx = normalize(vtx); vtx.xy /= 1.0 - vtx.z; vtx.z = (distance / scene_data.z_far); vtx.z = vtx.z * 2.0 - 1.0; - vertex_interp = vtx; -#else - - float z_ofs = scene_data.z_offset; - z_ofs += max(0.0, 1.0 - abs(normalize(normal_interp).z)) * scene_data.z_slope_scale; - vertex_interp.z -= z_ofs; #endif @@ -267,6 +261,14 @@ VERTEX_SHADER_CODE #else gl_Position = projection_matrix * vec4(vertex_interp, 1.0); #endif + +#ifdef MODE_RENDER_DEPTH + if (scene_data.pancake_shadows) { + if (gl_Position.z <= 0.00001) { + gl_Position.z = 0.00001; + } + } +#endif } /* clang-format off */ @@ -315,6 +317,11 @@ layout(location = 8) in float dp_clip; #define world_normal_matrix instances.data[instance_index].normal_transform #define projection_matrix scene_data.projection_matrix +#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) +//both required for transmittance to be enabled +#define LIGHT_TRANSMITTANCE_USED +#endif + #ifdef USE_MATERIAL_UNIFORMS layout(set = 5, binding = 0, std140) uniform MaterialUniforms{ /* clang-format off */ @@ -434,9 +441,16 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, vec3 attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - vec3 transmission, +void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, + float transmittance_z, #endif #ifdef LIGHT_RIM_USED float rim, float rim_tint, @@ -467,7 +481,7 @@ LIGHT_SHADER_CODE /* clang-format on */ #else - float NdotL = dot(N, L); + float NdotL = min(A + dot(N, L), 1.0); float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); @@ -477,11 +491,11 @@ LIGHT_SHADER_CODE #endif #if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cNdotH = max(dot(N, H), 0.0); + float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); #endif #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cLdotH = max(dot(L, H), 0.0); + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); #endif if (metallic < 1.0) { @@ -538,16 +552,48 @@ LIGHT_SHADER_CODE diffuse_brdf_NL = cNdotL * (1.0 / M_PI); #endif - diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; + diffuse_light += light_color * diffuse_color * shadow_attenuation * diffuse_brdf_NL * attenuation; -#if defined(LIGHT_TRANSMISSION_USED) - diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; +#if defined(LIGHT_BACKLIGHT_USED) + diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; #endif #if defined(LIGHT_RIM_USED) float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; #endif + +#ifdef LIGHT_TRANSMITTANCE_USED + +#ifdef SSS_MODE_SKIN + + { + float scale = 8.25 / transmittance_depth; + float d = scale * abs(transmittance_z); + float dd = -d * d; + vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); + + diffuse_light += profile * transmittance_color.a * diffuse_color * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI) * attenuation; + } +#else + + if (transmittance_depth > 0.0) { + float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0); + + fade = pow(max(0.0, 1.0 - fade), transmittance_curve); + fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); + + diffuse_light += diffuse_color * transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade * attenuation; + } + +#endif //SSS_MODE_SKIN + +#endif //LIGHT_TRANSMITTANCE_USED } if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely @@ -562,18 +608,18 @@ LIGHT_SHADER_CODE blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = blinn; - specular_light += light_color * intensity * specular_blob_intensity * attenuation; + specular_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(0.0, dot(R, V)); + float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float phong = pow(cRdotV, shininess); phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - specular_light += light_color * intensity * specular_blob_intensity * attenuation; + specular_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_TOON) @@ -582,7 +628,7 @@ LIGHT_SHADER_CODE float mid = 1.0 - roughness; mid *= mid; float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - diffuse_light += light_color * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection + diffuse_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection #elif defined(SPECULAR_DISABLED) // none.. @@ -613,7 +659,7 @@ LIGHT_SHADER_CODE vec3 specular_brdf_NL = cNdotL * D * F * G; - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + specular_light += specular_brdf_NL * light_color * shadow_attenuation * specular_blob_intensity * attenuation; #endif #if defined(LIGHT_CLEARCOAT_USED) @@ -627,12 +673,12 @@ LIGHT_SHADER_CODE float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + specular_light += clearcoat_specular_brdf_NL * light_color * shadow_attenuation * specular_blob_intensity * attenuation; #endif } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); + alpha = min(alpha, clamp(1.0 - length(shadow_attenuation * attenuation), 0.0, 1.0)); #endif #endif //defined(USE_LIGHT_SHADER_CODE) @@ -640,53 +686,119 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS +const vec2 shadow_poisson_disk[16] = vec2[]( + vec2(-0.94201624, -0.39906216), + vec2(0.94558609, -0.76890725), + vec2(-0.094184101, -0.92938870), + vec2(0.34495938, 0.29387760), + vec2(-0.91588581, 0.45771432), + vec2(-0.81544232, -0.87912464), + vec2(-0.38277543, 0.27676845), + vec2(0.97484398, 0.75648379), + vec2(0.44323325, -0.97511554), + vec2(0.53742981, -0.47373420), + vec2(-0.26496911, -0.41893023), + vec2(0.79197514, 0.19090188), + vec2(-0.24188840, 0.99706507), + vec2(-0.81409955, 0.91437590), + vec2(0.19984126, 0.78641367), + vec2(0.14383161, -0.14100790)); + float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { - //todo optimize vec2 pos = coord.xy; float depth = coord.z; -#ifdef SHADOW_MODE_PCF_13 + switch (scene_data.shadow_filter_mode) { + case SHADOW_MODE_NO_FILTER: { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + }; + case SHADOW_MODE_PCF5: { + float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); + return avg * (1.0 / 5.0); + }; + case SHADOW_MODE_PCF13: { + + float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); + return avg * (1.0 / 13.0); + }; + } - float avg = textureProj(shadow, vec4(pos, depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); - return avg * (1.0 / 13.0); -#endif + return 0; +} -#ifdef SHADOW_MODE_PCF_5 +float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { - float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - return avg * (1.0 / 5.0); + //find blocker + float blocker_count = 0.0; + float blocker_average = 0.0; -#endif + mat2 poisson_rotate; -#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) + { + float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123)); + float sr = sin(r); + float cr = cos(r); + poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr)); + } - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { + vec2 suv = pssm_coord.xy + (poisson_rotate * shadow_poisson_disk[i]) * tex_scale; + float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; + if (d < pssm_coord.z) { + blocker_average += d; + blocker_count += 1.0; + } + } -#endif + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (pssm_coord.z - blocker_average) / blocker_average; + tex_scale *= penumbra; + + float s = 0.0; + for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { + vec2 suv = pssm_coord.xy + (poisson_rotate * shadow_poisson_disk[i]) * tex_scale; + s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0)); + } + + return s / float(scene_data.shadow_blocker_count); + + } else { + //no blockers found, so no shadow + return 1.0; + } } #endif //USE_NO_SHADOWS void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - vec3 transmission, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, #endif #ifdef LIGHT_RIM_USED float rim, float rim_tint, @@ -707,45 +819,203 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a float normalized_distance = light_length * lights.data[idx].inv_radius; vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x); - vec3 light_attenuation = vec3(omni_attenuation); + float light_attenuation = omni_attenuation; + vec3 shadow_attenuation = vec3(1.0); vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); color_specular.rgb *= attenuation_energy.y; + float size_A = 0.0; + + if (lights.data[idx].size > 0.0) { + + float t = lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; //no transmittance by default +#endif #ifndef USE_NO_SHADOWS vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); if (shadow_color_enabled.w > 0.5) { // there is a shadowmap - vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); - float shadow_len = length(splane); - splane = normalize(splane); - vec4 clamp_rect = lights.data[idx].atlas_rect; + vec4 v = vec4(vertex, 1.0); + + vec4 splane = (lights.data[idx].shadow_matrix * v); + float shadow_len = length(splane.xyz); //need to remember shadow len from here + + { + vec3 nofs = normal_interp * lights.data[idx].shadow_normal_bias / lights.data[idx].inv_radius; + nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp)))); + v.xyz += nofs; + splane = (lights.data[idx].shadow_matrix * v); + } + + float shadow; + + if (lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker - if (splane.z >= 0.0) { + float blocker_count = 0.0; + float blocker_average = 0.0; - splane.z += 1.0; + mat2 poisson_rotate; - clamp_rect.y += clamp_rect.w; + { + float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123)); + float sr = sin(r); + float cr = cos(r); + poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + vec3 normal = normalize(splane.xyz); + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); + vec3 tangent = normalize(cross(v0, normal)); + vec3 bitangent = normalize(cross(tangent, normal)); + float z_norm = shadow_len * lights.data[idx].inv_radius; + + tangent *= lights.data[idx].soft_shadow_size; + bitangent *= lights.data[idx].soft_shadow_size; + + for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { + vec2 poisson = (poisson_rotate * shadow_poisson_disk[i]); + vec3 pos = splane.xyz + tangent * poisson.x + bitangent * poisson.y; + + pos = normalize(pos); + vec4 uv_rect = lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + tangent *= penumbra; + bitangent *= penumbra; + + z_norm -= lights.data[idx].inv_radius * lights.data[idx].shadow_bias; + + shadow = 0.0; + for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { + + vec2 poisson = (poisson_rotate * shadow_poisson_disk[i]); + vec3 pos = splane.xyz + tangent * poisson.x + bitangent * poisson.y; + + pos = normalize(pos); + vec4 uv_rect = lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); + } + + shadow /= float(scene_data.shadow_blocker_count); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } } else { - splane.z = 1.0 - splane.z; + splane.xyz = normalize(splane.xyz); + vec4 clamp_rect = lights.data[idx].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[idx].shadow_bias) * lights.data[idx].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already + shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); } - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * lights.data[idx].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 shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); +#ifdef LIGHT_TRANSMITTANCE_USED + { + + //redo shadowmapping, but shrink the model a bit to avoid arctifacts + splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); + + shadow_len = length(splane); + splane = normalize(splane); + + if (splane.z >= 0.0) { + + splane.z += 1.0; + + } 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[idx].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 shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + transmittance_z = (splane.z - shadow_z) / lights.data[idx].inv_radius; + } +#endif - light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); } #endif //USE_NO_SHADOWS - light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - transmission, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, #endif #ifdef LIGHT_RIM_USED rim * omni_attenuation, rim_tint, @@ -764,8 +1034,14 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a } void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - vec3 transmission, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, #endif #ifdef LIGHT_RIM_USED float rim, float rim_tint, @@ -792,31 +1068,135 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a 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)); spot_attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x); - vec3 light_attenuation = vec3(spot_attenuation); + float light_attenuation = spot_attenuation; + vec3 shadow_attenuation = vec3(1.0); vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); color_specular.rgb *= attenuation_energy.y; + float size_A = 0.0; + + if (lights.data[idx].size > 0.0) { + + float t = lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } /* if (lights.data[idx].atlas_rect!=vec4(0.0)) { //use projector texture } */ +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; +#endif + #ifndef USE_NO_SHADOWS vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); if (shadow_color_enabled.w > 0.5) { //there is a shadowmap - vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); + vec4 v = vec4(vertex, 1.0); + + v.xyz -= spot_dir * lights.data[idx].shadow_bias; + + float z_norm = dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius; + + float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * lights.data[idx].shadow_normal_bias * depth_bias_scale; + normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z + v.xyz += normal_bias; + + //adjust with bias + z_norm = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius; + + float shadow; + + vec4 splane = (lights.data[idx].shadow_matrix * v); splane /= splane.w; - float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); - light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + if (lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 poisson_rotate; + + { + float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123)); + float sr = sin(r); + float cr = cos(r); + poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float uv_size = lights.data[idx].soft_shadow_size * z_norm; + for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { + vec2 suv = splane.xy + (poisson_rotate * shadow_poisson_disk[i]) * uv_size; + suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw); + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + uv_size *= penumbra; + + shadow = 0.0; + for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { + vec2 suv = splane.xy + (poisson_rotate * shadow_poisson_disk[i]) * uv_size; + suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw); + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); + } + + shadow /= float(scene_data.shadow_blocker_count); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + + } else { + //hard shadow + splane.z = z_norm; + shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); + } + + shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + +#ifdef LIGHT_TRANSMITTANCE_USED + { + + vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); + splane /= splane.w; + + 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; + //distance to light plane + float z = dot(spot_dir, -light_rel_vec); + transmittance_z = z - shadow_z; + } +#endif //LIGHT_TRANSMITTANCE_USED } #endif //USE_NO_SHADOWS - light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - transmission, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, #endif #ifdef LIGHT_RIM_USED rim * spot_attenuation, rim_tint, @@ -1185,7 +1565,11 @@ void main() { vec3 vertex = vertex_interp; vec3 view = -normalize(vertex_interp); vec3 albedo = vec3(1.0); - vec3 transmission = vec3(0.0); + vec3 backlight = vec3(0.0); + vec4 transmittance_color = vec4(0.0); + float transmittance_depth = 0.0; + float transmittance_curve = 1.0; + float transmittance_boost = 0.0; float metallic = 0.0; float specular = 0.5; vec3 emission = vec3(0.0); @@ -1254,6 +1638,14 @@ FRAGMENT_SHADER_CODE /* clang-format on */ } +#if defined(LIGHT_TRANSMITTANCE_USED) +#ifdef SSS_MODE_SKIN + transmittance_color.a = sss_strength; +#else + transmittance_color.a *= sss_strength; +#endif +#endif + #if !defined(USE_SHADOW_TO_OPACITY) #if defined(ALPHA_SCISSOR_USED) @@ -1462,58 +1854,250 @@ FRAGMENT_SHADER_CODE continue; //not masked } - vec3 light_attenuation = vec3(1.0); + vec3 shadow_attenuation = vec3(1.0); + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; +#endif if (directional_lights.data[i].shadow_enabled) { float depth_z = -vertex.z; vec4 pssm_coord; + vec3 shadow_color = vec3(0.0); + vec3 light_dir = directional_lights.data[i].direction; + +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ + m_var.xyz += normal_bias; + + float shadow = 0.0; if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - pssm_coord = (directional_lights.data[i].shadow_matrix1 * vec4(vertex, 1.0)); + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 0) + + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.x; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + } else { + shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color1.rgb; + +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; + 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; + + transmittance_z = z - shadow_z; + } +#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - pssm_coord = (directional_lights.data[i].shadow_matrix2 * vec4(vertex, 1.0)); + + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 1) + + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.y; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + } else { + shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color2.rgb; +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; + 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; + + transmittance_z = z - shadow_z; + } +#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - pssm_coord = (directional_lights.data[i].shadow_matrix3 * vec4(vertex, 1.0)); + + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 2) + + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.z; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + } else { + shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color3.rgb; +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; + 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; + + transmittance_z = z - shadow_z; + } +#endif + } else { - pssm_coord = (directional_lights.data[i].shadow_matrix4 * vec4(vertex, 1.0)); - } - pssm_coord /= pssm_coord.w; + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 3) + + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.w; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + } else { + shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color4.rgb; + +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; + 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; - float shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + transmittance_z = z - shadow_z; + } +#endif + } if (directional_lights.data[i].blend_splits) { + vec3 shadow_color_blend = vec3(0.0); float pssm_blend; + float shadow2; if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - pssm_coord = (directional_lights.data[i].shadow_matrix2 * vec4(vertex, 1.0)); + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 1) + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.y; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + } else { + shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + } + pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); + shadow_color_blend = directional_lights.data[i].shadow_color2.rgb; } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - pssm_coord = (directional_lights.data[i].shadow_matrix3 * vec4(vertex, 1.0)); + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 2) + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.z; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + } else { + shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + } + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); + + shadow_color_blend = directional_lights.data[i].shadow_color3.rgb; } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - pssm_coord = (directional_lights.data[i].shadow_matrix4 * vec4(vertex, 1.0)); + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 3) + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.w; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + } else { + shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + } + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); + shadow_color_blend = directional_lights.data[i].shadow_color4.rgb; } else { pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) } - pssm_coord /= pssm_coord.w; + pssm_blend = sqrt(pssm_blend); - float shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); shadow = mix(shadow, shadow2, pssm_blend); + shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend); } shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance - light_attenuation = mix(directional_lights.data[i].shadow_color, vec3(1.0), shadow); + shadow_attenuation = mix(shadow_color, vec3(1.0), shadow); + +#undef BIAS_FUNC } - light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, light_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - transmission, + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].size, directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, #endif #ifdef LIGHT_RIM_USED rim, rim_tint, @@ -1546,8 +2130,14 @@ FRAGMENT_SHADER_CODE } light_process_omni(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - transmission, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED rim, @@ -1579,8 +2169,14 @@ FRAGMENT_SHADER_CODE } light_process_spot(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - transmission, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED rim, @@ -1697,6 +2293,9 @@ FRAGMENT_SHADER_CODE #else +#ifdef SSS_MODE_SKIN + sss_strength = -sss_strength; +#endif diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); specular_buffer = vec4(specular_light, metallic); diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl index baef1e060f..59f326bc9b 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl @@ -22,6 +22,10 @@ draw_call; #define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 #define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 +#define SHADOW_MODE_NO_FILTER 0 +#define SHADOW_MODE_PCF5 1 +#define SHADOW_MODE_PCF13 2 + layout(set = 0, binding = 1) uniform sampler material_samplers[12]; layout(set = 0, binding = 2) uniform sampler shadow_sampler; @@ -37,13 +41,17 @@ layout(set = 0, binding = 3, std140) uniform SceneData { vec2 viewport_size; vec2 screen_pixel_size; - //used for shadow mapping only - float z_offset; - float z_slope_scale; - float time; float reflection_multiplier; // one normally, zero when rendering reflections + bool pancake_shadows; + uint shadow_filter_mode; + + uint shadow_blocker_count; + uint shadow_pad0; + uint shadow_pad1; + uint shadow_pad2; + vec4 ambient_light_color_energy; float ambient_color_sky_mix; @@ -134,21 +142,27 @@ layout(set = 0, binding = 4, std430) buffer Instances { } instances; -struct LightData { //this structure needs to be 128 bits +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 mask; uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) - vec4 atlas_rect; //used for shadow atlas uv on omni, and for projection atlas on spot + vec4 atlas_rect; // used for spot 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 + uint mask; + uint pad[3]; }; -layout(set = 0, binding = 5, std140) uniform Lights { - LightData data[MAX_LIGHT_DATA_STRUCTS]; +layout(set = 0, binding = 5, std430) buffer Lights { + LightData data[]; } lights; @@ -173,18 +187,33 @@ struct DirectionalLightData { vec3 direction; float energy; vec3 color; + float size; float specular; - vec3 shadow_color; uint mask; + float softshadow_angle; + uint pad1; 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 { diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl index 671e289ed0..1a5dd5ab55 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl @@ -69,8 +69,6 @@ float gauss_weight(float p_val) { 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 vec3 reconstructCSPosition(vec2 S, float z) { @@ -105,17 +103,14 @@ void do_filter(inout vec4 accum, inout float accum_radius, inout float divisor, break; } - float contrib = 0.0; if (d < radius) { - contrib += gauss_weight(d / radius); - } - if (contrib > 0.0) { - accum += imageLoad(source_ssr, tc) * contrib; + float w = gauss_weight(d / radius); + accum += imageLoad(source_ssr, tc) * w; #ifndef VERTICAL_PASS - accum_radius += r * contrib; + accum_radius += r * w; #endif - divisor += contrib; + divisor += w; } } } diff --git a/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl new file mode 100644 index 0000000000..41f8fde3ca --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl @@ -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); +} diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h index 8480aa30fc..1b9755397a 100644 --- a/servers/rendering/rendering_server_raster.h +++ b/servers/rendering/rendering_server_raster.h @@ -456,7 +456,7 @@ public: BIND0R(RID, viewport_create) - BIND2(viewport_set_use_arvr, RID, bool) + BIND2(viewport_set_use_xr, RID, bool) BIND3(viewport_set_size, RID, int, int) BIND2(viewport_set_active, RID, bool) @@ -541,6 +541,8 @@ public: BIND5(environment_set_fog_height, RID, bool, float, float, 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 */ @@ -552,6 +554,8 @@ public: BIND8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) BIND3(camera_effects_set_custom_exposure, RID, bool, float) + BIND1(shadow_filter_set, ShadowFilter) + /* SCENARIO API */ #undef BINDBASE diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp index 65823e11aa..d66708587a 100644 --- a/servers/rendering/rendering_server_scene.cpp +++ b/servers/rendering/rendering_server_scene.cpp @@ -1334,7 +1334,7 @@ void RenderingServerScene::_update_instance_lightmap_captures(Instance *p_instan } } -bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) { +bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); @@ -1347,16 +1347,18 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c case RS::LIGHT_DIRECTIONAL: { - float max_distance = p_cam_projection.get_z_far(); - float shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); + real_t max_distance = p_cam_projection.get_z_far(); + real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera max_distance = MIN(shadow_max, max_distance); } max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); - float min_distance = MIN(p_cam_projection.get_z_near(), max_distance); + real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); + real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); + if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) { //optimize min/max Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); @@ -1365,8 +1367,8 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c //check distance max and min bool found_items = false; - float z_max = -1e20; - float z_min = 1e20; + real_t z_max = -1e20; + real_t z_min = 1e20; for (int i = 0; i < cull_count; i++) { @@ -1379,7 +1381,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c animated_material_found = true; } - float max, min; + real_t max, min; instance->transformed_aabb.project_range_in_plane(base, min, max); if (max > z_max) { @@ -1399,7 +1401,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - float range = max_distance - min_distance; + real_t range = max_distance - min_distance; int splits = 0; switch (RSG::storage->light_directional_get_shadow_mode(p_instance->base)) { @@ -1408,7 +1410,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: splits = 4; break; } - float distances[5]; + real_t distances[5]; distances[0] = min_distance; for (int i = 0; i < splits; i++) { @@ -1417,11 +1419,13 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c distances[splits] = max_distance; - float texture_size = RSG::scene_render->get_directional_light_shadow_size(light->instance); + real_t texture_size = RSG::scene_render->get_directional_light_shadow_size(light->instance); bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base); - float first_radius = 0.0; + real_t first_radius = 0.0; + + real_t min_distance_bias_scale = pancake_size > 0 ? distances[1] / 10.0 : 0; for (int i = 0; i < splits; i++) { @@ -1430,7 +1434,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c // setup a camera matrix for that range! CameraMatrix camera_matrix; - float aspect = p_cam_projection.get_aspect(); + real_t aspect = p_cam_projection.get_aspect(); if (p_cam_orthogonal) { @@ -1439,8 +1443,8 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); } else { - float fov = p_cam_projection.get_fov(); - camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + real_t fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it + camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); } //obtain the frustum endpoints @@ -1458,26 +1462,27 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized(); //z_vec points agsint the camera, like in default opengl - float x_min = 0.f, x_max = 0.f; - float y_min = 0.f, y_max = 0.f; - float z_min = 0.f, z_max = 0.f; + real_t x_min = 0.f, x_max = 0.f; + real_t y_min = 0.f, y_max = 0.f; + real_t z_min = 0.f, z_max = 0.f; // FIXME: z_max_cam is defined, computed, but not used below when setting up // ortho_camera. Commented out for now to fix warnings but should be investigated. - float x_min_cam = 0.f, x_max_cam = 0.f; - float y_min_cam = 0.f, y_max_cam = 0.f; - float z_min_cam = 0.f; - //float z_max_cam = 0.f; + real_t x_min_cam = 0.f, x_max_cam = 0.f; + real_t y_min_cam = 0.f, y_max_cam = 0.f; + real_t z_min_cam = 0.f; + //real_t z_max_cam = 0.f; - float bias_scale = 1.0; + real_t bias_scale = 1.0; + real_t aspect_bias_scale = 1.0; //used for culling for (int j = 0; j < 8; j++) { - float d_x = x_vec.dot(endpoints[j]); - float d_y = y_vec.dot(endpoints[j]); - float d_z = z_vec.dot(endpoints[j]); + real_t d_x = x_vec.dot(endpoints[j]); + real_t d_y = y_vec.dot(endpoints[j]); + real_t d_z = z_vec.dot(endpoints[j]); if (j == 0 || d_x < x_min) x_min = d_x; @@ -1495,11 +1500,13 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c z_max = d_z; } + real_t radius = 0; + real_t soft_shadow_expand = 0; + Vector3 center; + { //camera viewport stuff - Vector3 center; - for (int j = 0; j < 8; j++) { center += endpoints[j]; @@ -1508,11 +1515,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5; - float radius = 0; - for (int j = 0; j < 8; j++) { - float d = center.distance_to(endpoints[j]); + real_t d = center.distance_to(endpoints[j]); if (d > radius) radius = d; } @@ -1525,18 +1530,35 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c bias_scale = radius / first_radius; } - x_max_cam = x_vec.dot(center) + radius; - x_min_cam = x_vec.dot(center) - radius; - y_max_cam = y_vec.dot(center) + radius; - y_min_cam = y_vec.dot(center) - radius; - //z_max_cam = z_vec.dot(center) + radius; z_min_cam = z_vec.dot(center) - radius; + { + + float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE); + + if (soft_shadow_angle > 0.0 && pancake_size > 0.0) { + + float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam; + soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range; + + x_max += soft_shadow_expand; + y_max += soft_shadow_expand; + + x_min -= soft_shadow_expand; + y_min -= soft_shadow_expand; + } + } + + x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; + x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; + y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; + y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; + if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { //this trick here is what stabilizes the shadow (make potential jaggies to not move) //at the cost of some wasted resolution. Still the quality increase is very well worth it - float unit = radius * 2.0 / texture_size; + real_t unit = radius * 2.0 / texture_size; x_max_cam = Math::stepify(x_max_cam, unit); x_min_cam = Math::stepify(x_min_cam, unit); @@ -1566,9 +1588,10 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); + real_t cull_max = 0; for (int j = 0; j < cull_count; j++) { - float min, max; + real_t min, max; Instance *instance = instance_shadow_cull_result[j]; if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { cull_count--; @@ -1580,8 +1603,91 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c instance->transformed_aabb.project_range_in_plane(Plane(z_vec, 0), min, max); instance->depth = near_plane.distance_to(instance->transform.origin); instance->depth_layer = 0; - if (max > z_max) - z_max = max; + if (j == 0 || max > cull_max) { + cull_max = max; + } + } + + if (cull_max > z_max) { + z_max = cull_max; + } + + if (pancake_size > 0) { + z_max = z_vec.dot(center) + radius + pancake_size; + } + + if (aspect != 1.0) { + + // if the aspect is different, then the radius will become larger. + // if this happens, then bias needs to be adjusted too, as depth will increase + // to do this, compare the depth of one that would have resulted from a square frustum + + CameraMatrix camera_matrix_square; + if (p_cam_orthogonal) { + + Vector2 vp_he = camera_matrix.get_viewport_half_extents(); + if (p_cam_vaspect) { + camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } else { + camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } + } else { + Vector2 vp_he = camera_matrix.get_viewport_half_extents(); + if (p_cam_vaspect) { + camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } else { + camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } + + if (i == 0) { + //print_line("prev he: " + vp_he + " new he: " + camera_matrix_square.get_viewport_half_extents()); + } + } + + Vector3 endpoints_square[8]; // frustum plane endpoints + res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square); + ERR_CONTINUE(!res); + Vector3 center_square; + real_t z_max_square = 0; + + for (int j = 0; j < 8; j++) { + + center_square += endpoints_square[j]; + + real_t d_z = z_vec.dot(endpoints_square[j]); + + if (j == 0 || d_z > z_max_square) + z_max_square = d_z; + } + + if (cull_max > z_max_square) { + z_max_square = cull_max; + } + + center_square /= 8.0; + + real_t radius_square = 0; + + for (int j = 0; j < 8; j++) { + + real_t d = center_square.distance_to(endpoints_square[j]); + if (d > radius_square) + radius_square = d; + } + + radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side + + if (pancake_size > 0) { + z_max_square = z_vec.dot(center_square) + radius_square + pancake_size; + } + + real_t z_min_cam_square = z_vec.dot(center_square) - radius_square; + + aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square); + + // this is not entirely perfect, because the cull-adjusted z-max may be different + // but at least it's warranted that it results in a greater bias, so no acne should be present either way. + // pancaking also helps with this. } { @@ -1592,11 +1698,19 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam)); + Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); + Transform ortho_transform; ortho_transform.basis = transform.basis; ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; - RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, 0, distances[i + 1], i, bias_scale); + { + Vector3 max_in_view = p_cam_transform.affine_inverse().xform(z_vec * cull_max); + Vector3 dir_in_view = p_cam_transform.xform_inv(z_vec).normalized(); + cull_max = dir_in_view.dot(max_in_view); + } + + RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale, z_max, uv_scale); } RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); @@ -1614,9 +1728,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c //using this one ensures that raster deferred will have it RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i)); - float radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - float z = i == 0 ? -1 : 1; + real_t z = i == 0 ? -1 : 1; Vector<Plane> planes; planes.resize(5); planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); @@ -1645,12 +1759,12 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); } } else { //shadow cube - float radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); CameraMatrix cm; cm.set_perspective(90, 1, 0.01, radius); @@ -1699,12 +1813,12 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); } //restore the regular DP matrix - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); } } break; @@ -1712,8 +1826,8 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c RENDER_TIMESTAMP("Culling Spot Light"); - float radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - float angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); CameraMatrix cm; cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); @@ -1738,7 +1852,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); } break; @@ -1793,12 +1907,12 @@ void RenderingServerScene::render_camera(RID p_render_buffers, RID p_camera, RID } break; } - _prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); + _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); #endif } -void RenderingServerScene::render_camera(RID p_render_buffers, Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { +void RenderingServerScene::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { // render for AR/VR interface Camera *camera = camera_owner.getornull(p_camera); @@ -1810,16 +1924,14 @@ void RenderingServerScene::render_camera(RID p_render_buffers, Ref<ARVRInterface // We also ignore our camera position, it will have been positioned with a slightly old tracking position. // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! - Transform world_origin = ARVRServer::get_singleton()->get_world_origin(); + Transform world_origin = XRServer::get_singleton()->get_world_origin(); Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye - if (p_eye == ARVRInterface::EYE_LEFT) { - ///@TODO possibly move responsibility for this into our ARVRServer or ARVRInterface? - + if (p_eye == XRInterface::EYE_LEFT) { // Center our transform, we assume basis is equal. Transform mono_transform = cam_transform; - Transform right_transform = p_interface->get_transform_for_eye(ARVRInterface::EYE_RIGHT, world_origin); + Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); mono_transform.origin += right_transform.origin; mono_transform.origin *= 0.5; @@ -1872,17 +1984,17 @@ void RenderingServerScene::render_camera(RID p_render_buffers, Ref<ARVRInterface mono_transform *= apply_z_shift; // now prepare our scene with our adjusted transform projection matrix - _prepare_scene(mono_transform, combined_matrix, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - } else if (p_eye == ARVRInterface::EYE_MONO) { + _prepare_scene(mono_transform, combined_matrix, false, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); + } else if (p_eye == XRInterface::EYE_MONO) { // For mono render, prepare as per usual - _prepare_scene(cam_transform, camera_matrix, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); + _prepare_scene(cam_transform, camera_matrix, false, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); } // And render our scene... _render_scene(p_render_buffers, cam_transform, camera_matrix, false, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); }; -void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) { +void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) { // Note, in stereo rendering: // - p_cam_transform will be a transform in the middle of our two eyes // - p_cam_projection is a wider frustrum that encompasses both eyes @@ -2112,7 +2224,7 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i)); - _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario); + _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i)); } @@ -2214,7 +2326,7 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const if (redraw) { //must redraw! RENDER_TIMESTAMP(">Rendering Light " + itos(i)); - light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario); + light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); RENDER_TIMESTAMP("<Rendering Light " + itos(i)); } } @@ -2324,7 +2436,7 @@ bool RenderingServerScene::_render_reflection_probe_step(Instance *p_instance, i } RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); - _prepare_scene(xform, cm, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows); + _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows); _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step); } else { diff --git a/servers/rendering/rendering_server_scene.h b/servers/rendering/rendering_server_scene.h index 41641b7c75..0970fed6c4 100644 --- a/servers/rendering/rendering_server_scene.h +++ b/servers/rendering/rendering_server_scene.h @@ -39,7 +39,7 @@ #include "core/os/thread.h" #include "core/rid_owner.h" #include "core/self_list.h" -#include "servers/arvr/arvr_interface.h" +#include "servers/xr/xr_interface.h" class RenderingServerScene { public: @@ -418,15 +418,15 @@ public: _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); - _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); + _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario); bool _render_reflection_probe_step(Instance *p_instance, int p_step); - void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true); + void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true); void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); void render_probes(); diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/rendering_server_viewport.cpp index aa65101ddf..87dcb772bc 100644 --- a/servers/rendering/rendering_server_viewport.cpp +++ b/servers/rendering/rendering_server_viewport.cpp @@ -62,24 +62,24 @@ static Transform2D _canvas_get_transform(RenderingServerViewport::Viewport *p_vi return xf; } -void RenderingServerViewport::_draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye) { +void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { RENDER_TIMESTAMP(">Begin Rendering 3D Scene"); - Ref<ARVRInterface> arvr_interface; - if (ARVRServer::get_singleton() != nullptr) { - arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + Ref<XRInterface> xr_interface; + if (XRServer::get_singleton() != nullptr) { + xr_interface = XRServer::get_singleton()->get_primary_interface(); } - if (p_viewport->use_arvr && arvr_interface.is_valid()) { - RSG::scene->render_camera(p_viewport->render_buffers, arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + if (p_viewport->use_xr && xr_interface.is_valid()) { + RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); } else { RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); } RENDER_TIMESTAMP("<End Rendering 3D Scene"); } -void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye) { +void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) { /* Camera should always be BEFORE any other 3D */ @@ -293,17 +293,15 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface void RenderingServerViewport::draw_viewports() { -#if 0 - // get our arvr interface in case we need it - Ref<ARVRInterface> arvr_interface; + // get our xr interface in case we need it + Ref<XRInterface> xr_interface; - if (ARVRServer::get_singleton() != nullptr) { - arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + if (XRServer::get_singleton() != nullptr) { + xr_interface = XRServer::get_singleton()->get_primary_interface(); // process all our active interfaces - ARVRServer::get_singleton()->_process(); + XRServer::get_singleton()->_process(); } -#endif if (Engine::get_singleton()->is_editor_hint()) { set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color")); @@ -367,38 +365,41 @@ void RenderingServerViewport::draw_viewports() { RSG::storage->render_target_set_as_unused(vp->render_target); #if 0 - if (vp->use_arvr && arvr_interface.is_valid()) { + // TODO fix up this code after we change our commit_for_eye to accept our new render targets + + if (vp->use_xr && xr_interface.is_valid()) { // override our size, make sure it matches our required size - vp->size = arvr_interface->get_render_targetsize(); + vp->size = xr_interface->get_render_targetsize(); RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y); // render mono or left eye first - ARVRInterface::Eyes leftOrMono = arvr_interface->is_stereo() ? ARVRInterface::EYE_LEFT : ARVRInterface::EYE_MONO; + XRInterface::Eyes leftOrMono = xr_interface->is_stereo() ? XRInterface::EYE_LEFT : XRInterface::EYE_MONO; // check for an external texture destination for our left eye/mono - RSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(leftOrMono)); + // TODO investigate how we're going to make external textures work + RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono)); // set our render target as current RSG::rasterizer->set_current_render_target(vp->render_target); // and draw left eye/mono _draw_viewport(vp, leftOrMono); - arvr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect); + xr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect); // render right eye - if (leftOrMono == ARVRInterface::EYE_LEFT) { + if (leftOrMono == XRInterface::EYE_LEFT) { // check for an external texture destination for our right eye - RSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(ARVRInterface::EYE_RIGHT)); + RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(XRInterface::EYE_RIGHT)); // commit for eye may have changed the render target RSG::rasterizer->set_current_render_target(vp->render_target); - _draw_viewport(vp, ARVRInterface::EYE_RIGHT); - arvr_interface->commit_for_eye(ARVRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect); + _draw_viewport(vp, XRInterface::EYE_RIGHT); + xr_interface->commit_for_eye(XRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect); } // and for our frame timing, mark when we've finished committing our eyes - ARVRServer::get_singleton()->_mark_commit(); + XRServer::get_singleton()->_mark_commit(); } else { #endif { @@ -470,11 +471,11 @@ RID RenderingServerViewport::viewport_create() { return rid; } -void RenderingServerViewport::viewport_set_use_arvr(RID p_viewport, bool p_use_arvr) { +void RenderingServerViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - viewport->use_arvr = p_use_arvr; + viewport->use_xr = p_use_xr; } void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/rendering_server_viewport.h index f574c58d96..71d8408ed1 100644 --- a/servers/rendering/rendering_server_viewport.h +++ b/servers/rendering/rendering_server_viewport.h @@ -34,8 +34,8 @@ #include "core/rid_owner.h" #include "core/self_list.h" #include "rasterizer.h" -#include "servers/arvr/arvr_interface.h" #include "servers/rendering_server.h" +#include "servers/xr/xr_interface.h" class RenderingServerViewport { public: @@ -47,7 +47,7 @@ public: RID self; RID parent; - bool use_arvr; /* use arvr interface to override camera positioning and projection matrices and control output */ + bool use_xr; /* use xr interface to override camera positioning and projection matrices and control output */ Size2i size; RID camera; @@ -127,7 +127,7 @@ public: for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) { render_info[i] = 0; } - use_arvr = false; + use_xr = false; } }; @@ -152,13 +152,13 @@ public: Vector<Viewport *> active_viewports; private: - void _draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye); - void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO); + void _draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye); + void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO); public: RID viewport_create(); - void viewport_set_use_arvr(RID p_viewport, bool p_use_arvr); + void viewport_set_use_xr(RID p_viewport, bool p_use_xr); void viewport_set_size(RID p_viewport, int p_width, int p_height); diff --git a/servers/rendering/rendering_server_wrap_mt.cpp b/servers/rendering/rendering_server_wrap_mt.cpp index aa3bf583c7..4ca13dbef9 100644 --- a/servers/rendering/rendering_server_wrap_mt.cpp +++ b/servers/rendering/rendering_server_wrap_mt.cpp @@ -126,17 +126,6 @@ void RenderingServerWrapMT::init() { void RenderingServerWrapMT::finish() { - if (thread) { - - command_queue.push(this, &RenderingServerWrapMT::thread_exit); - Thread::wait_to_finish(thread); - memdelete(thread); - - thread = nullptr; - } else { - rendering_server->finish(); - } - sky_free_cached_ids(); shader_free_cached_ids(); material_free_cached_ids(); @@ -161,6 +150,17 @@ void RenderingServerWrapMT::finish() { canvas_item_free_cached_ids(); canvas_light_occluder_free_cached_ids(); canvas_occluder_polygon_free_cached_ids(); + + if (thread) { + + command_queue.push(this, &RenderingServerWrapMT::thread_exit); + Thread::wait_to_finish(thread); + memdelete(thread); + + thread = nullptr; + } else { + rendering_server->finish(); + } } void RenderingServerWrapMT::set_use_vsync_callback(bool p_enable) { diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index 13dad3ec18..9a98841b2c 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -370,7 +370,7 @@ public: FUNCRID(viewport) - FUNC2(viewport_set_use_arvr, RID, bool) + FUNC2(viewport_set_use_xr, RID, bool) FUNC3(viewport_set_size, RID, int, int) @@ -456,6 +456,8 @@ public: FUNC5(environment_set_fog_height, RID, bool, float, float, 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) @@ -465,6 +467,8 @@ public: FUNC8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) FUNC3(camera_effects_set_custom_exposure, RID, bool, float) + FUNC1(shadow_filter_set, ShadowFilter) + FUNCRID(scenario) FUNC2(scenario_set_debug, RID, ScenarioDebugMode) diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index ba7b992e51..de69fea16f 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -108,7 +108,11 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY_FLOW"] = ShaderLanguage::TYPE_VEC2; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_STRENGTH"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["TRANSMISSION"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_COLOR"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_DEPTH"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_CURVE"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_BOOST"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BACKLIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3; @@ -145,7 +149,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ATTENUATION"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALBEDO"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["TRANSMISSION"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["BACKLIGHT"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3; @@ -168,6 +172,8 @@ ShaderTypes::ShaderTypes() { 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_front"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_disabled"); |