diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd')
31 files changed, 6131 insertions, 1106 deletions
diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp index 943ef1c7fa..f75308a975 100644 --- a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp +++ b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp @@ -39,6 +39,7 @@ void LightClusterBuilder::begin(const Transform &p_view_transform, const CameraM //reset counts light_count = 0; refprobe_count = 0; + decal_count = 0; item_count = 0; sort_id_count = 0; } diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.h b/servers/rendering/rasterizer_rd/light_cluster_builder.h index 3411ed07a0..78288dc620 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; } @@ -195,23 +193,25 @@ public: refprobes = (OrientedBoxData *)memrealloc(refprobes, sizeof(OrientedBoxData) * refprobe_max); } + Transform xform = view_xform * p_transform; + OrientedBoxData &rp = refprobes[refprobe_count]; - Vector3 origin = p_transform.origin; + Vector3 origin = xform.origin; rp.position[0] = origin.x; rp.position[1] = origin.y; rp.position[2] = origin.z; - Vector3 x_axis = p_transform.basis.get_axis(0) * p_half_extents.x; + Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x; rp.x_axis[0] = x_axis.x; rp.x_axis[1] = x_axis.y; rp.x_axis[2] = x_axis.z; - Vector3 y_axis = p_transform.basis.get_axis(1) * p_half_extents.y; + Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y; rp.y_axis[0] = y_axis.x; rp.y_axis[1] = y_axis.y; rp.y_axis[2] = y_axis.z; - Vector3 z_axis = p_transform.basis.get_axis(2) * p_half_extents.z; + Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z; rp.z_axis[0] = z_axis.x; rp.z_axis[1] = z_axis.y; rp.z_axis[2] = z_axis.z; @@ -232,35 +232,37 @@ public: refprobe_count++; } - _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector2 &p_half_extents, float p_depth) { + _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector3 &p_half_extents) { if (unlikely(decal_count == decal_max)) { decal_max = nearest_power_of_2_templated(decal_max + 1); decals = (OrientedBoxData *)memrealloc(decals, sizeof(OrientedBoxData) * decal_max); } - OrientedBoxData &dc = decals[decal_count]; + Transform xform = view_xform * p_transform; - Vector3 z_axis = -p_transform.basis.get_axis(2) * p_depth * 0.5; - dc.z_axis[0] = z_axis.x; - dc.z_axis[1] = z_axis.y; - dc.z_axis[2] = z_axis.z; + OrientedBoxData &dc = decals[decal_count]; - Vector3 origin = p_transform.origin - z_axis; + Vector3 origin = xform.origin; dc.position[0] = origin.x; dc.position[1] = origin.y; dc.position[2] = origin.z; - Vector3 x_axis = p_transform.basis.get_axis(0) * p_half_extents.x; + Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x; dc.x_axis[0] = x_axis.x; dc.x_axis[1] = x_axis.y; dc.x_axis[2] = x_axis.z; - Vector3 y_axis = p_transform.basis.get_axis(1) * p_half_extents.y; + Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y; dc.y_axis[0] = y_axis.x; dc.y_axis[1] = y_axis.y; dc.y_axis[2] = y_axis.z; + Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z; + dc.z_axis[0] = z_axis.x; + dc.z_axis[1] = z_axis.y; + dc.z_axis[2] = z_axis.z; + AABB aabb; aabb.position = origin + x_axis + y_axis + z_axis; diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp index ba4f4c4acb..956bf54d01 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -273,7 +273,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int Vector<uint8_t> polygon_buffer; polygon_buffer.resize(buffer_size * sizeof(float)); - Vector<RD::VertexDescription> descriptions; + Vector<RD::VertexAttribute> descriptions; descriptions.resize(4); Vector<RID> buffers; buffers.resize(4); @@ -284,7 +284,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int uint32_t *uptr = (uint32_t *)r; uint32_t base_offset = 0; { //vertices - RD::VertexDescription vd; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; vd.offset = base_offset * sizeof(float); vd.location = RS::ARRAY_VERTEX; @@ -304,7 +304,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int //colors if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) { - RD::VertexDescription vd; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; vd.offset = base_offset * sizeof(float); vd.location = RS::ARRAY_COLOR; @@ -332,7 +332,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int } base_offset += 4; } else { - RD::VertexDescription vd; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; vd.offset = 0; vd.location = RS::ARRAY_COLOR; @@ -344,7 +344,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int //uvs if ((uint32_t)p_uvs.size() == vertex_count) { - RD::VertexDescription vd; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; vd.offset = base_offset * sizeof(float); vd.location = RS::ARRAY_TEX_UV; @@ -360,7 +360,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int } base_offset += 2; } else { - RD::VertexDescription vd; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; vd.offset = 0; vd.location = RS::ARRAY_TEX_UV; @@ -372,7 +372,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int //bones if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) { - RD::VertexDescription vd; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; vd.offset = base_offset * sizeof(float); vd.location = RS::ARRAY_BONES; @@ -401,7 +401,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int base_offset += 4; } else { - RD::VertexDescription vd; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; vd.offset = 0; vd.location = RS::ARRAY_BONES; @@ -618,6 +618,14 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 7; + u.ids.push_back(storage->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + //validate and update lighs if they are being used if (light_count > 0) { @@ -2012,6 +2020,9 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + continue; + } if (E->get().texture_order >= 0) { order[E->get().texture_order + 100000] = E->key(); } else { @@ -2027,6 +2038,23 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_ } } +void RasterizerCanvasRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { + + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RasterizerStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E->get()); + p.info.name = E->key(); //supply name + p.index = E->get().instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p_param_list->push_back(p); + } +} + bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; @@ -2366,6 +2394,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.default_repeat = ShaderLanguage::REPEAT_DISABLE; actions.base_varying_index = 4; + actions.global_buffer_array_variable = "global_variables.data"; + shader.compiler.initialize(actions); } @@ -2393,8 +2423,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { } //pipelines - Vector<RD::VertexDescription> vf; - RD::VertexDescription vd; + Vector<RD::VertexAttribute> vf; + RD::VertexAttribute vd; vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; vd.location = 0; vd.offset = 0; diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h index 83b431eaf6..4d47b3e13b 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h @@ -185,6 +185,8 @@ class RasterizerCanvasRD : public RasterizerCanvas { virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index 9ccc1f172e..d469dd97ca 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -50,6 +50,16 @@ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_ar p_array[11] = 0; } +static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + + p_array[i * 4 + j] = p_mtx.matrix[i][j]; + } + } +} + RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) { if (image_to_uniform_set_cache.has(p_image)) { @@ -89,7 +99,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use u.ids.push_back(p_texture); uniforms.push_back(u); //any thing with the same configuration (one texture in binding 0 for set 0), is good - RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, blur.shader.version_get_shader(blur.shader_version, 0), 0); + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0); texture_to_uniform_set_cache[p_texture] = uniform_set; @@ -120,167 +130,549 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bo return uniform_set; } -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) { +RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { + + TexturePair tp; + tp.texture1 = p_texture1; + tp.texture2 = p_texture2; + + if (texture_pair_to_compute_uniform_set_cache.has(tp)) { + RID uniform_set = texture_pair_to_compute_uniform_set_cache[tp]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); + u.ids.push_back(p_texture1); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 1; + u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); + u.ids.push_back(p_texture2); + uniforms.push_back(u); + } + //any thing with the same configuration (one texture in binding 0 for set 0), is good + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), 1); + + texture_pair_to_compute_uniform_set_cache[tp] = uniform_set; + + return uniform_set; +} + +RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_texture2) { + + TexturePair tp; + tp.texture1 = p_texture1; + tp.texture2 = p_texture2; + + if (image_pair_to_compute_uniform_set_cache.has(tp)) { + RID uniform_set = image_pair_to_compute_uniform_set_cache[tp]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_texture1); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_texture2); + uniforms.push_back(u); + } + //any thing with the same configuration (one texture in binding 0 for set 0), is good + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), 3); + + image_pair_to_compute_uniform_set_cache[tp] = uniform_set; + + return uniform_set; +} + +void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { + + zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); + + copy_to_fb.push_constant.use_section = true; + copy_to_fb.push_constant.section[0] = p_uv_rect.position.x; + copy_to_fb.push_constant.section[1] = p_uv_rect.position.y; + copy_to_fb.push_constant.section[2] = p_uv_rect.size.x; + copy_to_fb.push_constant.section[3] = p_uv_rect.size.y; + + if (p_flip_y) { + copy_to_fb.push_constant.flip_y = true; + } + + RD::DrawListID draw_list = p_draw_list; + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[p_panorama ? COPY_TO_FB_COPY_PANORAMA_TO_DP : COPY_TO_FB_COPY].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, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); +} + +void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero) { + zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); if (p_flip_y) { - blur.push_constant.flags |= BLUR_FLAG_FLIP_Y; + copy_to_fb.push_constant.flip_y = true; } if (p_force_luminance) { - blur.push_constant.flags |= BLUR_COPY_FORCE_LUMINANCE; + copy_to_fb.push_constant.force_luminance = true; + } + if (p_alpha_to_zero) { + copy_to_fb.push_constant.alpha_to_zero = true; } 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_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[COPY_TO_FB_COPY].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_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, true); RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) { +void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst) { - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + zeromem(©.push_constant, sizeof(CopyPushConstant)); + if (p_flip_y) { + copy.push_constant.flags |= COPY_FLAG_FLIP_Y; + } - if (p_region != Rect2()) { - blur.push_constant.flags = BLUR_FLAG_USE_BLUR_SECTION; - blur.push_constant.section[0] = p_region.position.x; - blur.push_constant.section[1] = p_region.position.y; - blur.push_constant.section[2] = p_region.size.width; - blur.push_constant.section[3] = p_region.size.height; + if (p_force_luminance) { + copy.push_constant.flags |= COPY_FLAG_FORCE_LUMINANCE; } - 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); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].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(); + if (p_all_source) { + copy.push_constant.flags |= COPY_FLAG_ALL_SOURCE; + } + + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_rect.size.width; + copy.push_constant.section[3] = p_rect.size.height; + copy.push_constant.target[0] = p_rect.position.x; + copy.push_constant.target[1] = p_rect.position.y; + + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8_bit_dst ? COPY_MODE_SIMPLY_COPY_8BIT : COPY_MODE_SIMPLY_COPY]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::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 RasterizerEffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + zeromem(©.push_constant, sizeof(CopyPushConstant)); + if (p_flip_y) { + copy.push_constant.flags |= COPY_FLAG_FLIP_Y; + } - uint32_t base_flags = 0; - if (p_region != Rect2()) { - base_flags = BLUR_FLAG_USE_BLUR_SECTION; - blur.push_constant.section[0] = p_region.position.x; - blur.push_constant.section[1] = p_region.position.y; - blur.push_constant.section[2] = p_region.size.width; - blur.push_constant.section[3] = p_region.size.height; + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_rect.size.width; + copy.push_constant.section[3] = p_rect.size.height; + copy.push_constant.target[0] = p_rect.position.x; + copy.push_constant.target[1] = p_rect.position.y; + copy.push_constant.camera_z_far = p_z_far; + copy.push_constant.camera_z_near = p_z_near; + + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_LINEARIZE_DEPTH]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); +} + +void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { + + zeromem(©.push_constant, sizeof(CopyPushConstant)); + if (p_flip_y) { + copy.push_constant.flags |= COPY_FLAG_FLIP_Y; } - blur.push_constant.pixel_size[0] = p_pixel_size.x; - blur.push_constant.pixel_size[1] = p_pixel_size.y; + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_rect.size.width; + copy.push_constant.section[3] = p_rect.size.height; + copy.push_constant.target[0] = p_rect.position.x; + copy.push_constant.target[1] = p_rect.position.y; + + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_SIMPLY_COPY_DEPTH]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); +} + +void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { + + zeromem(©.push_constant, sizeof(CopyPushConstant)); + uint32_t base_flags = 0; + copy.push_constant.section[0] = p_region.position.x; + copy.push_constant.section[1] = p_region.position.y; + copy.push_constant.section[2] = p_region.size.width; + copy.push_constant.section[3] = p_region.size.height; + + int32_t x_groups = (p_region.size.width - 1) / 8 + 1; + int32_t y_groups = (p_region.size.height - 1) / 8 + 1; //HORIZONTAL - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half))); - 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::DrawListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 0); - blur.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL; + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + + RD::get_singleton()->compute_list_add_barrier(compute_list); //VERTICAL - 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); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].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_rd_texture_half), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 0); - blur.push_constant.flags = base_flags; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags; + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::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, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + zeromem(©.push_constant, sizeof(CopyPushConstant)); - BlurMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW; + CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW; uint32_t base_flags = 0; - blur.push_constant.pixel_size[0] = p_pixel_size.x; - blur.push_constant.pixel_size[1] = p_pixel_size.y; + int32_t x_groups = (p_size.width - 1) / 8 + 1; + int32_t y_groups = (p_size.height - 1) / 8 + 1; + + copy.push_constant.section[2] = p_size.x; + copy.push_constant.section[3] = p_size.y; + + copy.push_constant.glow_strength = p_strength; + copy.push_constant.glow_bloom = p_bloom; + copy.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold; + copy.push_constant.glow_hdr_scale = p_hdr_bleed_scale; + copy.push_constant.glow_exposure = p_exposure; + copy.push_constant.glow_white = 0; //actually unused + copy.push_constant.glow_luminance_cap = p_luminance_cap; - blur.push_constant.glow_strength = p_strength; - blur.push_constant.glow_bloom = p_bloom; - blur.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold; - blur.push_constant.glow_hdr_scale = p_hdr_bleed_scale; - blur.push_constant.glow_exposure = p_exposure; - blur.push_constant.glow_white = 0; //actually unused - blur.push_constant.glow_luminance_cap = p_luminance_cap; - blur.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also + copy.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also //HORIZONTAL - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3); if (p_auto_exposure.is_valid() && p_first_pass) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_auto_exposure), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_auto_exposure), 1); } - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - blur.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL | (p_first_pass ? BLUR_FLAG_GLOW_FIRST_PASS : 0); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); - blur_mode = BLUR_MODE_GAUSSIAN_GLOW; + copy_mode = COPY_MODE_GAUSSIAN_GLOW; //VERTICAL - 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); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[blur_mode].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_rd_texture_half), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3); - blur.push_constant.flags = base_flags; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags; + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_framebuffer, const Vector2 &p_pixel_size) { +void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal, RenderingServer::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) { + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + int32_t x_groups = (p_screen_size.width - 1) / 8 + 1; + int32_t y_groups = (p_screen_size.height - 1) / 8 + 1; - blur.push_constant.pixel_size[0] = p_pixel_size.x; - blur.push_constant.pixel_size[1] = p_pixel_size.y; + { //scale color and depth to half + ssr_scale.push_constant.camera_z_far = p_camera.get_z_far(); + ssr_scale.push_constant.camera_z_near = p_camera.get_z_near(); + ssr_scale.push_constant.orthogonal = p_camera.is_orthogonal(); + ssr_scale.push_constant.filter = false; //enabling causes arctifacts + ssr_scale.push_constant.screen_size[0] = p_screen_size.x; + ssr_scale.push_constant.screen_size[1] = p_screen_size.y; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_scale.pipeline); + + 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_compute_uniform_set_from_texture_pair(p_depth, p_normal), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output_blur), 2); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_scale_depth, p_scale_normal), 3); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_scale.push_constant, sizeof(ScreenSpaceReflectionScalePushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + + { + + ssr.push_constant.camera_z_far = p_camera.get_z_far(); + ssr.push_constant.camera_z_near = p_camera.get_z_near(); + ssr.push_constant.orthogonal = p_camera.is_orthogonal(); + ssr.push_constant.screen_size[0] = p_screen_size.x; + ssr.push_constant.screen_size[1] = p_screen_size.y; + ssr.push_constant.curve_fade_in = p_fade_in; + ssr.push_constant.distance_fade = p_fade_out; + ssr.push_constant.num_steps = p_max_steps; + ssr.push_constant.depth_tolerance = p_tolerance; + ssr.push_constant.use_half_res = true; + ssr.push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_camera.matrix[0][0]); + ssr.push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_camera.matrix[1][1]); + ssr.push_constant.proj_info[2] = (1.0f - p_camera.matrix[0][2]) / p_camera.matrix[0][0]; + ssr.push_constant.proj_info[3] = (1.0f + p_camera.matrix[1][2]) / p_camera.matrix[1][1]; + ssr.push_constant.metallic_mask[0] = CLAMP(p_metallic_mask.r * 255.0, 0, 255); + ssr.push_constant.metallic_mask[1] = CLAMP(p_metallic_mask.g * 255.0, 0, 255); + ssr.push_constant.metallic_mask[2] = CLAMP(p_metallic_mask.b * 255.0, 0, 255); + ssr.push_constant.metallic_mask[3] = CLAMP(p_metallic_mask.a * 255.0, 0, 255); + store_camera(p_camera, ssr.push_constant.projection); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[(p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL]); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr.push_constant, sizeof(ScreenSpaceReflectionPushConstant)); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_scale_depth), 0); + + if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_metallic, p_roughness), 3); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_metallic), 3); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 2); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + } + + if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) { + + //blurr + + RD::get_singleton()->compute_list_add_barrier(compute_list); + + ssr_filter.push_constant.orthogonal = p_camera.is_orthogonal(); + ssr_filter.push_constant.edge_tolerance = Math::sin(Math::deg2rad(15.0)); + ssr_filter.push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_camera.matrix[0][0]); + ssr_filter.push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_camera.matrix[1][1]); + ssr_filter.push_constant.proj_info[2] = (1.0f - p_camera.matrix[0][2]) / p_camera.matrix[0][0]; + ssr_filter.push_constant.proj_info[3] = (1.0f + p_camera.matrix[1][2]) / p_camera.matrix[1][1]; + ssr_filter.push_constant.vertical = 0; + if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_LOW) { + ssr_filter.push_constant.steps = p_max_steps / 3; + ssr_filter.push_constant.increment = 3; + } else if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_MEDIUM) { + ssr_filter.push_constant.steps = p_max_steps / 2; + ssr_filter.push_constant.increment = 2; + } else { + ssr_filter.push_constant.steps = p_max_steps; + ssr_filter.push_constant.increment = 1; + } + + ssr_filter.push_constant.screen_size[0] = p_screen_size.width; + ssr_filter.push_constant.screen_size[1] = p_screen_size.height; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_blur_radius2), 2); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_depth), 3); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_filter.push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant)); + + 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_compute_pipeline(compute_list, ssr_filter.pipelines[SCREEN_SPACE_REFLECTION_FILTER_VERTICAL]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_blur_radius2), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 2); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_depth), 3); + + ssr_filter.push_constant.vertical = 1; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_filter.push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + } + + 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>()); + + if (p_reflection.is_valid()) { + + if (p_base.is_valid()) { + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_SSR].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_base), 2); + } else { + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_ADDITIVE_SSR].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_specular), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_reflection), 1); + + } else { + + if (p_base.is_valid()) { + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_ADD].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_base), 2); + } else { + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_ADDITIVE_ADD].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_specular), 0); + } - 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); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_MIPMAP].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_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) { +void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { + + zeromem(©.push_constant, sizeof(CopyPushConstant)); + + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_size.width; + copy.push_constant.section[3] = p_size.height; + + int32_t x_groups = (p_size.width - 1) / 8 + 1; + int32_t y_groups = (p_size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_MIPMAP]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); +} + +void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) { CopyToDPPushConstant push_constant; + push_constant.screen_size[0] = p_rect.size.x; + push_constant.screen_size[1] = p_rect.size.y; + push_constant.dest_offset[0] = p_rect.position.x; + push_constant.dest_offset[1] = p_rect.position.y; push_constant.bias = p_bias; push_constant.z_far = p_z_far; push_constant.z_near = p_z_near; push_constant.z_flip = p_dp_flip; - 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, copy.pipelines[COPY_MODE_CUBE_TO_DP].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, &push_constant, sizeof(CopyToDPPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cube_to_dp.pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(CopyToDPPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { @@ -309,7 +701,11 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, tonemap.push_constant.use_color_correction = p_settings.use_color_correction; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + tonemap.push_constant.use_fxaa = p_settings.use_fxaa; + tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; + tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); @@ -819,31 +1215,39 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_ RasterizerEffectsRD::RasterizerEffectsRD() { + { // Initialize copy + Vector<String> copy_modes; + copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define DST_IMAGE_8BIT\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); + copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n"); + copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n#define DST_IMAGE_8BIT\n"); + copy_modes.push_back("\n#define MODE_SIMPLE_COPY_DEPTH\n"); + copy_modes.push_back("\n#define MODE_MIPMAP\n"); + copy_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n"); + + copy.shader.initialize(copy_modes); + zeromem(©.push_constant, sizeof(CopyPushConstant)); + copy.shader_version = copy.shader.version_create(); + + for (int i = 0; i < COPY_MODE_MAX; i++) { + copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i)); + } + } { - // 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"); - blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n#define DOF_NEAR_BLUR_MERGE\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n#define DOF_NEAR_BLUR_MERGE\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n#define DOF_NEAR_BLUR_MERGE\n"); - blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_LOW\n"); - blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_MEDIUM\n"); - blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_HIGH\n"); - 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.shader.initialize(blur_modes); - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); - blur.shader_version = blur.shader.version_create(); - - for (int i = 0; i < BLUR_MODE_MAX; i++) { - blur.pipelines[i].setup(blur.shader.version_get_shader(blur.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + Vector<String> copy_modes; + copy_modes.push_back("\n"); + copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n"); + + copy_to_fb.shader.initialize(copy_modes); + + copy_to_fb.shader_version = copy_to_fb.shader.version_create(); + + //use additive + + for (int i = 0; i < COPY_TO_FB_MAX; i++) { + copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); } } @@ -892,15 +1296,13 @@ RasterizerEffectsRD::RasterizerEffectsRD() { { // Initialize copier Vector<String> copy_modes; - copy_modes.push_back("\n#define MODE_CUBE_TO_DP\n"); + copy_modes.push_back("\n"); - copy.shader.initialize(copy_modes); + cube_to_dp.shader.initialize(copy_modes); - copy.shader_version = copy.shader.version_create(); + cube_to_dp.shader_version = cube_to_dp.shader.version_create(); - for (int i = 0; i < COPY_MODE_MAX; i++) { - copy.pipelines[i].setup(copy.shader.version_get_shader(copy.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); - } + cube_to_dp.pipeline = RD::get_singleton()->compute_pipeline_create(cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0)); } { @@ -970,6 +1372,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() { for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_UPSCALE; i++) { ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); + pipeline++; } } @@ -1035,6 +1438,97 @@ RasterizerEffectsRD::RasterizerEffectsRD() { filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); } + { + Vector<String> specular_modes; + specular_modes.push_back("\n#define MODE_MERGE\n"); + specular_modes.push_back("\n#define MODE_MERGE\n#define MODE_SSR\n"); + specular_modes.push_back("\n"); + specular_modes.push_back("\n#define MODE_SSR\n"); + + specular_merge.shader.initialize(specular_modes); + + specular_merge.shader_version = specular_merge.shader.version_create(); + + //use additive + + RD::PipelineColorBlendState::Attachment ba; + ba.enable_blend = true; + ba.src_color_blend_factor = RD::BLEND_FACTOR_ONE; + ba.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + ba.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + ba.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + ba.color_blend_op = RD::BLEND_OP_ADD; + ba.alpha_blend_op = RD::BLEND_OP_ADD; + + RD::PipelineColorBlendState blend_additive; + blend_additive.attachments.push_back(ba); + + for (int i = 0; i < SPECULAR_MERGE_MAX; i++) { + + RD::PipelineColorBlendState blend_state; + if (i == SPECULAR_MERGE_ADDITIVE_ADD || i == SPECULAR_MERGE_ADDITIVE_SSR) { + blend_state = blend_additive; + } else { + blend_state = RD::PipelineColorBlendState::create_disabled(); + } + specular_merge.pipelines[i].setup(specular_merge.shader.version_get_shader(specular_merge.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); + } + } + + { + Vector<String> ssr_modes; + ssr_modes.push_back("\n"); + ssr_modes.push_back("\n#define MODE_ROUGH\n"); + + ssr.shader.initialize(ssr_modes); + + ssr.shader_version = ssr.shader.version_create(); + + for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) { + ssr.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i)); + } + } + + { + Vector<String> ssr_filter_modes; + ssr_filter_modes.push_back("\n"); + ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n"); + + ssr_filter.shader.initialize(ssr_filter_modes); + + ssr_filter.shader_version = ssr_filter.shader.version_create(); + + for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) { + ssr_filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i)); + } + } + + { + Vector<String> ssr_scale_modes; + ssr_scale_modes.push_back("\n"); + + ssr_scale.shader.initialize(ssr_scale_modes); + + ssr_scale.shader_version = ssr_scale.shader.version_create(); + + 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; @@ -1079,16 +1573,23 @@ 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); + copy_to_fb.shader.version_free(copy_to_fb.shader_version); + cube_to_dp.shader.version_free(cube_to_dp.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 69da5dc6d4..531591442b 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -33,87 +33,110 @@ #include "core/math/camera_matrix.h" #include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/blur.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/copy.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao_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" class RasterizerEffectsRD { - enum BlurMode { - BLUR_MODE_GAUSSIAN_BLUR, - BLUR_MODE_GAUSSIAN_GLOW, - BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, - BLUR_MODE_DOF_NEAR_LOW, - BLUR_MODE_DOF_NEAR_MEDIUM, - BLUR_MODE_DOF_NEAR_HIGH, - BLUR_MODE_DOF_NEAR_MERGE_LOW, - BLUR_MODE_DOF_NEAR_MERGE_MEDIUM, - BLUR_MODE_DOF_NEAR_MERGE_HIGH, - BLUR_MODE_DOF_FAR_LOW, - BLUR_MODE_DOF_FAR_MEDIUM, - BLUR_MODE_DOF_FAR_HIGH, - BLUR_MODE_SSAO_MERGE, - BLUR_MODE_SIMPLY_COPY, - BLUR_MODE_MIPMAP, - BLUR_MODE_MAX, + enum CopyMode { + COPY_MODE_GAUSSIAN_COPY, + COPY_MODE_GAUSSIAN_COPY_8BIT, + COPY_MODE_GAUSSIAN_GLOW, + COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, + COPY_MODE_SIMPLY_COPY, + COPY_MODE_SIMPLY_COPY_8BIT, + COPY_MODE_SIMPLY_COPY_DEPTH, + COPY_MODE_MIPMAP, + COPY_MODE_LINEARIZE_DEPTH, + COPY_MODE_MAX, }; enum { - BLUR_FLAG_HORIZONTAL = (1 << 0), - BLUR_FLAG_USE_BLUR_SECTION = (1 << 1), - BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2), - BLUR_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3), - BLUR_FLAG_GLOW_FIRST_PASS = (1 << 4), - BLUR_FLAG_FLIP_Y = (1 << 5), - BLUR_COPY_FORCE_LUMINANCE = (1 << 6) + COPY_FLAG_HORIZONTAL = (1 << 0), + COPY_FLAG_USE_COPY_SECTION = (1 << 1), + COPY_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2), + COPY_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3), + COPY_FLAG_GLOW_FIRST_PASS = (1 << 4), + COPY_FLAG_FLIP_Y = (1 << 5), + COPY_FLAG_FORCE_LUMINANCE = (1 << 6), + COPY_FLAG_ALL_SOURCE = (1 << 7) }; - struct BlurPushConstant { - float section[4]; - float pixel_size[2]; + struct CopyPushConstant { + + int32_t section[4]; + int32_t target[2]; uint32_t flags; uint32_t pad; - //glow + // Glow. float glow_strength; float glow_bloom; float glow_hdr_threshold; float glow_hdr_scale; + float glow_exposure; float glow_white; float glow_luminance_cap; float glow_auto_exposure_grey; - //dof - float dof_begin; - float dof_end; - float dof_radius; - float dof_pad; - - float dof_dir[2]; + // DOF. float camera_z_far; float camera_z_near; + uint32_t pad2[2]; + }; + + struct Copy { + CopyPushConstant push_constant; + CopyShaderRD shader; + RID shader_version; + RID pipelines[COPY_MODE_MAX]; + + } copy; + + enum CopyToFBMode { + COPY_TO_FB_COPY, + COPY_TO_FB_COPY_PANORAMA_TO_DP, + COPY_TO_FB_MAX, - float ssao_color[4]; }; - struct Blur { - BlurPushConstant push_constant; - BlurShaderRD shader; + struct CopyToFbPushConstant { + + float section[4]; + float pixel_size[2]; + uint32_t flip_y; + uint32_t use_section; + + uint32_t force_luminance; + uint32_t alpha_to_zero; + uint32_t pad[2]; + }; + + struct CopyToFb { + CopyToFbPushConstant push_constant; + CopyToFbShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[BLUR_MODE_MAX]; + RenderPipelineVertexFormatCacheRD pipelines[COPY_TO_FB_MAX]; - } blur; + } copy_to_fb; struct CubemapRoughnessPushConstant { uint32_t face_id; @@ -156,10 +179,17 @@ class RasterizerEffectsRD { float exposure; float white; float auto_exposure_grey; + + float pixel_size[2]; + uint32_t use_fxaa; + uint32_t pad; }; + /* tonemap actually writes to a framebuffer, which is + * better to do using the raster pipeline rather than + * comptute, as that framebuffer might be in different formats + */ struct Tonemap { - TonemapPushConstant push_constant; TonemapShaderRD shader; RID shader_version; @@ -190,23 +220,20 @@ class RasterizerEffectsRD { } luminance_reduce; struct CopyToDPPushConstant { + int32_t screen_size[2]; + int32_t dest_offset[2]; float bias; float z_far; float z_near; uint32_t z_flip; }; - enum CopyMode { - COPY_MODE_CUBE_TO_DP, - COPY_MODE_MAX - }; - - struct Copy { + struct CoptToDP { - CopyShaderRD shader; + CubeToDpShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[COPY_MODE_MAX]; - } copy; + RID pipeline; + } cube_to_dp; struct BokehPushConstant { uint32_t size[2]; @@ -378,6 +405,131 @@ class RasterizerEffectsRD { float pad[3]; }; + enum SpecularMergeMode { + SPECULAR_MERGE_ADD, + SPECULAR_MERGE_SSR, + SPECULAR_MERGE_ADDITIVE_ADD, + SPECULAR_MERGE_ADDITIVE_SSR, + SPECULAR_MERGE_MAX + }; + + /* Specular merge must be done using raster, rather than compute + * because it must continue the existing color buffer + */ + + struct SpecularMerge { + + SpecularMergeShaderRD shader; + RID shader_version; + RenderPipelineVertexFormatCacheRD pipelines[SPECULAR_MERGE_MAX]; + + } specular_merge; + + enum ScreenSpaceReflectionMode { + SCREEN_SPACE_REFLECTION_NORMAL, + SCREEN_SPACE_REFLECTION_ROUGH, + SCREEN_SPACE_REFLECTION_MAX, + }; + + struct ScreenSpaceReflectionPushConstant { + + float proj_info[4]; + + int32_t screen_size[2]; + float camera_z_near; + float camera_z_far; + + int32_t num_steps; + float depth_tolerance; + float distance_fade; + float curve_fade_in; + + uint32_t orthogonal; + float filter_mipmap_levels; + uint32_t use_half_res; + uint8_t metallic_mask[4]; + + float projection[16]; + }; + + struct ScreenSpaceReflection { + + ScreenSpaceReflectionPushConstant push_constant; + ScreenSpaceReflectionShaderRD shader; + RID shader_version; + RID pipelines[SCREEN_SPACE_REFLECTION_MAX]; + + } ssr; + + struct ScreenSpaceReflectionFilterPushConstant { + + float proj_info[4]; + + uint32_t orthogonal; + float edge_tolerance; + int32_t increment; + uint32_t pad; + + int32_t screen_size[2]; + uint32_t vertical; + uint32_t steps; + }; + enum { + SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL, + SCREEN_SPACE_REFLECTION_FILTER_VERTICAL, + SCREEN_SPACE_REFLECTION_FILTER_MAX, + }; + + struct ScreenSpaceReflectionFilter { + + ScreenSpaceReflectionFilterPushConstant push_constant; + ScreenSpaceReflectionFilterShaderRD shader; + RID shader_version; + RID pipelines[SCREEN_SPACE_REFLECTION_FILTER_MAX]; + } ssr_filter; + + struct ScreenSpaceReflectionScalePushConstant { + + int32_t screen_size[2]; + float camera_z_near; + float camera_z_far; + + uint32_t orthogonal; + uint32_t filter; + uint32_t pad[2]; + }; + + struct ScreenSpaceReflectionScale { + + ScreenSpaceReflectionScalePushConstant push_constant; + ScreenSpaceReflectionScaleShaderRD shader; + RID shader_version; + 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; @@ -386,23 +538,41 @@ class RasterizerEffectsRD { Map<RID, RID> texture_to_uniform_set_cache; Map<RID, RID> image_to_uniform_set_cache; + + struct TexturePair { + RID texture1; + RID texture2; + _FORCE_INLINE_ bool operator<(const TexturePair &p_pair) const { + if (texture1 == p_pair.texture1) { + return texture2 < p_pair.texture2; + } else { + return texture1 < p_pair.texture1; + } + } + }; + Map<RID, RID> texture_to_compute_uniform_set_cache; + Map<TexturePair, RID> texture_pair_to_compute_uniform_set_cache; + Map<TexturePair, RID> image_pair_to_compute_uniform_set_cache; RID _get_uniform_set_from_image(RID p_texture); RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); + RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false); + RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2); public: - //TODO must re-do most of the shaders in compute - - 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 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); + void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false); + void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false); + void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); + void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far); + void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false); + void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); + void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_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); void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); - void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size); - void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); + void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); @@ -439,6 +609,9 @@ public: bool use_color_correction = false; RID color_correction_texture; + + bool use_fxaa = false; + Vector2i texture_size; }; void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); @@ -450,6 +623,10 @@ public: void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); + 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_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp index 9c54f0caae..4c92912e9c 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp @@ -30,6 +30,8 @@ #include "rasterizer_rd.h" +#include "core/project_settings.h" + void RasterizerRD::prepare_for_blitting_render_targets() { RD::get_singleton()->prepare_screen_for_drawing(); } @@ -78,6 +80,10 @@ void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_scree void RasterizerRD::begin_frame(double frame_step) { frame++; time += frame_step; + + double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs"); + time = Math::fmod(time, time_roll_over); + canvas->set_time(time); scene->set_time(time, frame_step); } 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 10d83b0c26..6986f82065 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -52,6 +52,21 @@ static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_arra p_array[15] = 1; } +static _FORCE_INLINE_ void store_basis_3x4(const Basis &p_mtx, float *p_array) { + p_array[0] = p_mtx.elements[0][0]; + p_array[1] = p_mtx.elements[1][0]; + p_array[2] = p_mtx.elements[2][0]; + p_array[3] = 0; + p_array[4] = p_mtx.elements[0][1]; + p_array[5] = p_mtx.elements[1][1]; + p_array[6] = p_mtx.elements[2][1]; + p_array[7] = 0; + p_array[8] = p_mtx.elements[0][2]; + p_array[9] = p_mtx.elements[1][2]; + p_array[10] = p_mtx.elements[2][2]; + p_array[11] = 0; +} + static _FORCE_INLINE_ void store_transform_3x3(const Transform &p_mtx, float *p_array) { p_array[0] = p_mtx.basis.elements[0][0]; p_array[1] = p_mtx.basis.elements[1][0]; @@ -77,6 +92,13 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_arra } } +static _FORCE_INLINE_ void store_soft_shadow_kernel(const float *p_kernel, float *p_array) { + + for (int i = 0; i < 128; i++) { + p_array[i] = p_kernel[i]; + } +} + /* SCENE SHADER */ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { //compile @@ -109,6 +131,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 +165,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; @@ -321,7 +345,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL) { blend_state = blend_state_depth_normal; } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { - blend_state = blend_state_depth_normal; + blend_state = blend_state_depth_normal_roughness; } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way @@ -354,6 +378,10 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + continue; + } + if (E->get().texture_order >= 0) { order[E->get().texture_order + 100000] = E->key(); } else { @@ -369,6 +397,23 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_ } } +void RasterizerSceneHighEndRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { + + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RasterizerStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E->get()); + p.info.name = E->key(); //supply name + p.index = E->get().instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p_param_list->push_back(p); + } +} + bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; @@ -533,37 +578,100 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() { tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = width; tf.height = height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + if (msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } specular = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb; - fb.push_back(color); - fb.push_back(specular); - fb.push_back(depth); + if (msaa == RS::VIEWPORT_MSAA_DISABLED) { + + { + Vector<RID> fb; + fb.push_back(color); + fb.push_back(specular); + fb.push_back(depth); + + color_specular_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(specular); + + specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + } + + } else { + + tf.samples = texture_samples; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + specular_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector<RID> fb; + fb.push_back(color_msaa); + fb.push_back(specular_msaa); + fb.push_back(depth_msaa); + + color_specular_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(specular_msaa); - color_specular_fb = RD::get_singleton()->framebuffer_create(fb); + specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + } + } } } void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { + if (color_msaa.is_valid()) { + RD::get_singleton()->free(color_msaa); + color_msaa = RID(); + } + + if (depth_msaa.is_valid()) { + RD::get_singleton()->free(depth_msaa); + depth_msaa = RID(); + } + if (specular.is_valid()) { + if (specular_msaa.is_valid()) { + RD::get_singleton()->free(specular_msaa); + specular_msaa = RID(); + } RD::get_singleton()->free(specular); specular = RID(); } + color = RID(); + depth = RID(); color_specular_fb = RID(); + specular_only_fb = RID(); color_fb = RID(); + depth_fb = RID(); if (normal_buffer.is_valid()) { RD::get_singleton()->free(normal_buffer); + if (normal_buffer_msaa.is_valid()) { + RD::get_singleton()->free(normal_buffer_msaa); + normal_buffer_msaa = RID(); + } normal_buffer = RID(); depth_normal_fb = RID(); } if (roughness_buffer.is_valid()) { RD::get_singleton()->free(roughness_buffer); + if (roughness_buffer_msaa.is_valid()) { + RD::get_singleton()->free(roughness_buffer_msaa); + roughness_buffer_msaa = RID(); + } roughness_buffer = RID(); depth_normal_roughness_fb = RID(); } @@ -572,24 +680,69 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { clear(); + msaa = p_msaa; + width = p_width; height = p_height; color = p_color_buffer; depth = p_depth_buffer; - { - Vector<RID> fb; - fb.push_back(p_color_buffer); - fb.push_back(depth); + if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { - color_fb = RD::get_singleton()->framebuffer_create(fb); - } - { - Vector<RID> fb; - fb.push_back(depth); + { + Vector<RID> fb; + fb.push_back(p_color_buffer); + fb.push_back(depth); - depth_fb = RD::get_singleton()->framebuffer_create(fb); + color_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(depth); + + depth_fb = RD::get_singleton()->framebuffer_create(fb); + } + } else { + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = p_width; + tf.height = p_height; + tf.type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + + RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { + RD::TEXTURE_SAMPLES_1, + RD::TEXTURE_SAMPLES_2, + RD::TEXTURE_SAMPLES_4, + RD::TEXTURE_SAMPLES_8, + RD::TEXTURE_SAMPLES_16 + }; + + texture_samples = ts[p_msaa]; + tf.samples = texture_samples; + + color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + + depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector<RID> fb; + fb.push_back(color_msaa); + fb.push_back(depth_msaa); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(depth_msaa); + + depth_fb = RD::get_singleton()->framebuffer_create(fb); + } } } @@ -602,13 +755,31 @@ void RasterizerSceneHighEndRD::_allocate_normal_texture(RenderBufferDataHighEnd tf.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; tf.width = rb->width; tf.height = rb->height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } rb->normal_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb; - fb.push_back(rb->depth); - fb.push_back(rb->normal_buffer); - rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb); + + if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { + Vector<RID> fb; + fb.push_back(rb->depth); + fb.push_back(rb->normal_buffer); + rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb); + } else { + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + tf.samples = rb->texture_samples; + rb->normal_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector<RID> fb; + fb.push_back(rb->depth_msaa); + fb.push_back(rb->normal_buffer_msaa); + rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb); + } _render_buffers_clear_uniform_set(rb); } @@ -627,12 +798,32 @@ void RasterizerSceneHighEndRD::_allocate_roughness_texture(RenderBufferDataHighE tf.height = rb->height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } + rb->roughness_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb; - fb.push_back(rb->depth); - fb.push_back(rb->normal_buffer); - fb.push_back(rb->roughness_buffer); - rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + + if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { + + Vector<RID> fb; + fb.push_back(rb->depth); + fb.push_back(rb->normal_buffer); + fb.push_back(rb->roughness_buffer); + rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + } else { + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + tf.samples = rb->texture_samples; + rb->roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector<RID> fb; + fb.push_back(rb->depth_msaa); + fb.push_back(rb->normal_buffer_msaa); + fb.push_back(rb->roughness_buffer_msaa); + rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + } _render_buffers_clear_uniform_set(rb); } @@ -658,6 +849,7 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements, store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform); id.flags = 0; id.mask = e->instance->layer_mask; + id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0; if (e->instance->base_type == RS::INSTANCE_MULTIMESH) { id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; @@ -935,7 +1127,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 @@ -952,6 +1144,18 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer scene_state.ubo.z_far = p_zfar; scene_state.ubo.z_near = p_znear; + scene_state.ubo.pancake_shadows = p_pancake_shadows; + + store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); + store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); + store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); + store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); + + scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get(); + scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get(); + scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get(); + scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get(); + scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x; scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y; @@ -982,7 +1186,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer } else if (is_environment(p_environment)) { RS::EnvironmentBG env_bg = environment_get_background(p_environment); - RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_light_ambient_source(p_environment); + RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_environment); float bg_energy = environment_get_bg_energy(p_environment); scene_state.ubo.ambient_light_color_energy[3] = bg_energy; @@ -1002,7 +1206,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer scene_state.ubo.use_ambient_cubemap = false; } else { - float energy = environment_get_ambient_light_ambient_energy(p_environment); + float energy = environment_get_ambient_light_energy(p_environment); Color color = environment_get_ambient_light_color(p_environment); color = color.to_linear(); scene_state.ubo.ambient_light_color_energy[0] = color.r * energy; @@ -1344,7 +1548,7 @@ void RasterizerSceneHighEndRD::_setup_reflections(RID *p_reflection_probe_cull_r Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear(); if (is_environment(p_environment)) { Color env_ambient_color = environment_get_ambient_light_color(p_environment).to_linear(); - float env_ambient_energy = environment_get_ambient_light_ambient_energy(p_environment); + float env_ambient_energy = environment_get_ambient_light_energy(p_environment); ambient_linear = env_ambient_color; ambient_linear.r *= env_ambient_energy; ambient_linear.g *= env_ambient_energy; @@ -1470,14 +1674,62 @@ 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); + float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + if (angular_diameter > 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) + angular_diameter = Math::tan(Math::deg2rad(angular_diameter)); + } else { + angular_diameter = 0.0; + } + if (light_data.shadow_enabled) { RS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base); @@ -1498,12 +1750,46 @@ 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]; + + light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); + light_data.softshadow_angle = angular_diameter; + + if (angular_diameter <= 0.0) { + light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF + } } // Copy to SkyDirectionalLightData @@ -1524,6 +1810,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig sky_light_data.color[2] = light_data.color[2]; sky_light_data.enabled = true; + sky_light_data.size = angular_diameter; sky_scene_state.directional_light_count++; } @@ -1566,51 +1853,114 @@ 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; light_data.atlas_rect[3] = 0; + RID projector = storage->light_get_projector(base); + + if (projector.is_valid()) { + Rect2 rect = storage->decal_atlas_get_texture_rect(projector); + + if (type == RS::LIGHT_SPOT) { + + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = -rect.size.height; + } else { + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y; + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half + } + } else { + light_data.projector_rect[0] = 0; + light_data.projector_rect[1] = 0; + light_data.projector_rect[2] = 0; + light_data.projector_rect[3] = 0; + } + 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.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); - 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; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF + } + } else if (type == RS::LIGHT_SPOT) { Transform modelview = (p_camera_inverse_transform * light_transform).inverse(); CameraMatrix bias; bias.set_light_bias(); - CameraMatrix rectm; - rectm.set_light_atlas_rect(rect); - CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview; + CameraMatrix shadow_mtx = 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; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF + } } + } else { + light_data.shadow_color_enabled[3] = 0; } light_instance_set_index(li, light_count); @@ -1635,7 +1985,140 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig } } -void RasterizerSceneHighEndRD::_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) { +void RasterizerSceneHighEndRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) { + + Transform uv_xform; + uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0)); + uv_xform.origin = Vector3(-1.0, 0.0, -1.0); + + p_decal_count = MIN((uint32_t)p_decal_count, scene_state.max_decals); + int idx = 0; + for (int i = 0; i < p_decal_count; i++) { + + RID di = p_decal_instances[i]; + RID decal = decal_instance_get_base(di); + + Transform xform = decal_instance_get_transform(di); + + float fade = 1.0; + + if (storage->decal_is_distance_fade_enabled(decal)) { + real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + float fade_begin = storage->decal_get_distance_fade_begin(decal); + float fade_length = storage->decal_get_distance_fade_length(decal); + + if (distance > fade_begin) { + if (distance > fade_begin + fade_length) { + continue; // do not use this decal, its invisible + } + + fade = 1.0 - (distance - fade_begin) / fade_length; + } + } + + DecalData &dd = scene_state.decals[idx]; + + Vector3 decal_extents = storage->decal_get_extents(decal); + + Transform scale_xform; + scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z)); + Transform to_decal_xform = (p_camera_inverse_xform * decal_instance_get_transform(di) * scale_xform * uv_xform).affine_inverse(); + store_transform(to_decal_xform, dd.xform); + + Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized(); + normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine + + dd.normal[0] = normal.x; + dd.normal[1] = normal.y; + dd.normal[2] = normal.z; + dd.normal_fade = storage->decal_get_normal_fade(decal); + + RID albedo_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ALBEDO); + RID emission_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_EMISSION); + if (albedo_tex.is_valid()) { + Rect2 rect = storage->decal_atlas_get_texture_rect(albedo_tex); + dd.albedo_rect[0] = rect.position.x; + dd.albedo_rect[1] = rect.position.y; + dd.albedo_rect[2] = rect.size.x; + dd.albedo_rect[3] = rect.size.y; + } else { + + if (!emission_tex.is_valid()) { + continue; //no albedo, no emission, no decal. + } + dd.albedo_rect[0] = 0; + dd.albedo_rect[1] = 0; + dd.albedo_rect[2] = 0; + dd.albedo_rect[3] = 0; + } + + RID normal_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_NORMAL); + + if (normal_tex.is_valid()) { + Rect2 rect = storage->decal_atlas_get_texture_rect(normal_tex); + dd.normal_rect[0] = rect.position.x; + dd.normal_rect[1] = rect.position.y; + dd.normal_rect[2] = rect.size.x; + dd.normal_rect[3] = rect.size.y; + + Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized(); + store_basis_3x4(normal_xform, dd.normal_xform); + } else { + dd.normal_rect[0] = 0; + dd.normal_rect[1] = 0; + dd.normal_rect[2] = 0; + dd.normal_rect[3] = 0; + } + + RID orm_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ORM); + if (orm_tex.is_valid()) { + Rect2 rect = storage->decal_atlas_get_texture_rect(orm_tex); + dd.orm_rect[0] = rect.position.x; + dd.orm_rect[1] = rect.position.y; + dd.orm_rect[2] = rect.size.x; + dd.orm_rect[3] = rect.size.y; + } else { + dd.orm_rect[0] = 0; + dd.orm_rect[1] = 0; + dd.orm_rect[2] = 0; + dd.orm_rect[3] = 0; + } + + if (emission_tex.is_valid()) { + Rect2 rect = storage->decal_atlas_get_texture_rect(emission_tex); + dd.emission_rect[0] = rect.position.x; + dd.emission_rect[1] = rect.position.y; + dd.emission_rect[2] = rect.size.x; + dd.emission_rect[3] = rect.size.y; + } else { + dd.emission_rect[0] = 0; + dd.emission_rect[1] = 0; + dd.emission_rect[2] = 0; + dd.emission_rect[3] = 0; + } + + Color modulate = storage->decal_get_modulate(decal); + dd.modulate[0] = modulate.r; + dd.modulate[1] = modulate.g; + dd.modulate[2] = modulate.b; + dd.modulate[3] = modulate.a * fade; + dd.emission_energy = storage->decal_get_emission_energy(decal) * fade; + dd.albedo_mix = storage->decal_get_albedo_mix(decal); + dd.mask = storage->decal_get_cull_mask(decal); + dd.upper_fade = storage->decal_get_upper_fade(decal); + dd.lower_fade = storage->decal_get_lower_fade(decal); + + cluster_builder.add_decal(xform, decal_extents); + + idx++; + } + + if (idx > 0) { + RD::get_singleton()->buffer_update(scene_state.decal_buffer, 0, sizeof(DecalData) * idx, scene_state.decals, true); + } +} + +void RasterizerSceneHighEndRD::_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_decal_cull_result, int p_decal_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) { RenderBufferDataHighEnd *render_buffer = nullptr; if (p_render_buffer.is_valid()) { @@ -1646,27 +2129,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor render_pass++; //fill up ubo -#if 0 - storage->info.render.object_count += p_cull_count; - - Environment *env = environment_owner.getornull(p_environment); - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); - - if (shadow_atlas && shadow_atlas->size) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); - scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / shadow_atlas->size; - scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / shadow_atlas->size; - } - - if (reflection_atlas && reflection_atlas->size) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); - } -#endif RENDER_TIMESTAMP("Setup 3D Scene"); @@ -1689,9 +2151,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; @@ -1699,13 +2158,17 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor Size2 screen_pixel_size; Size2i screen_size; RID opaque_framebuffer; + RID opaque_specular_framebuffer; RID depth_framebuffer; RID alpha_framebuffer; PassMode depth_pass_mode = PASS_MODE_DEPTH; Vector<Color> depth_pass_clear; + bool using_separate_specular = false; + bool using_ssr = false; if (render_buffer) { + screen_pixel_size.width = 1.0 / render_buffer->width; screen_pixel_size.height = 1.0 / render_buffer->height; screen_size.x = render_buffer->width; @@ -1715,6 +2178,10 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor if (p_environment.is_valid() && environment_is_ssr_enabled(p_environment)) { depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; + render_buffer->ensure_specular(); + using_separate_specular = true; + using_ssr = true; + opaque_specular_framebuffer = render_buffer->color_specular_fb; } else if (screen_space_roughness_limiter_is_active()) { depth_pass_mode = PASS_MODE_DEPTH_NORMAL; //we need to allocate both these, if not allocated @@ -1768,6 +2235,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor cluster_builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows); + _setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse()); _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment); _setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform); _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); @@ -1779,6 +2247,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; @@ -1804,23 +2280,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor clear_color.b *= bg_energy; } break; case RS::ENV_BG_SKY: { - RID sky = environment_get_sky(p_environment); - if (sky.is_valid()) { - - RENDER_TIMESTAMP("Setup Sky"); - CameraMatrix projection = p_cam_projection; - if (p_reflection_probe.is_valid()) { - CameraMatrix correction; - correction.set_depth_correction(true); - projection = correction * p_cam_projection; - } - - _setup_sky(p_environment, p_cam_transform.origin, screen_size); - _update_sky(p_environment, projection, p_cam_transform); - radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET); - - draw_sky = true; - } + draw_sky = true; } break; case RS::ENV_BG_CANVAS: { keep_color = true; @@ -1834,6 +2294,27 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor default: { } } + // setup sky if used for ambient, reflections, or background + if (draw_sky || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + RID sky = environment_get_sky(p_environment); + if (sky.is_valid()) { + + RENDER_TIMESTAMP("Setup Sky"); + CameraMatrix projection = p_cam_projection; + if (p_reflection_probe.is_valid()) { + CameraMatrix correction; + correction.set_depth_correction(true); + projection = correction * p_cam_projection; + } + + _setup_sky(p_environment, p_cam_transform.origin, screen_size); + _update_sky(p_environment, projection, p_cam_transform); + radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET); + } else { + // do not try to draw sky if invalid + draw_sky = false; + } + } } else { clear_color = p_default_bg_color; @@ -1845,22 +2326,36 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor _fill_instances(render_list.elements, render_list.element_count, false); - bool can_continue = true; //unless the middle buffers are needed bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; - bool using_separate_specular = false; bool depth_pre_pass = depth_framebuffer.is_valid(); RID render_buffers_uniform_set; + bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment); + if (depth_pre_pass) { //depth pre pass RENDER_TIMESTAMP("Render Depth Pre-Pass"); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear); + bool finish_depth = using_ssao; + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, radiance_uniform_set, RID()); RD::get_singleton()->draw_list_end(); + + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + if (finish_depth) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + } + + if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->normal_buffer_msaa, render_buffer->normal_buffer, true); + if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->roughness_buffer_msaa, render_buffer->roughness_buffer, true); + } + } + } } - if (p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment)) { + if (using_ssao) { _process_ssao(p_render_buffer, p_environment, render_buffer->normal_buffer, p_cam_projection); } @@ -1878,23 +2373,46 @@ 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 && !using_sss; + bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; + { - bool will_continue = (can_continue || draw_sky || debug_giprobes); + + bool will_continue_color = (can_continue_color || draw_sky || debug_giprobes); + bool will_continue_depth = (can_continue_depth || draw_sky || debug_giprobes); + //regular forward for now Vector<Color> c; - c.push_back(clear_color.to_linear()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set); + 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); RD::get_singleton()->draw_list_end(); + + if (will_continue_color && using_separate_specular) { + // close the specular framebuffer, as it's no longer used + draw_list = RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_end(); + } } if (debug_giprobes) { //debug giprobes - bool will_continue = (can_continue || draw_sky); + bool will_continue_color = (can_continue_color || draw_sky); + bool will_continue_depth = (can_continue_depth || draw_sky); + CameraMatrix dc; dc.set_depth_correction(true); CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); for (int i = 0; i < p_gi_probe_cull_count; i++) { _debug_giprobe(p_gi_probe_cull_result[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); } @@ -1911,101 +2429,60 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor projection = correction * p_cam_projection; } - _draw_sky(can_continue, opaque_framebuffer, p_environment, projection, p_cam_transform); + _draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform); + } + + if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - if (using_separate_specular && !can_continue) { - //can't continue, so close the buffers - //RD::get_singleton()->draw_list_begin(render_buffer->color_specular_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH, c); - //RD::get_singleton()->draw_list_end(); + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); + if (using_separate_specular) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular, true); } } - RENDER_TIMESTAMP("Render Transparent Pass"); - - _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - render_list.sort_by_reverse_depth_and_priority(true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + } - _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false); + if (using_separate_specular) { - { - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set); - RD::get_singleton()->draw_list_end(); - } + if (using_sss) { + RENDER_TIMESTAMP("Sub Surface Scattering"); + _process_sss(p_render_buffer, p_cam_projection); + } - //_render_list -#if 0 - if (state.directional_light_count == 0) { - directional_light = nullptr; - _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, false, shadow_atlas != nullptr); - } else { - for (int i = 0; i < state.directional_light_count; i++) { - directional_light = directional_lights[i]; - _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != nullptr && shadow_atlas->size > 0); - _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, i > 0, shadow_atlas != nullptr); + if (using_ssr) { + RENDER_TIMESTAMP("Screen Space Reflection"); + _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_buffer, render_buffer->roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); + } else { + //just mix specular back + RENDER_TIMESTAMP("Merge Specular"); + storage->get_effects()->merge_specular(render_buffer->color_fb, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID()); } } -#endif -#if 0 - _post_process(env, p_cam_projection); - // Needed only for debugging - /* if (shadow_atlas && storage->frame.current_rt) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - } + RENDER_TIMESTAMP("Render Transparent Pass"); - if (storage->frame.current_rt) { + _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, exposure_shrink[4].color); - //glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->exposure.color); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 16, storage->frame.current_rt->height / 16), Rect2(0, 0, 1, 1)); - } + render_list.sort_by_reverse_depth_and_priority(true); - if (reflection_atlas && storage->frame.current_rt) { + _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false); - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); + { + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set); + RD::get_singleton()->draw_list_end(); } - if (directional_shadow.fbo) { + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); } - - if ( env_radiance_tex) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, env_radiance_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - }*/ - //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"); @@ -2013,11 +2490,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(); @@ -2048,8 +2523,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); @@ -2146,7 +2619,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); } @@ -2209,17 +2682,40 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { uniforms.push_back(u); } - { RD::Uniform u; u.binding = 10; u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(cluster_builder.get_cluster_texture()); + RID decal_atlas = storage->decal_atlas_get_texture(); + u.ids.push_back(decal_atlas); uniforms.push_back(u); } { RD::Uniform u; u.binding = 11; + u.type = RD::UNIFORM_TYPE_TEXTURE; + RID decal_atlas = storage->decal_atlas_get_texture_srgb(); + u.ids.push_back(decal_atlas); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 12; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.decal_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 13; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(cluster_builder.get_cluster_texture()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 14; u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cluster_builder.get_cluster_indices_buffer()); uniforms.push_back(u); @@ -2227,7 +2723,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; - u.binding = 12; + u.binding = 15; u.type = RD::UNIFORM_TYPE_TEXTURE; if (directional_shadow_get_texture().is_valid()) { u.ids.push_back(directional_shadow_get_texture()); @@ -2237,6 +2733,14 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { uniforms.push_back(u); } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 16; + u.ids.push_back(storage->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET); } } @@ -2405,11 +2909,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); @@ -2448,6 +2952,13 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag defines += "\n#define MAX_GI_PROBES " + itos(scene_state.max_gi_probes) + "\n"; } + { //decals + scene_state.max_decals = MIN(1024 * 1024, uniform_max_size) / sizeof(DecalData); //1mb of decals + uint32_t decal_buffer_size = scene_state.max_decals * sizeof(DecalData); + scene_state.decals = memnew_arr(DecalData, scene_state.max_decals); + scene_state.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); + } + Vector<String> shader_versions; shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); @@ -2511,7 +3022,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"; @@ -2551,7 +3066,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"; @@ -2574,6 +3090,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) { @@ -2599,6 +3117,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; + actions.global_buffer_array_variable = "global_variables.data"; + actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs"; shader.compiler.initialize(actions); } @@ -2720,10 +3240,12 @@ RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() { RD::get_singleton()->free(scene_state.directional_light_buffer); RD::get_singleton()->free(scene_state.light_buffer); RD::get_singleton()->free(scene_state.reflection_buffer); + RD::get_singleton()->free(scene_state.decal_buffer); memdelete_arr(scene_state.instances); memdelete_arr(scene_state.gi_probes); memdelete_arr(scene_state.directional_lights); memdelete_arr(scene_state.lights); memdelete_arr(scene_state.reflections); + memdelete_arr(scene_state.decals); } } 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 683a1fc82d..a48e2e2259 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; @@ -151,6 +152,8 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; @@ -197,16 +200,28 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { struct RenderBufferDataHighEnd : public RenderBufferData { //for rendering, may be MSAAd + RID color; RID depth; RID specular; RID normal_buffer; RID roughness_buffer; + + RS::ViewportMSAA msaa; + RD::TextureSamples texture_samples; + + RID color_msaa; + RID depth_msaa; + RID specular_msaa; + RID normal_buffer_msaa; + RID roughness_buffer_msaa; + RID depth_fb; RID depth_normal_fb; RID depth_normal_roughness_fb; RID color_fb; RID color_specular_fb; + RID specular_only_fb; int width, height; void ensure_specular(); @@ -252,13 +267,21 @@ 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; + float soft_shadow_scale; + uint32_t mask; + uint32_t pad[2]; + float projector_rect[4]; }; struct DirectionalLightData { @@ -266,15 +289,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; + float soft_shadow_scale; 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 { @@ -293,6 +331,24 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { uint32_t pad[1]; }; + struct DecalData { + float xform[16]; + float inv_extents[3]; + float albedo_mix; + float albedo_rect[4]; + float normal_rect[4]; + float orm_rect[4]; + float emission_rect[4]; + float modulate[4]; + float emission_energy; + uint32_t mask; + float upper_fade; + float lower_fade; + float normal_xform[12]; + float normal[3]; + float normal_fade; + }; + enum { INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, @@ -307,7 +363,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float transform[16]; float normal_transform[16]; uint32_t flags; - uint32_t instance_ofs; //instance_offset in instancing/skeleton buffer + uint32_t instance_uniforms_ofs; //instance_offset in instancing/skeleton buffer uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap) uint32_t mask; }; @@ -323,12 +379,22 @@ 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 pad; + + float directional_penumbra_shadow_kernel[128]; //32 vec4s + float directional_soft_shadow_kernel[128]; + float penumbra_shadow_kernel[128]; + float soft_shadow_kernel[128]; + + uint32_t directional_penumbra_shadow_samples; + uint32_t directional_soft_shadow_samples; + uint32_t penumbra_shadow_samples; + uint32_t soft_shadow_samples; + float ambient_light_color_energy[4]; float ambient_color_sky_mix; @@ -368,6 +434,10 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { RID gi_probe_buffer; uint32_t max_gi_probe_probes_per_instance; + DecalData *decals; + uint32_t max_decals; + RID decal_buffer; + LightData *lights; uint32_t max_lights; RID light_buffer; @@ -557,8 +627,9 @@ 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_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform); 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); @@ -570,8 +641,8 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi); 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_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_decal_cull_result, int p_decal_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, 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 7a0869e7c1..8877de87ac 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -36,6 +36,18 @@ uint64_t RasterizerSceneRD::auto_exposure_counter = 2; +void get_vogel_disk(float *r_kernel, int p_sample_count) { + const float golden_angle = 2.4; + + for (int i = 0; i < p_sample_count; i++) { + float r = Math::sqrt(float(i) + 0.5) / Math::sqrt(float(p_sample_count)); + float theta = float(i) * golden_angle; + + r_kernel[i * 4] = Math::cos(theta) * r; + r_kernel[i * 4 + 1] = Math::sin(theta) * r; + } +} + void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { rd.layers.clear(); @@ -181,10 +193,9 @@ void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd) { for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) { for (int k = 0; k < 6; k++) { RID view = rd.layers[i].mipmaps[j].views[k]; - RID fb = rd.layers[i].mipmaps[j + 1].framebuffers[k]; - Vector2 size = rd.layers[i].mipmaps[j].size; - size = Vector2(1.0 / size.x, 1.0 / size.y); - storage->get_effects()->make_mipmap(view, fb, size); + RID texture = rd.layers[i].mipmaps[j + 1].views[k]; + Size2i size = rd.layers[i].mipmaps[j + 1].size; + storage->get_effects()->make_mipmap(view, texture, size); } } } @@ -456,7 +467,7 @@ RID RasterizerSceneRD::sky_get_material(RID p_sky) const { return sky->material; } -void RasterizerSceneRD::_draw_sky(bool p_can_continue, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { +void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { ERR_FAIL_COND(!is_environment(p_environment)); @@ -537,7 +548,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue, RID p_fb, RID p_environme RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } @@ -644,7 +655,8 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, const Vector3 &p_position, sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] || sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] || sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] || - sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled) { + sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled || + sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) { light_data_dirty = true; break; } @@ -840,18 +852,22 @@ void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light; actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light; actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light; actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light; actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light; actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light; actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light; actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light; actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light; actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light; actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light; actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light; actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light; actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light; actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light; + actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light; actions.uniforms = &uniforms; @@ -915,6 +931,10 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + if (E->get().texture_order >= 0) { order[E->get().texture_order + 100000] = E->key(); } else { @@ -930,6 +950,23 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para } } +void RasterizerSceneRD::SkyShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { + + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RasterizerStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E->get()); + p.info.name = E->key(); //supply name + p.index = E->get().instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p_param_list->push_back(p); + } +} + bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; @@ -1168,12 +1205,12 @@ Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const { ERR_FAIL_COND_V(!env, Color()); return env->ambient_light; } -RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_light_ambient_source(RID p_env) const { +RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_source(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG); return env->ambient_source; } -float RasterizerSceneRD::environment_get_ambient_light_ambient_energy(RID p_env) const { +float RasterizerSceneRD::environment_get_ambient_light_energy(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->ambient_light_energy; @@ -1231,6 +1268,26 @@ void RasterizerSceneRD::environment_glow_set_use_bicubic_upscale(bool p_enable) glow_bicubic_upscale = p_enable; } +void RasterizerSceneRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { + + Environent *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->ssr_enabled = p_enable; + env->ssr_max_steps = p_max_steps; + env->ssr_fade_in = p_fade_int; + env->ssr_fade_out = p_fade_out; + env->ssr_depth_tolerance = p_depth_tolerance; +} + +void RasterizerSceneRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { + ssr_roughness_quality = p_quality; +} + +RS::EnvironmentSSRRoughnessQuality RasterizerSceneRD::environment_get_ssr_roughness_quality() const { + return ssr_roughness_quality; +} + void RasterizerSceneRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) { Environent *env = environment_owner.getornull(p_env); @@ -1272,7 +1329,7 @@ bool RasterizerSceneRD::environment_is_ssr_enabled(RID p_env) const { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); - return false; + return env->ssr_enabled; } bool RasterizerSceneRD::is_environment(RID p_env) const { @@ -1579,7 +1636,6 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { if (shadow_atlas->depth.is_valid()) { RD::get_singleton()->free(shadow_atlas->depth); shadow_atlas->depth = RID(); - shadow_atlas->fb = RID(); } for (int i = 0; i < 4; i++) { //clear subdivisions @@ -1605,13 +1661,9 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = shadow_atlas->size; tf.height = shadow_atlas->size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - Vector<RID> fb; - fb.push_back(shadow_atlas->depth); - shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb); } } @@ -1881,7 +1933,6 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { if (directional_shadow.depth.is_valid()) { RD::get_singleton()->free(directional_shadow.depth); directional_shadow.depth = RID(); - directional_shadow.fb = RID(); } if (p_size > 0) { @@ -1890,12 +1941,9 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = p_size; tf.height = p_size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb; - fb.push_back(directional_shadow.depth); - directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb); } _base_uniforms_changed(); @@ -2012,7 +2060,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); @@ -2028,6 +2076,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) { @@ -2091,6 +2142,21 @@ RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p return &shadow_maps[p_size]; } + +////////////////////////// + +RID RasterizerSceneRD::decal_instance_create(RID p_decal) { + DecalInstance di; + di.decal = p_decal; + return decal_instance_owner.make_rid(di); +} + +void RasterizerSceneRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) { + DecalInstance *di = decal_instance_owner.getornull(p_decal); + ERR_FAIL_COND(!di); + di->transform = p_transform; +} + ///////////////////////////////// RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) { @@ -3039,7 +3105,7 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { tf.width = rb->width; tf.height = rb->height; tf.type = RD::TEXTURE_TYPE_2D; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -3056,11 +3122,6 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { RenderBuffers::Blur::Mipmap mm; mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[0].texture, 0, i); - { - Vector<RID> fbs; - fbs.push_back(mm.texture); - mm.framebuffer = RD::get_singleton()->framebuffer_create(fbs); - } mm.width = base_width; mm.height = base_height; @@ -3070,11 +3131,6 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { if (i > 0) { mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, 0, i - 1); - { - Vector<RID> fbs; - fbs.push_back(mm.texture); - mm.framebuffer = RD::get_singleton()->framebuffer_create(fbs); - } rb->blur[1].mipmaps.push_back(mm); } @@ -3167,6 +3223,94 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { rb->ssao.ao_full = RID(); rb->ssao.depth_slices.clear(); } + + if (rb->ssr.blur_radius[0].is_valid()) { + RD::get_singleton()->free(rb->ssr.blur_radius[0]); + RD::get_singleton()->free(rb->ssr.blur_radius[1]); + rb->ssr.blur_radius[0] = RID(); + rb->ssr.blur_radius[1] = RID(); + } + + if (rb->ssr.depth_scaled.is_valid()) { + RD::get_singleton()->free(rb->ssr.depth_scaled); + rb->ssr.depth_scaled = RID(); + RD::get_singleton()->free(rb->ssr.normal_scaled); + rb->ssr.normal_scaled = RID(); + } +} + +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); + ERR_FAIL_COND(!rb); + + bool can_use_effects = rb->width >= 8 && rb->height >= 8; + + if (!can_use_effects) { + //just copy + storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, RID()); + return; + } + + Environent *env = environment_owner.getornull(p_environment); + ERR_FAIL_COND(!env); + + ERR_FAIL_COND(!env->ssr_enabled); + + if (rb->ssr.depth_scaled.is_null()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R32_SFLOAT; + tf.width = rb->width / 2; + tf.height = rb->height / 2; + tf.type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + + rb->ssr.depth_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + + rb->ssr.normal_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.width = rb->width / 2; + tf.height = rb->height / 2; + tf.type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + rb->ssr.blur_radius[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->ssr.blur_radius[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + if (rb->blur[0].texture.is_null()) { + _allocate_blur_textures(rb); + _render_buffers_uniform_set_changed(p_render_buffers); + } + + storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, p_roughness_buffer, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection); + storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture); } void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) { @@ -3313,9 +3457,9 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu if (env->auto_exposure && rb->luminance.current.is_valid()) { luminance_texture = rb->luminance.current; } - storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].framebuffer, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].framebuffer, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); } else { - storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].framebuffer, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].framebuffer, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength); + storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength); } } } @@ -3348,6 +3492,12 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.glow_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); } + if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) { + tonemap.use_fxaa = true; + } + + tonemap.texture_size = Vector2i(rb->width, rb->height); + if (env) { tonemap.tonemap_mode = env->tone_mapper; tonemap.white = env->white; @@ -3371,7 +3521,7 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas); Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 2), false, true); + effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true); } } @@ -3380,7 +3530,17 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s RID shadow_atlas_texture = directional_shadow_get_texture(); Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 2), false, true); + effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true); + } + } + + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DECAL_ATLAS) { + RID decal_atlas = storage->decal_atlas_get_texture(); + + if (decal_atlas.is_valid()) { + Size2 rtsize = storage->render_target_get_size(rb->render_target); + + effects->copy_to_fb_rect(decal_atlas, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, false, true); } } @@ -3388,24 +3548,24 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s if (rb->luminance.current.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(rb->luminance.current, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 8), false, true); + effects->copy_to_fb_rect(rb->luminance.current, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 8), false, true); } } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao[0].is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); RID ao_buf = rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; - effects->copy_to_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + effects->copy_to_fb_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER && _render_buffers_get_roughness_texture(p_render_buffers).is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(_render_buffers_get_roughness_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + effects->copy_to_fb_rect(_render_buffers_get_roughness_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize)); + effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false); } } @@ -3426,13 +3586,14 @@ RID RasterizerSceneRD::render_buffers_get_ao_texture(RID p_render_buffers) { return rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; } -void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; rb->height = p_height; rb->render_target = p_render_target; rb->msaa = p_msaa; + rb->screen_space_aa = p_screen_space_aa; _free_render_buffer_data(rb); { @@ -3440,7 +3601,12 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = rb->width; tf.height = rb->height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } @@ -3451,6 +3617,9 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren tf.width = p_width; tf.height = p_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } @@ -3459,6 +3628,101 @@ 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::shadows_quality_set(RS::ShadowQuality p_quality) { + + ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); + + if (shadows_quality != p_quality) { + shadows_quality = p_quality; + + switch (shadows_quality) { + case RS::SHADOW_QUALITY_HARD: { + penumbra_shadow_samples = 4; + soft_shadow_samples = 1; + shadows_quality_radius = 1.0; + } break; + case RS::SHADOW_QUALITY_SOFT_LOW: { + penumbra_shadow_samples = 8; + soft_shadow_samples = 4; + shadows_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_MEDIUM: { + penumbra_shadow_samples = 12; + soft_shadow_samples = 8; + shadows_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_HIGH: { + penumbra_shadow_samples = 24; + soft_shadow_samples = 16; + shadows_quality_radius = 3.0; + } break; + case RS::SHADOW_QUALITY_SOFT_ULTRA: { + penumbra_shadow_samples = 32; + soft_shadow_samples = 32; + shadows_quality_radius = 4.0; + } break; + case RS::SHADOW_QUALITY_MAX: + break; + } + get_vogel_disk(penumbra_shadow_kernel, penumbra_shadow_samples); + get_vogel_disk(soft_shadow_kernel, soft_shadow_samples); + } +} + +void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) { + + ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); + + if (directional_shadow_quality != p_quality) { + directional_shadow_quality = p_quality; + + switch (directional_shadow_quality) { + case RS::SHADOW_QUALITY_HARD: { + directional_penumbra_shadow_samples = 4; + directional_soft_shadow_samples = 1; + directional_shadow_quality_radius = 1.0; + } break; + case RS::SHADOW_QUALITY_SOFT_LOW: { + directional_penumbra_shadow_samples = 8; + directional_soft_shadow_samples = 4; + directional_shadow_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_MEDIUM: { + directional_penumbra_shadow_samples = 12; + directional_soft_shadow_samples = 8; + directional_shadow_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_HIGH: { + directional_penumbra_shadow_samples = 24; + directional_soft_shadow_samples = 16; + directional_shadow_quality_radius = 3.0; + } break; + case RS::SHADOW_QUALITY_SOFT_ULTRA: { + directional_penumbra_shadow_samples = 32; + directional_soft_shadow_samples = 32; + directional_shadow_quality_radius = 4.0; + } break; + case RS::SHADOW_QUALITY_MAX: + break; + } + get_vogel_disk(directional_penumbra_shadow_kernel, directional_penumbra_shadow_samples); + get_vogel_disk(directional_soft_shadow_kernel, directional_soft_shadow_samples); + } +} + int RasterizerSceneRD::get_roughness_layers() const { return roughness_layers; } @@ -3473,7 +3737,7 @@ RasterizerSceneRD::RenderBufferData *RasterizerSceneRD::render_buffers_get_data( return rb->data; } -void RasterizerSceneRD::render_scene(RID p_render_buffers, 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) { +void RasterizerSceneRD::render_scene(RID p_render_buffers, 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_decal_cull_result, int p_decal_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) { Color clear_color; if (p_render_buffers.is_valid()) { @@ -3484,7 +3748,7 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca clear_color = storage->get_default_clear_color(); } - _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color); + _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_decal_cull_result, p_decal_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color); if (p_render_buffers.is_valid()) { RENDER_TIMESTAMP("Tonemap"); @@ -3500,16 +3764,19 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas ERR_FAIL_COND(!light_instance); Rect2i atlas_rect; - RID atlas_fb; + RID atlas_texture; 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; @@ -3524,6 +3791,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; @@ -3562,7 +3830,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; @@ -3570,7 +3838,7 @@ 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; - atlas_fb = directional_shadow.fb; + atlas_texture = directional_shadow.depth; } else { //set from shadow atlas @@ -3597,7 +3865,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas atlas_rect.size.width = shadow_size; atlas_rect.size.height = shadow_size; - atlas_fb = shadow_atlas->fb; + atlas_texture = shadow_atlas->depth; 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); @@ -3641,26 +3909,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_texture, 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_texture, 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_depth_to_rect_and_linearize(render_texture, atlas_texture, atlas_rect, true, znear, zfar); + } else { + storage->get_effects()->copy_depth_to_rect(render_texture, atlas_texture, 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); @@ -3693,6 +3968,8 @@ bool RasterizerSceneRD::free(RID p_rid) { //ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid); reflection_probe_release_atlas_index(p_rid); reflection_probe_instance_owner.free(p_rid); + } else if (decal_instance_owner.owns(p_rid)) { + decal_instance_owner.free(p_rid); } else if (gi_probe_instance_owner.owns(p_rid)) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid); if (gi_probe->texture.is_valid()) { @@ -3936,21 +4213,25 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color"; actions.renames["RADIANCE"] = "radiance"; actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled"; - actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction"; - actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].energy"; - actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color"; + actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz"; + actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w"; + actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz"; + actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w"; actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled"; - actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction"; - actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].energy"; - actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color"; + actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz"; + actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w"; + actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz"; + actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w"; actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled"; - actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction"; - actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].energy"; - actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color"; + actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz"; + actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w"; + actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz"; + actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w"; actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled"; - actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction"; - actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].energy"; - actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color"; + actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz"; + actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w"; + actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz"; + actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w"; actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS"; actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS"; actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS"; @@ -3966,6 +4247,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; + actions.global_buffer_array_variable = "global_variables.data"; sky_shader.compiler.initialize(actions); } @@ -3973,7 +4255,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { // default material and shader for sky shader sky_shader.default_shader = storage->shader_create(); - storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = mix(vec3(0.3), vec3(0.2, 0.4, 0.9), smoothstep(0.0, 0.05, EYEDIR.y)); } \n"); + storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = vec3(0.0); } \n"); sky_shader.default_material = storage->material_create(); storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader); @@ -4003,15 +4285,33 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { uniforms.push_back(u); } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.ids.push_back(storage->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS); } - camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_shape")))); - camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/filters/depth_of_field_use_jitter")); + camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape")))); + camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter")); environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); - screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter"); - screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve"); + screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter"); + screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/screen_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"); + directional_penumbra_shadow_kernel = memnew_arr(float, 128); + directional_soft_shadow_kernel = memnew_arr(float, 128); + penumbra_shadow_kernel = memnew_arr(float, 128); + soft_shadow_kernel = memnew_arr(float, 128); + shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality")))); + directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality")))); } RasterizerSceneRD::~RasterizerSceneRD() { @@ -4040,4 +4340,8 @@ RasterizerSceneRD::~RasterizerSceneRD() { memdelete_arr(sky_scene_state.last_frame_directional_lights); storage->free(sky_shader.default_shader); storage->free(sky_shader.default_material); + memdelete_arr(directional_penumbra_shadow_kernel); + memdelete_arr(directional_soft_shadow_kernel); + memdelete_arr(penumbra_shadow_kernel); + memdelete_arr(soft_shadow_kernel); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h index dbdaf2f447..a511838e16 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h @@ -56,7 +56,9 @@ protected: float direction[3]; float energy; float color[3]; + float size; uint32_t enabled; + uint32_t pad[3]; }; struct SkySceneState { @@ -78,8 +80,8 @@ 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_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_decal_cull_result, int p_decal_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, 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); @@ -92,10 +94,12 @@ protected: virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) = 0; 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); - void _draw_sky(bool p_can_continue, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); + void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); private: RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED; @@ -187,6 +191,7 @@ private: virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; @@ -322,6 +327,16 @@ private: mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; + /* REFLECTION PROBE INSTANCE */ + + struct DecalInstance { + + RID decal; + Transform transform; + }; + + mutable RID_Owner<DecalInstance> decal_instance_owner; + /* GIPROBE INSTANCE */ struct GIProbeLight { @@ -525,11 +540,24 @@ 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::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set + RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX; + float shadows_quality_radius = 1.0; + float directional_shadow_quality_radius = 1.0; + + float *directional_penumbra_shadow_kernel; + float *directional_soft_shadow_kernel; + float *penumbra_shadow_kernel; + float *soft_shadow_kernel; + int directional_penumbra_shadow_samples = 0; + int directional_soft_shadow_samples = 0; + int penumbra_shadow_samples = 0; + int soft_shadow_samples = 0; + /* DIRECTIONAL SHADOW */ struct DirectionalShadow { RID depth; - RID fb; //for copying int light_count = 0; int size = 0; @@ -568,7 +596,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; @@ -657,11 +688,20 @@ private: float ssao_ao_channel_affect = 0.0; float ssao_blur_edge_sharpness = 4.0; RS::EnvironmentSSAOBlur ssao_blur = RS::ENV_SSAO_BLUR_3x3; + + /// SSR + /// + bool ssr_enabled = false; + int ssr_max_steps = 64; + float ssr_fade_in = 0.15; + float ssr_fade_out = 2.0; + float ssr_depth_tolerance = 0.2; }; RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; bool ssao_half_size = false; bool glow_bicubic_upscale = false; + RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW; static uint64_t auto_exposure_counter; @@ -688,6 +728,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; @@ -698,6 +741,8 @@ private: RenderBufferData *data = nullptr; int width = 0, height = 0; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; + RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; + RID render_target; uint64_t auto_exposure_version = 1; @@ -711,7 +756,6 @@ private: struct Mipmap { RID texture; - RID framebuffer; int width; int height; }; @@ -733,6 +777,12 @@ private: RID ao[2]; RID ao_full; //when using half-size } ssao; + + struct SSR { + RID normal_scaled; + RID depth_scaled; + RID blur_radius[2]; + } ssr; }; bool screen_space_roughness_limiter = false; @@ -819,8 +869,8 @@ public: float environment_get_bg_energy(RID p_env) const; int environment_get_canvas_max_layer(RID p_env) const; Color environment_get_ambient_light_color(RID p_env) const; - RS::EnvironmentAmbientSource environment_get_ambient_light_ambient_source(RID p_env) const; - float environment_get_ambient_light_ambient_energy(RID p_env) const; + RS::EnvironmentAmbientSource environment_get_ambient_source(RID p_env) const; + float environment_get_ambient_light_energy(RID p_env) const; float environment_get_ambient_sky_contribution(RID p_env) const; RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const; Color environment_get_ao_color(RID p_env) const; @@ -832,7 +882,7 @@ public: void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} - void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) {} + void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance); void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness); void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size); bool environment_is_ssao_enabled(RID p_env) const; @@ -840,6 +890,9 @@ public: float environment_get_ssao_light_affect(RID p_env) const; bool environment_is_ssr_enabled(RID p_env) const; + void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality); + RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const; + void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} @@ -857,7 +910,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) { @@ -903,11 +956,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) { @@ -921,6 +1018,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; @@ -1013,6 +1116,19 @@ public: return rpi->atlas_index; } + virtual RID decal_instance_create(RID p_decal); + virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform); + + _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const { + DecalInstance *decal = decal_instance_owner.getornull(p_decal); + return decal->decal; + } + + _FORCE_INLINE_ Transform decal_instance_get_transform(RID p_decal) const { + DecalInstance *decal = decal_instance_owner.getornull(p_decal); + return decal->transform; + } + RID gi_probe_instance_create(RID p_base); void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); bool gi_probe_needs_update(RID p_probe) const; @@ -1073,24 +1189,49 @@ public: GIProbeQuality gi_probe_get_quality() const; RID render_buffers_create(); - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa); + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa); RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); - void render_scene(RID p_render_buffers, 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_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + void render_scene(RID p_render_buffers, 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_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); 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 shadows_quality_set(RS::ShadowQuality p_quality); + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality); + _FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const { return shadows_quality; } + _FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const { return directional_shadow_quality; } + _FORCE_INLINE_ float shadows_quality_radius_get() const { return shadows_quality_radius; } + _FORCE_INLINE_ float directional_shadow_quality_radius_get() const { return directional_shadow_quality_radius; } + + _FORCE_INLINE_ float *directional_penumbra_shadow_kernel_get() { return directional_penumbra_shadow_kernel; } + _FORCE_INLINE_ float *directional_soft_shadow_kernel_get() { return directional_soft_shadow_kernel; } + _FORCE_INLINE_ float *penumbra_shadow_kernel_get() { return penumbra_shadow_kernel; } + _FORCE_INLINE_ float *soft_shadow_kernel_get() { return soft_shadow_kernel; } + + _FORCE_INLINE_ int directional_penumbra_shadow_samples_get() const { return directional_penumbra_shadow_samples; } + _FORCE_INLINE_ int directional_soft_shadow_samples_get() const { return directional_soft_shadow_samples; } + _FORCE_INLINE_ int penumbra_shadow_samples_get() const { return penumbra_shadow_samples; } + _FORCE_INLINE_ int soft_shadow_samples_get() const { return soft_shadow_samples; } + int get_roughness_layers() const; bool is_using_radiance_cubemap_array() const; @@ -1099,7 +1240,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..8d299d623a 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -31,6 +31,7 @@ #include "rasterizer_storage_rd.h" #include "core/engine.h" +#include "core/io/resource_loader.h" #include "core/project_settings.h" #include "servers/rendering/shader_language.h" @@ -130,7 +131,6 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima image->convert(Image::FORMAT_RGBAF); } - r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; @@ -170,7 +170,6 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima image->convert(Image::FORMAT_RGBAH); } - r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; @@ -809,6 +808,12 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { } //delete last, so proxies can be updated texture_owner.free(p_by_texture); + + if (decal_atlas.textures.has(p_texture)) { + //belongs to decal atlas.. + + decal_atlas.dirty = true; //mark it dirty since it was most likely modified + } } void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { Texture *tex = texture_owner.getornull(p_texture); @@ -915,6 +920,7 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { Material *material = E->get(); if (shader->data) { material->data = material_data_request_func[new_type](shader->data); + material->data->self = material->self; material->data->set_next_pass(material->next_pass); material->data->set_render_priority(material->priority); } @@ -1015,8 +1021,8 @@ void RasterizerStorageRD::_material_queue_update(Material *material, bool p_unif material->update_next = material_update_list; material_update_list = material; material->update_requested = true; - material->uniform_dirty = p_uniform; - material->texture_dirty = p_texture; + material->uniform_dirty = material->uniform_dirty || p_uniform; + material->texture_dirty = material->texture_dirty || p_texture; } void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { @@ -1053,6 +1059,7 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { ERR_FAIL_COND(shader->data == nullptr); material->data = material_data_request_func[shader->type](shader->data); + material->data->self = p_material; material->data->set_next_pass(material->next_pass); material->data->set_render_priority(material->priority); //updating happens later @@ -1138,6 +1145,19 @@ bool RasterizerStorageRD::material_casts_shadows(RID p_material) { return true; //by default everything casts shadows } +void RasterizerStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) { + + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + if (material->shader && material->shader->data) { + material->shader->data->get_instance_param_list(r_parameters); + + if (material->next_pass.is_valid()) { + material_get_instance_shader_parameters(material->next_pass, r_parameters); + } + } +} + void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); @@ -1625,11 +1645,36 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) { + bool uses_global_buffer = false; + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) { if (E->get().order < 0) continue; // texture, does not go here + if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; //instance uniforms don't appear in the bufferr + } + + if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { + //this is a global variable, get the index to it + RasterizerStorageRD *rs = base_singleton; + + GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E->key()); + uint32_t index = 0; + if (gv) { + index = gv->buffer_index; + } else { + WARN_PRINT("Shader uses global uniform '" + E->key() + "', but it was removed at some point. Material will not display correctly."); + } + + uint32_t offset = p_uniform_offsets[E->get().order]; + uint32_t *intptr = (uint32_t *)&p_buffer[offset]; + *intptr = index; + uses_global_buffer = true; + continue; + } + //regular uniform uint32_t offset = p_uniform_offsets[E->get().order]; #ifdef DEBUG_ENABLED @@ -1658,6 +1703,38 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa } } } + + if (uses_global_buffer != (global_buffer_E != nullptr)) { + RasterizerStorageRD *rs = base_singleton; + if (uses_global_buffer) { + global_buffer_E = rs->global_variables.materials_using_buffer.push_back(self); + } else { + rs->global_variables.materials_using_buffer.erase(global_buffer_E); + global_buffer_E = nullptr; + } + } +} + +RasterizerStorageRD::MaterialData::~MaterialData() { + if (global_buffer_E) { + //unregister global buffers + RasterizerStorageRD *rs = base_singleton; + rs->global_variables.materials_using_buffer.erase(global_buffer_E); + } + + if (global_texture_E) { + //unregister global textures + RasterizerStorageRD *rs = base_singleton; + + for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) { + GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key()); + if (v) { + v->texture_materials.erase(self); + } + } + //unregister material from those using global textures + rs->global_variables.materials_using_texture.erase(global_texture_E); + } } void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { @@ -1669,22 +1746,57 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va Texture *normal_detect_texture = nullptr; #endif + bool uses_global_textures = false; + global_textures_pass++; + for (int i = 0; i < p_texture_uniforms.size(); i++) { const StringName &uniform_name = p_texture_uniforms[i].name; RID texture; - const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name); - if (V) { - texture = V->get(); - } + if (p_texture_uniforms[i].global) { + + RasterizerStorageRD *rs = base_singleton; + + uses_global_textures = true; + + GlobalVariables::Variable *v = rs->global_variables.variables.getptr(uniform_name); + if (v) { + if (v->buffer_index >= 0) { + WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!."); + + } else { + + Map<StringName, uint64_t>::Element *E = used_global_textures.find(uniform_name); + if (!E) { + E = used_global_textures.insert(uniform_name, global_textures_pass); + v->texture_materials.insert(self); + } else { + E->get() = global_textures_pass; + } + + texture = v->override.get_type() != Variant::NIL ? v->override : v->value; + } + + } else { + WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly."); + } + } else { + if (!texture.is_valid()) { - if (!texture.is_valid()) { - const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name); - if (W) { + const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name); + if (V) { + texture = V->get(); + } + } - texture = W->get(); + if (!texture.is_valid()) { + const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name); + if (W) { + + texture = W->get(); + } } } @@ -1747,6 +1859,36 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } #endif + { + //for textures no longer used, unregister them + List<Map<StringName, uint64_t>::Element *> to_delete; + RasterizerStorageRD *rs = base_singleton; + + for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) { + if (E->get() != global_textures_pass) { + to_delete.push_back(E); + + GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key()); + if (v) { + v->texture_materials.erase(self); + } + } + } + + while (to_delete.front()) { + used_global_textures.erase(to_delete.front()->get()); + to_delete.pop_front(); + } + //handle registering/unregistering global textures + if (uses_global_textures != (global_texture_E != nullptr)) { + if (uses_global_textures) { + global_texture_E = rs->global_variables.materials_using_texture.push_back(self); + } else { + rs->global_variables.materials_using_texture.erase(global_texture_E); + global_texture_E = nullptr; + } + } + } } void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { @@ -2197,14 +2339,14 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su Mesh::Surface::Version &v = s->versions[version]; - Vector<RD::VertexDescription> attributes; + Vector<RD::VertexAttribute> attributes; Vector<RID> buffers; uint32_t stride = 0; for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) { - RD::VertexDescription vd; + RD::VertexAttribute vd; RID buffer; vd.location = i; @@ -3104,15 +3246,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 +3282,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++; @@ -3171,7 +3316,19 @@ void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); + if (light->projector == p_texture) { + return; + } + + if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) { + texture_remove_from_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI); + } + light->projector = p_texture; + + if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) { + texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI); + } } void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) { @@ -3550,6 +3707,94 @@ float RasterizerStorageRD::reflection_probe_get_interior_ambient_probe_contribut return reflection_probe->interior_ambient_probe_contrib; } +RID RasterizerStorageRD::decal_create() { + return decal_owner.make_rid(Decal()); +} + +void RasterizerStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) { + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->extents = p_extents; + decal->instance_dependency.instance_notify_changed(true, false); +} +void RasterizerStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX); + + if (decal->textures[p_type] == p_texture) { + return; + } + + ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture)); + + if (decal->textures[p_type].is_valid() && texture_owner.owns(decal->textures[p_type])) { + texture_remove_from_decal_atlas(decal->textures[p_type]); + } + + decal->textures[p_type] = p_texture; + + if (decal->textures[p_type].is_valid()) { + texture_add_to_decal_atlas(decal->textures[p_type]); + } + + decal->instance_dependency.instance_notify_changed(false, true); +} +void RasterizerStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) { + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->emission_energy = p_energy; +} + +void RasterizerStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) { + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->albedo_mix = p_mix; +} + +void RasterizerStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) { + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->modulate = p_modulate; +} +void RasterizerStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->cull_mask = p_layers; + decal->instance_dependency.instance_notify_changed(true, false); +} + +void RasterizerStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { + + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->distance_fade = p_enabled; + decal->distance_fade_begin = p_begin; + decal->distance_fade_length = p_length; +} + +void RasterizerStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) { + + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->upper_fade = p_above; + decal->lower_fade = p_below; +} + +void RasterizerStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) { + + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND(!decal); + decal->normal_fade = p_fade; +} + +AABB RasterizerStorageRD::decal_get_aabb(RID p_decal) const { + Decal *decal = decal_owner.getornull(p_decal); + ERR_FAIL_COND_V(!decal, AABB()); + + return AABB(-decal->extents, decal->extents * 2.0); +} + RID RasterizerStorageRD::gi_probe_create() { return gi_probe_owner.make_rid(GIProbe()); @@ -3911,7 +4156,6 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { if (rt->backbuffer.is_valid()) { RD::get_singleton()->free(rt->backbuffer); rt->backbuffer = RID(); - rt->backbuffer_fb = RID(); for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { //just erase copies, since the rest are erased by dependency RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy); @@ -4025,17 +4269,11 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { tf.width = rt->size.width; tf.height = rt->size.height; tf.type = RD::TEXTURE_TYPE_2D; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - { - Vector<RID> backbuffer_att; - RID backbuffer_fb_tex = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); - backbuffer_att.push_back(backbuffer_fb_tex); - rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(backbuffer_att); - } + rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); //create mipmaps for (uint32_t i = 1; i < mipmaps_required; i++) { @@ -4043,9 +4281,6 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { RenderTarget::BackbufferMipmap mm; { mm.mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i); - Vector<RID> mm_fb_at; - mm_fb_at.push_back(mm.mipmap); - mm.mipmap_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); } { @@ -4057,9 +4292,6 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { mmtf.mipmaps = 1; mm.mipmap_copy = RD::get_singleton()->texture_create(mmtf, RD::TextureView()); - Vector<RID> mm_fb_at; - mm_fb_at.push_back(mm.mipmap_copy); - mm.mipmap_copy_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); } rt->backbuffer_mipmaps.push_back(mm); @@ -4135,7 +4367,12 @@ RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { return rt->framebuffer; } +RID RasterizerStorageRD::render_target_get_rd_texture(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + return rt->color; +} void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -4185,27 +4422,25 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, } Rect2i region = p_region; - Rect2 blur_region; if (region == Rect2i()) { region.size = rt->size; - } else { - blur_region = region; - blur_region.position /= rt->size; - blur_region.size /= rt->size; } //single texture copy for backbuffer - RD::get_singleton()->texture_copy(rt->color, rt->backbuffer, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); + RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); //effects.copy(rt->color, rt->backbuffer_fb, blur_region); //then mipmap blur RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. - Vector2 pixel_size = Vector2(1.0 / rt->size.width, 1.0 / rt->size.height); for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { - pixel_size *= 2.0; //go halfway + region.position.x >>= 1; + region.position.y >>= 1; + region.size.x = MAX(1, region.size.x >> 1); + region.size.y = MAX(1, region.size.y >> 1); + const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; - effects.gaussian_blur(prev_texture, mm.mipmap_copy_fb, mm.mipmap_copy, mm.mipmap_fb, pixel_size, blur_region); + effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); prev_texture = mm.mipmap; } } @@ -4250,6 +4485,9 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In } else if (reflection_probe_owner.owns(p_base)) { ReflectionProbe *rp = reflection_probe_owner.getornull(p_base); p_instance->update_dependency(&rp->instance_dependency); + } else if (decal_owner.owns(p_base)) { + Decal *decal = decal_owner.getornull(p_base); + p_instance->update_dependency(&decal->instance_dependency); } else if (gi_probe_owner.owns(p_base)) { GIProbe *gip = gi_probe_owner.getornull(p_base); p_instance->update_dependency(&gip->instance_dependency); @@ -4278,6 +4516,9 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { if (reflection_probe_owner.owns(p_rid)) { return RS::INSTANCE_REFLECTION_PROBE; } + if (decal_owner.owns(p_rid)) { + return RS::INSTANCE_DECAL; + } if (gi_probe_owner.owns(p_rid)) { return RS::INSTANCE_GI_PROBE; } @@ -4287,10 +4528,924 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { return RS::INSTANCE_NONE; } + +void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) { + if (!decal_atlas.textures.has(p_texture)) { + DecalAtlas::Texture t; + t.users = 1; + t.panorama_to_dp_users = p_panorama_to_dp ? 1 : 0; + decal_atlas.textures[p_texture] = t; + decal_atlas.dirty = true; + } else { + DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture); + t->users++; + if (p_panorama_to_dp) { + t->panorama_to_dp_users++; + } + } +} + +void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) { + DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture); + ERR_FAIL_COND(!t); + t->users--; + if (p_panorama_to_dp) { + ERR_FAIL_COND(t->panorama_to_dp_users == 0); + t->panorama_to_dp_users--; + } + if (t->users == 0) { + decal_atlas.textures.erase(p_texture); + //do not mark it dirty, there is no need to since it remains working + } +} + +RID RasterizerStorageRD::decal_atlas_get_texture() const { + return decal_atlas.texture; +} + +RID RasterizerStorageRD::decal_atlas_get_texture_srgb() const { + return decal_atlas.texture; +} + +void RasterizerStorageRD::_update_decal_atlas() { + if (!decal_atlas.dirty) { + return; //nothing to do + } + + decal_atlas.dirty = false; + + if (decal_atlas.texture.is_valid()) { + RD::get_singleton()->free(decal_atlas.texture); + decal_atlas.texture = RID(); + decal_atlas.texture_srgb = RID(); + decal_atlas.texture_mipmaps.clear(); + } + + int border = 1 << decal_atlas.mipmaps; + + if (decal_atlas.textures.size()) { + //generate atlas + Vector<DecalAtlas::SortItem> itemsv; + itemsv.resize(decal_atlas.textures.size()); + int base_size = 8; + const RID *K = NULL; + + int idx = 0; + while ((K = decal_atlas.textures.next(K))) { + DecalAtlas::SortItem &si = itemsv.write[idx]; + + Texture *src_tex = texture_owner.getornull(*K); + + si.size.width = (src_tex->width / border) + 1; + si.size.height = (src_tex->height / border) + 1; + si.pixel_size = Size2i(src_tex->width, src_tex->height); + + if (base_size < si.size.width) { + base_size = nearest_power_of_2_templated(si.size.width); + } + + si.texture = *K; + idx++; + } + + //sort items by size + itemsv.sort(); + + //attempt to create atlas + int item_count = itemsv.size(); + DecalAtlas::SortItem *items = itemsv.ptrw(); + + int atlas_height = 0; + + while (true) { + + Vector<int> v_offsetsv; + v_offsetsv.resize(base_size); + + int *v_offsets = v_offsetsv.ptrw(); + zeromem(v_offsets, sizeof(int) * base_size); + + int max_height = 0; + + for (int i = 0; i < item_count; i++) { + //best fit + DecalAtlas::SortItem &si = items[i]; + int best_idx = -1; + int best_height = 0x7FFFFFFF; + for (int j = 0; j <= base_size - si.size.width; j++) { + int height = 0; + for (int k = 0; k < si.size.width; k++) { + int h = v_offsets[k + j]; + if (h > height) { + height = h; + if (height > best_height) { + break; //already bad + } + } + } + + if (height < best_height) { + best_height = height; + best_idx = j; + } + } + + //update + for (int k = 0; k < si.size.width; k++) { + v_offsets[k + best_idx] = best_height + si.size.height; + } + + si.pos.x = best_idx; + si.pos.y = best_height; + + if (si.pos.y + si.size.height > max_height) { + max_height = si.pos.y + si.size.height; + } + } + + if (max_height <= base_size * 2) { + atlas_height = max_height; + break; //good ratio, break; + } + + base_size *= 2; + } + + decal_atlas.size.width = base_size * border; + decal_atlas.size.height = nearest_power_of_2_templated(atlas_height * border); + + for (int i = 0; i < item_count; i++) { + DecalAtlas::Texture *t = decal_atlas.textures.getptr(items[i].texture); + t->uv_rect.position = items[i].pos * border + Vector2i(border / 2, border / 2); + t->uv_rect.size = items[i].pixel_size; + //print_line("blitrect: " + t->uv_rect); + t->uv_rect.position /= Size2(decal_atlas.size); + t->uv_rect.size /= Size2(decal_atlas.size); + } + } else { + + //use border as size, so it at least has enough mipmaps + decal_atlas.size.width = border; + decal_atlas.size.height = border; + } + + //blit textures + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = decal_atlas.size.width; + tformat.height = decal_atlas.size.height; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tformat.type = RD::TEXTURE_TYPE_2D; + tformat.mipmaps = decal_atlas.mipmaps; + tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); + tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); + + decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + { + //create the framebuffer + + Size2i s = decal_atlas.size; + + for (int i = 0; i < decal_atlas.mipmaps; i++) { + DecalAtlas::MipMap mm; + mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), decal_atlas.texture, 0, i); + Vector<RID> fb; + fb.push_back(mm.texture); + mm.fb = RD::get_singleton()->framebuffer_create(fb); + mm.size = s; + decal_atlas.texture_mipmaps.push_back(mm); + + s.width = MAX(1, s.width >> 1); + s.height = MAX(1, s.height >> 1); + } + { + //create the SRGB variant + RD::TextureView rd_view; + rd_view.format_override = RD::DATA_FORMAT_R8G8B8A8_SRGB; + decal_atlas.texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, decal_atlas.texture); + } + } + + RID prev_texture; + for (int i = 0; i < decal_atlas.texture_mipmaps.size(); i++) { + const DecalAtlas::MipMap &mm = decal_atlas.texture_mipmaps[i]; + + Color clear_color(0, 0, 0, 0); + + if (decal_atlas.textures.size()) { + + if (i == 0) { + Vector<Color> cc; + cc.push_back(clear_color); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, cc); + + const RID *K = NULL; + while ((K = decal_atlas.textures.next(K))) { + DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K); + Texture *src_tex = texture_owner.getornull(*K); + effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0); + } + + RD::get_singleton()->draw_list_end(); + + prev_texture = mm.texture; + } else { + + effects.copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size)); + prev_texture = mm.texture; + } + } else { + RD::get_singleton()->texture_clear(mm.texture, clear_color, 0, 1, 0, 1, false); + } + } +} + +int32_t RasterizerStorageRD::_global_variable_allocate(uint32_t p_elements) { + + int32_t idx = 0; + while (idx + p_elements <= global_variables.buffer_size) { + if (global_variables.buffer_usage[idx].elements == 0) { + bool valid = true; + for (uint32_t i = 1; i < p_elements; i++) { + if (global_variables.buffer_usage[idx + i].elements > 0) { + valid = false; + idx += i + global_variables.buffer_usage[idx + i].elements; + break; + } + } + + if (!valid) { + continue; //if not valid, idx is in new position + } + + return idx; + } else { + idx += global_variables.buffer_usage[idx].elements; + } + } + + return -1; +} + +void RasterizerStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value) { + + switch (p_type) { + case RS::GLOBAL_VAR_TYPE_BOOL: { + + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + bool b = p_value; + bv.x = b ? 1.0 : 0.0; + bv.y = 0.0; + bv.z = 0.0; + bv.w = 0.0; + + } break; + case RS::GLOBAL_VAR_TYPE_BVEC2: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + uint32_t bvec = p_value; + bv.x = (bvec & 1) ? 1.0 : 0.0; + bv.y = (bvec & 2) ? 1.0 : 0.0; + bv.z = 0.0; + bv.w = 0.0; + } break; + case RS::GLOBAL_VAR_TYPE_BVEC3: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + uint32_t bvec = p_value; + bv.x = (bvec & 1) ? 1.0 : 0.0; + bv.y = (bvec & 2) ? 1.0 : 0.0; + bv.z = (bvec & 4) ? 1.0 : 0.0; + bv.w = 0.0; + } break; + case RS::GLOBAL_VAR_TYPE_BVEC4: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + uint32_t bvec = p_value; + bv.x = (bvec & 1) ? 1.0 : 0.0; + bv.y = (bvec & 2) ? 1.0 : 0.0; + bv.z = (bvec & 4) ? 1.0 : 0.0; + bv.w = (bvec & 8) ? 1.0 : 0.0; + } break; + case RS::GLOBAL_VAR_TYPE_INT: { + GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index]; + int32_t v = p_value; + bv.x = v; + bv.y = 0; + bv.z = 0; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_IVEC2: { + GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index]; + Vector2i v = p_value; + bv.x = v.x; + bv.y = v.y; + bv.z = 0; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_IVEC3: { + GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index]; + Vector3i v = p_value; + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_IVEC4: { + GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index]; + Vector<int32_t> v = p_value; + bv.x = v.size() >= 1 ? v[0] : 0; + bv.y = v.size() >= 2 ? v[1] : 0; + bv.z = v.size() >= 3 ? v[2] : 0; + bv.w = v.size() >= 4 ? v[3] : 0; + } break; + case RS::GLOBAL_VAR_TYPE_RECT2I: { + GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index]; + Rect2i v = p_value; + bv.x = v.position.x; + bv.y = v.position.y; + bv.z = v.size.x; + bv.w = v.size.y; + } break; + case RS::GLOBAL_VAR_TYPE_UINT: { + GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index]; + uint32_t v = p_value; + bv.x = v; + bv.y = 0; + bv.z = 0; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_UVEC2: { + GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index]; + Vector2i v = p_value; + bv.x = v.x; + bv.y = v.y; + bv.z = 0; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_UVEC3: { + GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index]; + Vector3i v = p_value; + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_UVEC4: { + GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index]; + Vector<int32_t> v = p_value; + bv.x = v.size() >= 1 ? v[0] : 0; + bv.y = v.size() >= 2 ? v[1] : 0; + bv.z = v.size() >= 3 ? v[2] : 0; + bv.w = v.size() >= 4 ? v[3] : 0; + } break; + case RS::GLOBAL_VAR_TYPE_FLOAT: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + float v = p_value; + bv.x = v; + bv.y = 0; + bv.z = 0; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_VEC2: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + Vector2 v = p_value; + bv.x = v.x; + bv.y = v.y; + bv.z = 0; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_VEC3: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + Vector3 v = p_value; + bv.x = v.x; + bv.y = v.y; + bv.z = v.z; + bv.w = 0; + } break; + case RS::GLOBAL_VAR_TYPE_VEC4: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + Plane v = p_value; + bv.x = v.normal.x; + bv.y = v.normal.y; + bv.z = v.normal.z; + bv.w = v.d; + } break; + case RS::GLOBAL_VAR_TYPE_COLOR: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + Color v = p_value; + bv.x = v.r; + bv.y = v.g; + bv.z = v.b; + bv.w = v.a; + + GlobalVariables::Value &bv_linear = global_variables.buffer_values[p_index + 1]; + v = v.to_linear(); + bv_linear.x = v.r; + bv_linear.y = v.g; + bv_linear.z = v.b; + bv_linear.w = v.a; + + } break; + case RS::GLOBAL_VAR_TYPE_RECT2: { + GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; + Rect2 v = p_value; + bv.x = v.position.x; + bv.y = v.position.y; + bv.z = v.size.x; + bv.w = v.size.y; + } break; + case RS::GLOBAL_VAR_TYPE_MAT2: { + GlobalVariables::Value *bv = &global_variables.buffer_values[p_index]; + Vector<float> m2 = p_value; + if (m2.size() < 4) { + m2.resize(4); + } + bv[0].x = m2[0]; + bv[0].y = m2[1]; + bv[0].z = 0; + bv[0].w = 0; + + bv[1].x = m2[2]; + bv[1].y = m2[3]; + bv[1].z = 0; + bv[1].w = 0; + + } break; + case RS::GLOBAL_VAR_TYPE_MAT3: { + + GlobalVariables::Value *bv = &global_variables.buffer_values[p_index]; + Basis v = p_value; + bv[0].x = v.elements[0][0]; + bv[0].y = v.elements[1][0]; + bv[0].z = v.elements[2][0]; + bv[0].w = 0; + + bv[1].x = v.elements[0][1]; + bv[1].y = v.elements[1][1]; + bv[1].z = v.elements[2][1]; + bv[1].w = 0; + + bv[2].x = v.elements[0][2]; + bv[2].y = v.elements[1][2]; + bv[2].z = v.elements[2][2]; + bv[2].w = 0; + + } break; + case RS::GLOBAL_VAR_TYPE_MAT4: { + + GlobalVariables::Value *bv = &global_variables.buffer_values[p_index]; + + Vector<float> m2 = p_value; + if (m2.size() < 16) { + m2.resize(16); + } + + bv[0].x = m2[0]; + bv[0].y = m2[1]; + bv[0].z = m2[2]; + bv[0].w = m2[3]; + + bv[1].x = m2[4]; + bv[1].y = m2[5]; + bv[1].z = m2[6]; + bv[1].w = m2[7]; + + bv[2].x = m2[8]; + bv[2].y = m2[9]; + bv[2].z = m2[10]; + bv[2].w = m2[11]; + + bv[3].x = m2[12]; + bv[3].y = m2[13]; + bv[3].z = m2[14]; + bv[3].w = m2[15]; + + } break; + case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: { + + GlobalVariables::Value *bv = &global_variables.buffer_values[p_index]; + Transform2D v = p_value; + bv[0].x = v.elements[0][0]; + bv[0].y = v.elements[0][1]; + bv[0].z = 0; + bv[0].w = 0; + + bv[1].x = v.elements[1][0]; + bv[1].y = v.elements[1][1]; + bv[1].z = 0; + bv[1].w = 0; + + bv[2].x = v.elements[2][0]; + bv[2].y = v.elements[2][1]; + bv[2].z = 1; + bv[2].w = 0; + + } break; + case RS::GLOBAL_VAR_TYPE_TRANSFORM: { + + GlobalVariables::Value *bv = &global_variables.buffer_values[p_index]; + Transform v = p_value; + bv[0].x = v.basis.elements[0][0]; + bv[0].y = v.basis.elements[1][0]; + bv[0].z = v.basis.elements[2][0]; + bv[0].w = 0; + + bv[1].x = v.basis.elements[0][1]; + bv[1].y = v.basis.elements[1][1]; + bv[1].z = v.basis.elements[2][1]; + bv[1].w = 0; + + bv[2].x = v.basis.elements[0][2]; + bv[2].y = v.basis.elements[1][2]; + bv[2].z = v.basis.elements[2][2]; + bv[2].w = 0; + + bv[3].x = v.origin.x; + bv[3].y = v.origin.y; + bv[3].z = v.origin.z; + bv[3].w = 1; + + } break; + default: { + ERR_FAIL(); + } + } +} + +void RasterizerStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements) { + + int32_t prev_chunk = -1; + + for (int32_t i = 0; i < p_elements; i++) { + int32_t chunk = (p_index + i) / GlobalVariables::BUFFER_DIRTY_REGION_SIZE; + if (chunk != prev_chunk) { + if (!global_variables.buffer_dirty_regions[chunk]) { + global_variables.buffer_dirty_regions[chunk] = true; + global_variables.buffer_dirty_region_count++; + } + } + + prev_chunk = chunk; + } +} + +void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) { + + ERR_FAIL_COND(global_variables.variables.has(p_name)); + GlobalVariables::Variable gv; + gv.type = p_type; + gv.value = p_value; + gv.buffer_index = -1; + + if (p_type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) { + //is texture + global_variables.must_update_texture_materials = true; //normally ther are no + } else { + + gv.buffer_elements = 1; + if (p_type == RS::GLOBAL_VAR_TYPE_COLOR || p_type == RS::GLOBAL_VAR_TYPE_MAT2) { + //color needs to elements to store srgb and linear + gv.buffer_elements = 2; + } + if (p_type == RS::GLOBAL_VAR_TYPE_MAT3 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM_2D) { + //color needs to elements to store srgb and linear + gv.buffer_elements = 3; + } + if (p_type == RS::GLOBAL_VAR_TYPE_MAT4 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM) { + //color needs to elements to store srgb and linear + gv.buffer_elements = 4; + } + + //is vector, allocate in buffer and update index + gv.buffer_index = _global_variable_allocate(gv.buffer_elements); + ERR_FAIL_COND_MSG(gv.buffer_index < 0, vformat("Failed allocating global variable '%s' out of buffer memory. Consider increasing it in the Project Settings.", String(p_name))); + global_variables.buffer_usage[gv.buffer_index].elements = gv.buffer_elements; + _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value); + _global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements); + + global_variables.must_update_buffer_materials = true; //normally ther are no + } + + global_variables.variables[p_name] = gv; +} + +void RasterizerStorageRD::global_variable_remove(const StringName &p_name) { + if (!global_variables.variables.has(p_name)) { + return; + } + GlobalVariables::Variable &gv = global_variables.variables[p_name]; + + if (gv.buffer_index >= 0) { + global_variables.buffer_usage[gv.buffer_index].elements = 0; + global_variables.must_update_buffer_materials = true; + } else { + global_variables.must_update_texture_materials = true; + } + + global_variables.variables.erase(p_name); +} +Vector<StringName> RasterizerStorageRD::global_variable_get_list() const { + + if (!Engine::get_singleton()->is_editor_hint()) { + ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance."); + } + + const StringName *K = NULL; + Vector<StringName> names; + while ((K = global_variables.variables.next(K))) { + names.push_back(*K); + } + names.sort_custom<StringName::AlphCompare>(); + return names; +} + +void RasterizerStorageRD::global_variable_set(const StringName &p_name, const Variant &p_value) { + ERR_FAIL_COND(!global_variables.variables.has(p_name)); + GlobalVariables::Variable &gv = global_variables.variables[p_name]; + gv.value = p_value; + if (gv.override.get_type() == Variant::NIL) { + if (gv.buffer_index >= 0) { + //buffer + _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value); + _global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements); + } else { + //texture + for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) { + Material *material = material_owner.getornull(E->get()); + ERR_CONTINUE(!material); + _material_queue_update(material, false, true); + } + } + } +} +void RasterizerStorageRD::global_variable_set_override(const StringName &p_name, const Variant &p_value) { + if (!global_variables.variables.has(p_name)) { + return; //variable may not exist + } + GlobalVariables::Variable &gv = global_variables.variables[p_name]; + + gv.override = p_value; + + if (gv.buffer_index >= 0) { + //buffer + if (gv.override.get_type() == Variant::NIL) { + _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value); + } else { + _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.override); + } + + _global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements); + } else { + //texture + //texture + for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) { + Material *material = material_owner.getornull(E->get()); + ERR_CONTINUE(!material); + _material_queue_update(material, false, true); + } + } +} + +Variant RasterizerStorageRD::global_variable_get(const StringName &p_name) const { + + if (!Engine::get_singleton()->is_editor_hint()) { + ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance."); + } + + if (!global_variables.variables.has(p_name)) { + return Variant(); + } + + return global_variables.variables[p_name].value; +} + +RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type_internal(const StringName &p_name) const { + + if (!global_variables.variables.has(p_name)) { + return RS::GLOBAL_VAR_TYPE_MAX; + } + + return global_variables.variables[p_name].type; +} + +RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type(const StringName &p_name) const { + if (!Engine::get_singleton()->is_editor_hint()) { + ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance."); + } + + return global_variable_get_type_internal(p_name); +} + +void RasterizerStorageRD::global_variables_load_settings(bool p_load_textures) { + + List<PropertyInfo> settings; + ProjectSettings::get_singleton()->get_property_list(&settings); + + for (List<PropertyInfo>::Element *E = settings.front(); E; E = E->next()) { + if (E->get().name.begins_with("shader_globals/")) { + StringName name = E->get().name.get_slice("/", 1); + Dictionary d = ProjectSettings::get_singleton()->get(E->get().name); + + ERR_CONTINUE(!d.has("type")); + ERR_CONTINUE(!d.has("value")); + + String type = d["type"]; + + static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = { + "bool", + "bvec2", + "bvec3", + "bvec4", + "int", + "ivec2", + "ivec3", + "ivec4", + "rect2i", + "uint", + "uvec2", + "uvec3", + "uvec4", + "float", + "vec2", + "vec3", + "vec4", + "color", + "rect2", + "mat2", + "mat3", + "mat4", + "transform_2d", + "transform", + "sampler2D", + "sampler2DArray", + "sampler3D", + "samplerCube", + }; + + RS::GlobalVariableType gvtype = RS::GLOBAL_VAR_TYPE_MAX; + + for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) { + if (global_var_type_names[i] == type) { + gvtype = RS::GlobalVariableType(i); + break; + } + } + + ERR_CONTINUE(gvtype == RS::GLOBAL_VAR_TYPE_MAX); //type invalid + + Variant value = d["value"]; + + if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) { + //textire + if (!p_load_textures) { + value = RID(); + continue; + } + + String path = value; + RES resource = ResourceLoader::load(path); + ERR_CONTINUE(resource.is_null()); + value = resource; + } + + if (global_variables.variables.has(name)) { + //has it, update it + global_variable_set(name, value); + } else { + global_variable_add(name, gvtype, value); + } + } + } +} + +void RasterizerStorageRD::global_variables_clear() { + global_variables.variables.clear(); //not right but for now enough +} + +RID RasterizerStorageRD::global_variables_get_storage_buffer() const { + return global_variables.buffer; +} + +int32_t RasterizerStorageRD::global_variables_instance_allocate(RID p_instance) { + ERR_FAIL_COND_V(global_variables.instance_buffer_pos.has(p_instance), -1); + int32_t pos = _global_variable_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES); + global_variables.instance_buffer_pos[p_instance] = pos; //save anyway + ERR_FAIL_COND_V_MSG(pos < 0, -1, "Too many instances using shader instance variables. Increase buffer size in Project Settings."); + global_variables.buffer_usage[pos].elements = ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES; + return pos; +} + +void RasterizerStorageRD::global_variables_instance_free(RID p_instance) { + ERR_FAIL_COND(!global_variables.instance_buffer_pos.has(p_instance)); + int32_t pos = global_variables.instance_buffer_pos[p_instance]; + if (pos >= 0) { + global_variables.buffer_usage[pos].elements = 0; + } + global_variables.instance_buffer_pos.erase(p_instance); +} +void RasterizerStorageRD::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) { + + if (!global_variables.instance_buffer_pos.has(p_instance)) { + return; //just not allocated, ignore + } + int32_t pos = global_variables.instance_buffer_pos[p_instance]; + + if (pos < 0) { + return; //again, not allocated, ignore + } + ERR_FAIL_INDEX(p_index, ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES); + ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported + + ShaderLanguage::DataType datatype_from_value[Variant::COLOR + 1] = { + ShaderLanguage::TYPE_MAX, //nil + ShaderLanguage::TYPE_BOOL, //bool + ShaderLanguage::TYPE_INT, //int + ShaderLanguage::TYPE_FLOAT, //float + ShaderLanguage::TYPE_MAX, //string + ShaderLanguage::TYPE_VEC2, //vec2 + ShaderLanguage::TYPE_IVEC2, //vec2i + ShaderLanguage::TYPE_VEC4, //rect2 + ShaderLanguage::TYPE_IVEC4, //rect2i + ShaderLanguage::TYPE_VEC3, // vec3 + ShaderLanguage::TYPE_IVEC3, //vec3i + ShaderLanguage::TYPE_MAX, //xform2d not supported here + ShaderLanguage::TYPE_VEC4, //plane + ShaderLanguage::TYPE_VEC4, //quat + ShaderLanguage::TYPE_MAX, //aabb not supported here + ShaderLanguage::TYPE_MAX, //basis not supported here + ShaderLanguage::TYPE_MAX, //xform not supported here + ShaderLanguage::TYPE_VEC4 //color + }; + + ShaderLanguage::DataType datatype = datatype_from_value[p_value.get_type()]; + + ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported + + pos += p_index; + + _fill_std140_variant_ubo_value(datatype, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer + _global_variable_mark_buffer_dirty(pos, 1); +} + +void RasterizerStorageRD::_update_global_variables() { + + if (global_variables.buffer_dirty_region_count > 0) { + uint32_t total_regions = global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE; + if (total_regions / global_variables.buffer_dirty_region_count <= 4) { + // 25% of regions dirty, just update all buffer + RD::get_singleton()->buffer_update(global_variables.buffer, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size, global_variables.buffer_values); + zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * total_regions); + } else { + uint32_t region_byte_size = sizeof(GlobalVariables::Value) * GlobalVariables::BUFFER_DIRTY_REGION_SIZE; + + for (uint32_t i = 0; i < total_regions; i++) { + if (global_variables.buffer_dirty_regions[i]) { + + RD::get_singleton()->buffer_update(global_variables.buffer, i * region_byte_size, region_byte_size, global_variables.buffer_values); + + global_variables.buffer_dirty_regions[i] = false; + } + } + } + + global_variables.buffer_dirty_region_count = 0; + } + + if (global_variables.must_update_buffer_materials) { + // only happens in the case of a buffer variable added or removed, + // so not often. + for (List<RID>::Element *E = global_variables.materials_using_buffer.front(); E; E = E->next()) { + Material *material = material_owner.getornull(E->get()); + ERR_CONTINUE(!material); //wtf + + _material_queue_update(material, true, false); + } + + global_variables.must_update_buffer_materials = false; + } + + if (global_variables.must_update_texture_materials) { + // only happens in the case of a buffer variable added or removed, + // so not often. + for (List<RID>::Element *E = global_variables.materials_using_texture.front(); E; E = E->next()) { + Material *material = material_owner.getornull(E->get()); + ERR_CONTINUE(!material); //wtf + + _material_queue_update(material, false, true); + print_line("update material texture?"); + } + + global_variables.must_update_texture_materials = false; + } +} + void RasterizerStorageRD::update_dirty_resources() { + _update_global_variables(); //must do before materials, so it can queue them for update _update_queued_materials(); _update_dirty_multimeshes(); _update_dirty_skeletons(); + _update_decal_atlas(); } bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { @@ -4339,6 +5494,11 @@ bool RasterizerStorageRD::free(RID p_rid) { } } + if (decal_atlas.textures.has(p_rid)) { + decal_atlas.textures.erase(p_rid); + //there is not much a point of making it dirty, just let it be. + } + for (int i = 0; i < t->proxies.size(); i++) { Texture *p = texture_owner.getornull(t->proxies[i]); ERR_CONTINUE(!p); @@ -4389,6 +5549,15 @@ bool RasterizerStorageRD::free(RID p_rid) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); reflection_probe->instance_dependency.instance_notify_deleted(p_rid); reflection_probe_owner.free(p_rid); + } else if (decal_owner.owns(p_rid)) { + Decal *decal = decal_owner.getornull(p_rid); + for (int i = 0; i < RS::DECAL_TEXTURE_MAX; i++) { + if (decal->textures[i].is_valid() && texture_owner.owns(decal->textures[i])) { + texture_remove_from_decal_atlas(decal->textures[i]); + } + } + decal->instance_dependency.instance_notify_deleted(p_rid); + decal_owner.free(p_rid); } else if (gi_probe_owner.owns(p_rid)) { gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate GIProbe *gi_probe = gi_probe_owner.getornull(p_rid); @@ -4397,6 +5566,7 @@ bool RasterizerStorageRD::free(RID p_rid) { } else if (light_owner.owns(p_rid)) { + light_set_projector(p_rid, RID()); //clear projector // delete the texture Light *light = light_owner.getornull(p_rid); light->instance_dependency.instance_notify_deleted(p_rid); @@ -4450,12 +5620,27 @@ String RasterizerStorageRD::get_captured_timestamp_name(uint32_t p_index) const return RD::get_singleton()->get_captured_timestamp_name(p_index); } +RasterizerStorageRD *RasterizerStorageRD::base_singleton = nullptr; + RasterizerStorageRD::RasterizerStorageRD() { + base_singleton = this; + for (int i = 0; i < SHADER_TYPE_MAX; i++) { shader_data_request_func[i] = nullptr; } + static_assert(sizeof(GlobalVariables::Value) == 16); + + global_variables.buffer_size = GLOBAL_GET("rendering/high_end/global_shader_variables_buffer_size"); + global_variables.buffer_size = MAX(4096, global_variables.buffer_size); + global_variables.buffer_values = memnew_arr(GlobalVariables::Value, global_variables.buffer_size); + zeromem(global_variables.buffer_values, sizeof(GlobalVariables::Value) * global_variables.buffer_size); + global_variables.buffer_usage = memnew_arr(GlobalVariables::ValueUsage, global_variables.buffer_size); + global_variables.buffer_dirty_regions = memnew_arr(bool, global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE); + zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE); + global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size); + material_update_list = nullptr; { //create default textures @@ -4492,6 +5677,10 @@ RasterizerStorageRD::RasterizerStorageRD() { Vector<Vector<uint8_t>> vpv; vpv.push_back(pv); default_rd_textures[DEFAULT_RD_TEXTURE_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + + //take the chance and initialize decal atlas to something + decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + decal_atlas.texture_srgb = decal_atlas.texture; } for (int i = 0; i < 16; i++) { @@ -4644,14 +5833,14 @@ RasterizerStorageRD::RasterizerStorageRD() { sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.use_anisotropy = true; - sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy"); + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/quality/texture_filters/anisotropic_filtering_level")); } break; case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: { sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.use_anisotropy = true; - sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy"); + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/quality/texture_filters/anisotropic_filtering_level")); } break; default: { @@ -4683,9 +5872,11 @@ RasterizerStorageRD::RasterizerStorageRD() { //default rd buffers { - { //vertex + //vertex + { Vector<uint8_t> buffer; + buffer.resize(sizeof(float) * 3); { uint8_t *w = buffer.ptrw(); @@ -4803,6 +5994,11 @@ RasterizerStorageRD::RasterizerStorageRD() { RasterizerStorageRD::~RasterizerStorageRD() { + memdelete_arr(global_variables.buffer_values); + memdelete_arr(global_variables.buffer_usage); + memdelete_arr(global_variables.buffer_dirty_regions); + RD::get_singleton()->free(global_variables.buffer); + //def textures for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) { RD::get_singleton()->free(default_rd_textures[i]); @@ -4820,4 +6016,12 @@ RasterizerStorageRD::~RasterizerStorageRD() { RD::get_singleton()->free(mesh_default_rd_buffers[i]); } giprobe_sdf_shader.version_free(giprobe_sdf_shader_version); + + if (decal_atlas.textures.size()) { + ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas."); + } + + if (decal_atlas.texture.is_valid()) { + RD::get_singleton()->free(decal_atlas.texture); + } } diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index 49f77e49e1..f874c3baf8 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -52,6 +52,8 @@ public: virtual void set_code(const String &p_Code) = 0; virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0; virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0; + + virtual void get_instance_param_list(List<InstanceShaderParam> *p_param_list) const = 0; virtual bool is_param_texture(const StringName &p_param) const = 0; virtual bool is_animated() const = 0; virtual bool casts_shadows() const = 0; @@ -69,7 +71,15 @@ public: virtual void set_render_priority(int p_priority) = 0; virtual void set_next_pass(RID p_pass) = 0; virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0; - virtual ~MaterialData() {} + virtual ~MaterialData(); + + private: + friend class RasterizerStorageRD; + RID self; + List<RID>::Element *global_buffer_E = nullptr; + List<RID>::Element *global_texture_E = nullptr; + uint64_t global_textures_pass = 0; + Map<StringName, uint64_t> used_global_textures; }; typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *); @@ -173,6 +183,51 @@ private: RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX]; RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; + /* DECAL ATLAS */ + + struct DecalAtlas { + struct Texture { + + int panorama_to_dp_users; + int users; + Rect2 uv_rect; + }; + + struct SortItem { + RID texture; + Size2i pixel_size; + Size2i size; + Point2i pos; + + bool operator<(const SortItem &p_item) const { + //sort larger to smaller + if (size.height == p_item.size.height) { + return size.width > p_item.size.width; + } else { + return size.height > p_item.size.height; + } + } + }; + + HashMap<RID, Texture> textures; + bool dirty = true; + int mipmaps = 5; + + RID texture; + RID texture_srgb; + struct MipMap { + RID fb; + RID texture; + Size2i size; + }; + Vector<MipMap> texture_mipmaps; + + Size2i size; + + } decal_atlas; + + void _update_decal_atlas(); + /* SHADER */ struct Material; @@ -403,6 +458,28 @@ private: mutable RID_Owner<ReflectionProbe> reflection_probe_owner; + /* DECAL */ + + struct Decal { + + Vector3 extents = Vector3(1, 1, 1); + RID textures[RS::DECAL_TEXTURE_MAX]; + float emission_energy = 1.0; + float albedo_mix = 1.0; + Color modulate = Color(1, 1, 1, 1); + uint32_t cull_mask = (1 << 20) - 1; + float upper_fade = 0.3; + float lower_fade = 0.3; + bool distance_fade = false; + float distance_fade_begin = 10; + float distance_fade_length = 1; + float normal_fade = 0.0; + + RasterizerScene::InstanceDependency instance_dependency; + }; + + mutable RID_Owner<Decal> decal_owner; + /* GI PROBE */ struct GIProbe { @@ -463,13 +540,11 @@ private: bool flags[RENDER_TARGET_FLAG_MAX]; RID backbuffer; //used for effects - RID backbuffer_fb; + RID backbuffer_mipmap0; struct BackbufferMipmap { RID mipmap; - RID mipmap_fb; RID mipmap_copy; - RID mipmap_copy_fb; }; Vector<BackbufferMipmap> backbuffer_mipmaps; @@ -490,6 +565,73 @@ private: void _update_render_target(RenderTarget *rt); void _create_render_target_backbuffer(RenderTarget *rt); + /* GLOBAL SHADER VARIABLES */ + + struct GlobalVariables { + + enum { + BUFFER_DIRTY_REGION_SIZE = 1024 + }; + struct Variable { + Set<RID> texture_materials; // materials using this + + RS::GlobalVariableType type; + Variant value; + Variant override; + int32_t buffer_index; //for vectors + int32_t buffer_elements; //for vectors + }; + + HashMap<StringName, Variable> variables; + + struct Value { + float x; + float y; + float z; + float w; + }; + + struct ValueInt { + int32_t x; + int32_t y; + int32_t z; + int32_t w; + }; + + struct ValueUInt { + uint32_t x; + uint32_t y; + uint32_t z; + uint32_t w; + }; + + struct ValueUsage { + uint32_t elements = 0; + }; + + List<RID> materials_using_buffer; + List<RID> materials_using_texture; + + RID buffer; + Value *buffer_values; + ValueUsage *buffer_usage; + bool *buffer_dirty_regions; + uint32_t buffer_dirty_region_count = 0; + + uint32_t buffer_size; + + bool must_update_texture_materials = false; + bool must_update_buffer_materials = false; + + HashMap<RID, int32_t> instance_buffer_pos; + + } global_variables; + + int32_t _global_variable_allocate(uint32_t p_elements); + void _global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value); + void _global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements); + + void _update_global_variables(); /* EFFECTS */ RasterizerEffectsRD effects; @@ -535,6 +677,20 @@ public: virtual Size2 texture_size_with_proxy(RID p_proxy); + virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false); + virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false); + + RID decal_atlas_get_texture() const; + RID decal_atlas_get_texture_srgb() const; + _FORCE_INLINE_ Rect2 decal_atlas_get_texture_rect(RID p_texture) { + DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture); + if (!t) { + return Rect2(); + } + + return t->uv_rect; + } + //internal usage _FORCE_INLINE_ RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) { @@ -596,6 +752,8 @@ public: bool material_is_animated(RID p_material); bool material_casts_shadows(RID p_material); + void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters); + void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance); void material_force_update_textures(RID p_material, ShaderType p_shader_type); @@ -886,6 +1044,14 @@ public: return light->param[p_param]; } + _FORCE_INLINE_ RID light_get_projector(RID p_light) { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, RID()); + + return light->projector; + } + _FORCE_INLINE_ Color light_get_color(RID p_light) { const Light *light = light_owner.getornull(p_light); @@ -926,6 +1092,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; @@ -966,6 +1140,81 @@ public: void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); + /* DECAL API */ + + virtual RID decal_create(); + virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents); + virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture); + virtual void decal_set_emission_energy(RID p_decal, float p_energy); + virtual void decal_set_albedo_mix(RID p_decal, float p_mix); + virtual void decal_set_modulate(RID p_decal, const Color &p_modulate); + virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers); + virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length); + virtual void decal_set_fade(RID p_decal, float p_above, float p_below); + virtual void decal_set_normal_fade(RID p_decal, float p_fade); + + _FORCE_INLINE_ Vector3 decal_get_extents(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->extents; + } + + _FORCE_INLINE_ RID decal_get_texture(RID p_decal, RS::DecalTexture p_texture) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->textures[p_texture]; + } + + _FORCE_INLINE_ Color decal_get_modulate(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->modulate; + } + + _FORCE_INLINE_ float decal_get_emission_energy(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->emission_energy; + } + + _FORCE_INLINE_ float decal_get_albedo_mix(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->albedo_mix; + } + + _FORCE_INLINE_ uint32_t decal_get_cull_mask(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->cull_mask; + } + + _FORCE_INLINE_ float decal_get_upper_fade(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->upper_fade; + } + + _FORCE_INLINE_ float decal_get_lower_fade(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->lower_fade; + } + + _FORCE_INLINE_ float decal_get_normal_fade(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->normal_fade; + } + + _FORCE_INLINE_ bool decal_is_distance_fade_enabled(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->distance_fade; + } + + _FORCE_INLINE_ float decal_get_distance_fade_begin(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->distance_fade_begin; + } + + _FORCE_INLINE_ float decal_get_distance_fade_length(RID p_decal) { + const Decal *decal = decal_owner.getornull(p_decal); + return decal->distance_fade_length; + } + + virtual AABB decal_get_aabb(RID p_decal) const; + /* GI PROBE API */ RID gi_probe_create(); @@ -1076,6 +1325,27 @@ public: virtual bool particles_is_inactive(RID p_particles) const { return false; } + /* GLOBAL VARIABLES API */ + + virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value); + virtual void global_variable_remove(const StringName &p_name); + virtual Vector<StringName> global_variable_get_list() const; + + virtual void global_variable_set(const StringName &p_name, const Variant &p_value); + virtual void global_variable_set_override(const StringName &p_name, const Variant &p_value); + virtual Variant global_variable_get(const StringName &p_name) const; + virtual RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const; + RS::GlobalVariableType global_variable_get_type_internal(const StringName &p_name) const; + + virtual void global_variables_load_settings(bool p_load_textures = true); + virtual void global_variables_clear(); + + virtual int32_t global_variables_instance_allocate(RID p_instance); + virtual void global_variables_instance_free(RID p_instance); + virtual void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value); + + RID global_variables_get_storage_buffer() const; + /* RENDER TARGET API */ RID render_target_create(); @@ -1097,6 +1367,7 @@ public: Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); + RID render_target_get_rd_texture(RID p_render_target); RS::InstanceType get_base_type(RID p_rid) const; @@ -1124,7 +1395,7 @@ public: virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const; virtual String get_captured_timestamp_name(uint32_t p_index) const; - static RasterizerStorage *base_singleton; + static RasterizerStorageRD *base_singleton; RasterizerEffectsRD *get_effects(); diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp index 4a0b4f02b1..d4e6576125 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp @@ -32,6 +32,8 @@ #include "core/os/os.h" #include "core/project_settings.h" +#include "rasterizer_storage_rd.h" +#include "servers/rendering_server.h" #define SL ShaderLanguage @@ -91,6 +93,9 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; case SL::TYPE_STRUCT: return 0; + case SL::TYPE_MAX: { + ERR_FAIL_V(0); + }; } ERR_FAIL_V(0); @@ -131,6 +136,9 @@ static int _get_datatype_alignment(SL::DataType p_type) { case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; case SL::TYPE_STRUCT: return 0; + case SL::TYPE_MAX: { + ERR_FAIL_V(0); + } } ERR_FAIL_V(0); @@ -341,6 +349,71 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S } } +static String _get_global_variable_from_type_and_index(const String &p_buffer, const String &p_index, ShaderLanguage::DataType p_type) { + switch (p_type) { + case ShaderLanguage::TYPE_BOOL: { + return "(" + p_buffer + "[" + p_index + "].x != 0.0)"; + } + case ShaderLanguage::TYPE_BVEC2: { + return "(" + p_buffer + "[" + p_index + "].xy != vec2(0.0))"; + } + case ShaderLanguage::TYPE_BVEC3: { + return "(" + p_buffer + "[" + p_index + "].xyz != vec3(0.0))"; + } + case ShaderLanguage::TYPE_BVEC4: { + return "(" + p_buffer + "[" + p_index + "].xyzw != vec4(0.0))"; + } + case ShaderLanguage::TYPE_INT: { + return "floatBitsToInt(" + p_buffer + "[" + p_index + "].x)"; + } + case ShaderLanguage::TYPE_IVEC2: { + return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xy)"; + } + case ShaderLanguage::TYPE_IVEC3: { + return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xyz)"; + } + case ShaderLanguage::TYPE_IVEC4: { + return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xyzw)"; + } + case ShaderLanguage::TYPE_UINT: { + return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].x)"; + } + case ShaderLanguage::TYPE_UVEC2: { + return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xy)"; + } + case ShaderLanguage::TYPE_UVEC3: { + return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyz)"; + } + case ShaderLanguage::TYPE_UVEC4: { + return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyzw)"; + } + case ShaderLanguage::TYPE_FLOAT: { + return "(" + p_buffer + "[" + p_index + "].x)"; + } + case ShaderLanguage::TYPE_VEC2: { + return "(" + p_buffer + "[" + p_index + "].xy)"; + } + case ShaderLanguage::TYPE_VEC3: { + return "(" + p_buffer + "[" + p_index + "].xyz)"; + } + case ShaderLanguage::TYPE_VEC4: { + return "(" + p_buffer + "[" + p_index + "].xyzw)"; + } + case ShaderLanguage::TYPE_MAT2: { + return "mat2(" + p_buffer + "[" + p_index + "].xy," + p_buffer + "[" + p_index + "+1].xy)"; + } + case ShaderLanguage::TYPE_MAT3: { + return "mat3(" + p_buffer + "[" + p_index + "].xyz," + p_buffer + "[" + p_index + "+1].xyz," + p_buffer + "[" + p_index + "+2].xyz)"; + } + case ShaderLanguage::TYPE_MAT4: { + return "mat4(" + p_buffer + "[" + p_index + "].xyzw," + p_buffer + "[" + p_index + "+1].xyzw," + p_buffer + "[" + p_index + "+2].xyzw," + p_buffer + "[" + p_index + "+3].xyzw)"; + } + default: { + ERR_FAIL_V("void"); + } + } +} + String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) { String code; @@ -408,10 +481,17 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge int max_uniforms = 0; for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { - if (SL::is_sampler_type(E->get().type)) + + if (SL::is_sampler_type(E->get().type)) { max_texture_uniforms++; - else + } else { + + if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; //instances are indexed directly, dont need index uniforms + } + max_uniforms++; + } } r_gen_code.texture_uniforms.resize(max_texture_uniforms); @@ -428,12 +508,25 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge String ucode; + if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { + //insert, but don't generate any code. + p_actions.uniforms->insert(E->key(), E->get()); + continue; //instances are indexed directly, dont need index uniforms + } if (SL::is_sampler_type(E->get().type)) { ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform "; } - ucode += _prestr(E->get().precision); - ucode += _typestr(E->get().type); + bool is_buffer_global = !SL::is_sampler_type(E->get().type) && E->get().scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL; + + if (is_buffer_global) { + //this is an integer to index the global table + ucode += _typestr(ShaderLanguage::TYPE_UINT); + } else { + ucode += _prestr(E->get().precision); + ucode += _typestr(E->get().type); + } + ucode += " " + _mkid(E->key()); ucode += ";\n"; if (SL::is_sampler_type(E->get().type)) { @@ -446,6 +539,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge texture.type = E->get().type; texture.filter = E->get().filter; texture.repeat = E->get().repeat; + texture.global = E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL; + if (texture.global) { + r_gen_code.uses_global_textures = true; + } r_gen_code.texture_uniforms.write[E->get().texture_order] = texture; } else { @@ -455,8 +552,14 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uses_uniforms = true; } uniform_defines.write[E->get().order] = ucode; - uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type); - uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type); + if (is_buffer_global) { + //globals are indices into the global table + uniform_sizes.write[E->get().order] = _get_datatype_size(ShaderLanguage::TYPE_UINT); + uniform_alignments.write[E->get().order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT); + } else { + uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type); + uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type); + } } p_actions.uniforms->insert(E->key(), E->get()); @@ -547,18 +650,19 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge index++; } - for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) { + for (int i = 0; i < pnode->vconstants.size(); i++) { + const SL::ShaderNode::Constant &cnode = pnode->vconstants[i]; String gcode; gcode += "const "; - gcode += _prestr(E->get().precision); - if (E->get().type == SL::TYPE_STRUCT) { - gcode += _mkid(E->get().type_str); + gcode += _prestr(cnode.precision); + if (cnode.type == SL::TYPE_STRUCT) { + gcode += _mkid(cnode.type_str); } else { - gcode += _typestr(E->get().type); + gcode += _typestr(cnode.type); } - gcode += " " + _mkid(E->key()); + gcode += " " + _mkid(String(cnode.name)); gcode += "="; - gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + gcode += _dump_node_code(cnode.initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); gcode += ";\n"; r_gen_code.vertex_global += gcode; r_gen_code.fragment_global += gcode; @@ -690,9 +794,29 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (p_default_actions.renames.has(vnode->name)) code = p_default_actions.renames[vnode->name]; else { - code = _mkid(vnode->name); - if (actions.base_uniform_string != String() && shader->uniforms.has(vnode->name) && shader->uniforms[vnode->name].texture_order < 0) { - code = actions.base_uniform_string + code; + if (shader->uniforms.has(vnode->name)) { + //its a uniform! + const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[vnode->name]; + if (u.texture_order >= 0) { + code = _mkid(vnode->name); //texture, use as is + } else { + //a scalar or vector + if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { + code = actions.base_uniform_string + _mkid(vnode->name); //texture, use as is + //global variable, this means the code points to an index to the global table + code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type); + } else if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + //instance variable, index it as such + code = "(" + p_default_actions.instance_uniform_index_variable + "+" + itos(u.instance_index) + ")"; + code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type); + } else { + //regular uniform, index from UBO + code = actions.base_uniform_string + _mkid(vnode->name); + } + } + + } else { + code = _mkid(vnode->name); //its something else (local var most likely) use as is } } @@ -1037,9 +1161,14 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge return code; } +ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName &p_type) { + RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RasterizerStorage::base_singleton))->global_variable_get_type_internal(p_type); + return RS::global_variable_type_get_shader_datatype(gvt); +} + Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types()); + Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types(), _get_variable_type); if (err != OK) { @@ -1060,6 +1189,7 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide r_gen_code.light = String(); r_gen_code.uses_fragment_time = false; r_gen_code.uses_vertex_time = false; + r_gen_code.uses_global_textures = false; used_name_defines.clear(); used_rmode_defines.clear(); diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/rasterizer_rd/shader_compiler_rd.h index 7d78469e9c..16d53197a7 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.h +++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.h @@ -57,6 +57,7 @@ public: ShaderLanguage::ShaderNode::Uniform::Hint hint; ShaderLanguage::TextureFilter filter; ShaderLanguage::TextureRepeat repeat; + bool global; }; Vector<Texture> texture_uniforms; @@ -70,6 +71,7 @@ public: String fragment; String light; + bool uses_global_textures; bool uses_fragment_time; bool uses_vertex_time; }; @@ -86,6 +88,8 @@ public: int base_texture_binding_index = 0; int texture_layout_set = 0; String base_uniform_string; + String global_buffer_array_variable; + String instance_uniform_index_variable; uint32_t base_varying_index = 0; }; @@ -113,6 +117,8 @@ private: DefaultIdentifierActions actions; + static ShaderLanguage::DataType _get_variable_type(const StringName &p_type); + public: Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code); diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index 6e852e2dc5..a454d144aa 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -5,14 +5,15 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("canvas.glsl") env.RD_GLSL("canvas_occlusion.glsl") - env.RD_GLSL("blur.glsl") + env.RD_GLSL("copy.glsl") + env.RD_GLSL("copy_to_fb.glsl") env.RD_GLSL("cubemap_roughness.glsl") env.RD_GLSL("cubemap_downsampler.glsl") env.RD_GLSL("cubemap_filter.glsl") env.RD_GLSL("scene_high_end.glsl") env.RD_GLSL("sky.glsl") env.RD_GLSL("tonemap.glsl") - env.RD_GLSL("copy.glsl") + env.RD_GLSL("cube_to_dp.glsl") env.RD_GLSL("giprobe.glsl") env.RD_GLSL("giprobe_debug.glsl") env.RD_GLSL("giprobe_sdf.glsl") @@ -22,3 +23,8 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("ssao_minify.glsl") env.RD_GLSL("ssao_blur.glsl") env.RD_GLSL("roughness_limiter.glsl") + 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 deleted file mode 100644 index 87c20ebaef..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/blur.glsl +++ /dev/null @@ -1,294 +0,0 @@ -/* clang-format off */ -[vertex] - -#version 450 - -VERSION_DEFINES - -#include "blur_inc.glsl" - -layout(location = 0) out vec2 uv_interp; -/* clang-format on */ - -void main() { - - vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv_interp = base_arr[gl_VertexIndex]; - - if (bool(blur.flags & FLAG_USE_BLUR_SECTION)) { - uv_interp = blur.section.xy + uv_interp * blur.section.zw; - } - - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); - - if (bool(blur.flags & FLAG_FLIP_Y)) { - uv_interp.y = 1.0 - uv_interp.y; - } -} - -/* clang-format off */ -[fragment] - -#version 450 - -VERSION_DEFINES - -#include "blur_inc.glsl" - -layout(location = 0) in vec2 uv_interp; -/* clang-format on */ - -layout(set = 0, binding = 0) uniform sampler2D source_color; - -#ifdef MODE_SSAO_MERGE -layout(set = 1, binding = 0) uniform sampler2D source_ssao; -#endif - -#ifdef GLOW_USE_AUTO_EXPOSURE -layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; -#endif - -layout(location = 0) out vec4 frag_color; - -//DOF -#if defined(MODE_DOF_FAR_BLUR) || defined(MODE_DOF_NEAR_BLUR) - -layout(set = 1, binding = 0) uniform sampler2D dof_source_depth; - -#ifdef DOF_NEAR_BLUR_MERGE -layout(set = 2, binding = 0) uniform sampler2D source_dof_original; -#endif - -#ifdef DOF_QUALITY_LOW -const int dof_kernel_size = 5; -const int dof_kernel_from = 2; -const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); -#endif - -#ifdef DOF_QUALITY_MEDIUM -const int dof_kernel_size = 11; -const int dof_kernel_from = 5; -const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); - -#endif - -#ifdef DOF_QUALITY_HIGH -const int dof_kernel_size = 21; -const int dof_kernel_from = 10; -const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); -#endif - -#endif - -void main() { - -#ifdef MODE_MIPMAP - - vec2 pix_size = blur.pixel_size; - vec4 color = texture(source_color, uv_interp + vec2(-0.5, -0.5) * pix_size); - color += texture(source_color, uv_interp + vec2(0.5, -0.5) * pix_size); - color += texture(source_color, uv_interp + vec2(0.5, 0.5) * pix_size); - color += texture(source_color, uv_interp + vec2(-0.5, 0.5) * pix_size); - frag_color = color / 4.0; - -#endif - -#ifdef MODE_GAUSSIAN_BLUR - - //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect - - if (bool(blur.flags & FLAG_HORIZONTAL)) { - - vec2 pix_size = blur.pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607; - color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879; - color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514; - color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303; - color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879; - color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514; - color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303; - frag_color = color; - } else { - - vec2 pix_size = blur.pixel_size; - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774; - color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477; - color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136; - color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477; - color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136; - frag_color = color; - } -#endif - -#ifdef MODE_GAUSSIAN_GLOW - - //Glow uses larger sigma 1 for a more rounded blur effect - -#define GLOW_ADD(m_ofs, m_mult) \ - { \ - vec2 ofs = uv_interp + m_ofs * pix_size; \ - vec4 c = texture(source_color, ofs) * m_mult; \ - if (any(lessThan(ofs, vec2(0.0))) || any(greaterThan(ofs, vec2(1.0)))) { \ - c *= 0.0; \ - } \ - color += c; \ - } - - if (bool(blur.flags & FLAG_HORIZONTAL)) { - - vec2 pix_size = blur.pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938; - GLOW_ADD(vec2(1.0, 0.0), 0.165569); - GLOW_ADD(vec2(2.0, 0.0), 0.140367); - GLOW_ADD(vec2(3.0, 0.0), 0.106595); - GLOW_ADD(vec2(-1.0, 0.0), 0.165569); - GLOW_ADD(vec2(-2.0, 0.0), 0.140367); - GLOW_ADD(vec2(-3.0, 0.0), 0.106595); - color *= blur.glow_strength; - frag_color = color; - } else { - - vec2 pix_size = blur.pixel_size; - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713; - GLOW_ADD(vec2(0.0, 1.0), 0.233062); - GLOW_ADD(vec2(0.0, 2.0), 0.122581); - GLOW_ADD(vec2(0.0, -1.0), 0.233062); - GLOW_ADD(vec2(0.0, -2.0), 0.122581); - color *= blur.glow_strength; - frag_color = color; - } - -#undef GLOW_ADD - - if (bool(blur.flags & FLAG_GLOW_FIRST_PASS)) { -#ifdef GLOW_USE_AUTO_EXPOSURE - - frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey; -#endif - frag_color *= blur.glow_exposure; - - float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); - float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom); - - frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap)); - } - -#endif - -#ifdef MODE_DOF_FAR_BLUR - - vec4 color_accum = vec4(0.0); - - float depth = texture(dof_source_depth, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - 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)); - } - - float amount = smoothstep(blur.dof_begin, blur.dof_end, depth); - float k_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius; - - float tap_k = dof_kernel[i]; - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - - tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); - } - - float tap_amount = mix(smoothstep(blur.dof_begin, blur.dof_end, tap_depth), 1.0, int_ofs == 0); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k; - - k_accum += tap_k * tap_amount; - color_accum += tap_color * tap_amount; - } - - if (k_accum > 0.0) { - color_accum /= k_accum; - } - - frag_color = color_accum; ///k_accum; - -#endif - -#ifdef MODE_DOF_NEAR_BLUR - - vec4 color_accum = vec4(0.0); - - float max_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * blur.dof_radius; - float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from)); - - float tap_k = dof_kernel[i]; - - vec4 tap_color = texture(source_color, tap_uv, 0.0); - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - - tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); - } - float tap_amount = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) { - tap_color.a = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); - } - - max_accum = max(max_accum, tap_amount * ofs_influence); - - color_accum += tap_color * tap_k; - } - - color_accum.a = max(color_accum.a, sqrt(max_accum)); - -#ifdef DOF_NEAR_BLUR_MERGE - { - vec4 original = texture(source_dof_original, uv_interp, 0.0); - color_accum = mix(original, color_accum, color_accum.a); - } -#endif - - if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) { - frag_color = color_accum; - } -#endif - -#ifdef MODE_SIMPLE_COPY - vec4 color = texture(source_color, uv_interp, 0.0); - if (bool(blur.flags & FLAG_COPY_FORCE_LUMINANCE)) { - color.rgb = vec3(max(max(color.r, color.g), color.b)); - } - frag_color = color; -#endif - -#ifdef MODE_SSAO_MERGE - vec4 color = texture(source_color, uv_interp, 0.0); - float ssao = texture(source_ssao, uv_interp, 0.0).r; - frag_color = vec4(mix(color.rgb, color.rgb * mix(blur.ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); - -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl b/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl deleted file mode 100644 index 33ba9de7bb..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl +++ /dev/null @@ -1,35 +0,0 @@ -#define FLAG_HORIZONTAL (1 << 0) -#define FLAG_USE_BLUR_SECTION (1 << 1) -#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2) -#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3) -#define FLAG_GLOW_FIRST_PASS (1 << 4) -#define FLAG_FLIP_Y (1 << 5) -#define FLAG_COPY_FORCE_LUMINANCE (1 << 6) - -layout(push_constant, binding = 1, std430) uniform Blur { - vec4 section; - vec2 pixel_size; - uint flags; - uint pad; - // Glow. - float glow_strength; - float glow_bloom; - float glow_hdr_threshold; - float glow_hdr_scale; - float glow_exposure; - float glow_white; - float glow_luminance_cap; - float glow_auto_exposure_grey; - // DOF. - float dof_begin; - float dof_end; - float dof_radius; - float dof_pad; - - vec2 dof_dir; - float camera_z_far; - float camera_z_near; - - vec4 ssao_color; -} -blur; diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl index 1ac43480cd..a39866004b 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl @@ -132,6 +132,11 @@ layout(set = 2, binding = 6) uniform sampler shadow_sampler; #endif +layout(set = 2, binding = 7, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + /* SET3: Render Target Data */ #ifdef SCREEN_TEXTURE_USED diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index cbb9b546a3..2d7661f65f 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -1,86 +1,220 @@ /* clang-format off */ -[vertex] +[compute] #version 450 VERSION_DEFINES -layout(location = 0) out vec2 uv_interp; +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; /* clang-format on */ -void main() { +#define FLAG_HORIZONTAL (1 << 0) +#define FLAG_USE_BLUR_SECTION (1 << 1) +#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2) +#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3) +#define FLAG_GLOW_FIRST_PASS (1 << 4) +#define FLAG_FLIP_Y (1 << 5) +#define FLAG_FORCE_LUMINANCE (1 << 6) +#define FLAG_COPY_ALL_SOURCE (1 << 7) + +layout(push_constant, binding = 1, std430) uniform Params { + ivec4 section; + ivec2 target; + uint flags; + uint pad; + // Glow. + float glow_strength; + float glow_bloom; + float glow_hdr_threshold; + float glow_hdr_scale; + + float glow_exposure; + float glow_white; + float glow_luminance_cap; + float glow_auto_exposure_grey; + // DOF. + float camera_z_far; + float camera_z_near; + uint pad2[2]; +} +params; - vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv_interp = base_arr[gl_VertexIndex]; +layout(set = 0, binding = 0) uniform sampler2D source_color; - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); -} +#ifdef GLOW_USE_AUTO_EXPOSURE +layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; +#endif -/* clang-format off */ -[fragment] +#if defined(MODE_LINEARIZE_DEPTH_COPY) || defined(MODE_SIMPLE_COPY_DEPTH) +layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#elif defined(DST_IMAGE_8BIT) +layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#else +layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#endif -#version 450 +void main() { -VERSION_DEFINES + // Pixel being shaded + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pos, params.section.zw))) { //too large, do nothing + return; + } -layout(location = 0) in vec2 uv_interp; -/* clang-format on */ +#ifdef MODE_MIPMAP + + ivec2 base_pos = (pos + params.section.xy) << 1; + vec4 color = texelFetch(source_color, base_pos, 0); + color += texelFetch(source_color, base_pos + ivec2(0, 1), 0); + color += texelFetch(source_color, base_pos + ivec2(1, 0), 0); + color += texelFetch(source_color, base_pos + ivec2(1, 1), 0); + color /= 4.0; -#ifdef MODE_CUBE_TO_DP + imageStore(dest_buffer, pos + params.target, color); +#endif -layout(set = 0, binding = 0) uniform samplerCube source_cube; +#ifdef MODE_GAUSSIAN_BLUR -layout(push_constant, binding = 0, std430) uniform Params { - float bias; - float z_far; - float z_near; - bool z_flip; -} -params; + //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect -layout(location = 0) out float depth_buffer; + if (bool(params.flags & FLAG_HORIZONTAL)) { + ivec2 base_pos = (pos + params.section.xy) << 1; + vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.214607; + color += texelFetch(source_color, base_pos + ivec2(1, 0), 0) * 0.189879; + color += texelFetch(source_color, base_pos + ivec2(2, 0), 0) * 0.131514; + color += texelFetch(source_color, base_pos + ivec2(3, 0), 0) * 0.071303; + color += texelFetch(source_color, base_pos + ivec2(-1, 0), 0) * 0.189879; + color += texelFetch(source_color, base_pos + ivec2(-2, 0), 0) * 0.131514; + color += texelFetch(source_color, base_pos + ivec2(-3, 0), 0) * 0.071303; + imageStore(dest_buffer, pos + params.target, color); + } else { + + ivec2 base_pos = (pos + params.section.xy); + vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.38774; + color += texelFetch(source_color, base_pos + ivec2(0, 1), 0) * 0.24477; + color += texelFetch(source_color, base_pos + ivec2(0, 2), 0) * 0.06136; + color += texelFetch(source_color, base_pos + ivec2(0, -1), 0) * 0.24477; + color += texelFetch(source_color, base_pos + ivec2(0, -2), 0) * 0.06136; + imageStore(dest_buffer, pos + params.target, color); + } #endif -void main() { +#ifdef MODE_GAUSSIAN_GLOW -#ifdef MODE_CUBE_TO_DP + //Glow uses larger sigma 1 for a more rounded blur effect - vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0); +#define GLOW_ADD(m_ofs, m_mult) \ + { \ + ivec2 ofs = base_pos + m_ofs; \ + if (all(greaterThanEqual(ofs, section_begin)) && all(lessThan(ofs, section_end))) { \ + color += texelFetch(source_color, ofs, 0) * m_mult; \ + } \ + } + + vec4 color = vec4(0.0); + + if (bool(params.flags & FLAG_HORIZONTAL)) { + + ivec2 base_pos = (pos + params.section.xy) << 1; + ivec2 section_begin = params.section.xy << 1; + ivec2 section_end = section_begin + (params.section.zw << 1); + + GLOW_ADD(ivec2(0, 0), 0.174938); + GLOW_ADD(ivec2(1, 0), 0.165569); + GLOW_ADD(ivec2(2, 0), 0.140367); + GLOW_ADD(ivec2(3, 0), 0.106595); + GLOW_ADD(ivec2(-1, 0), 0.165569); + GLOW_ADD(ivec2(-2, 0), 0.140367); + GLOW_ADD(ivec2(-3, 0), 0.106595); + color *= params.glow_strength; + } else { - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - normal = normalize(normal); + ivec2 base_pos = pos + params.section.xy; + ivec2 section_begin = params.section.xy; + ivec2 section_end = section_begin + params.section.zw; - normal.y = -normal.y; //needs to be flipped to match projection matrix - if (!params.z_flip) { - normal.z = -normal.z; + GLOW_ADD(ivec2(0, 0), 0.288713); + GLOW_ADD(ivec2(0, 1), 0.233062); + GLOW_ADD(ivec2(0, 2), 0.122581); + GLOW_ADD(ivec2(0, -1), 0.233062); + GLOW_ADD(ivec2(0, -2), 0.122581); + color *= params.glow_strength; } - float depth = texture(source_cube, normal).r; +#undef GLOW_ADD - // absolute values for direction cosines, bigger value equals closer to basis axis - vec3 unorm = abs(normal); + if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { +#ifdef GLOW_USE_AUTO_EXPOSURE + + color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.glow_auto_exposure_grey; +#endif + color *= params.glow_exposure; + + float luminance = max(color.r, max(color.g, color.b)); + float feedback = max(smoothstep(params.glow_hdr_threshold, params.glow_hdr_threshold + params.glow_hdr_scale, luminance), params.glow_bloom); + + color = min(color * feedback, vec4(params.glow_luminance_cap)); + } + + imageStore(dest_buffer, pos + params.target, color); + +#endif + +#ifdef MODE_SIMPLE_COPY + + vec4 color; + if (bool(params.flags & FLAG_COPY_ALL_SOURCE)) { + vec2 uv = vec2(pos) / vec2(params.section.zw); + if (bool(params.flags & FLAG_FLIP_Y)) { + uv.y = 1.0 - uv.y; + } + color = textureLod(source_color, uv, 0.0); + + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + imageStore(dest_buffer, pos + params.target, color); - if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { - // x code - unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); - } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { - // y code - unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); - } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { - // z code - unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); } else { - // oh-no we messed up code - // has to be - unorm = vec3(1.0, 0.0, 0.0); + color = texelFetch(source_color, pos + params.section.xy, 0); + + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } + + imageStore(dest_buffer, pos + params.target, color); + } + +#endif + +#ifdef MODE_SIMPLE_COPY_DEPTH + + vec4 color = texelFetch(source_color, pos + params.section.xy, 0); + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; } - float depth_fix = 1.0 / dot(normal, unorm); + imageStore(dest_buffer, pos + params.target, vec4(color.r)); + +#endif + +#ifdef MODE_LINEARIZE_DEPTH_COPY + + float depth = texelFetch(source_color, pos + params.section.xy, 0).r; + depth = depth * 2.0 - 1.0; + 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)); + vec4 color = vec4(depth / params.camera_z_far); - 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; + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } + imageStore(dest_buffer, pos + params.target, color); #endif } diff --git a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl new file mode 100644 index 0000000000..07f8d09743 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl @@ -0,0 +1,104 @@ +/* clang-format off */ +[vertex] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) out vec2 uv_interp; +/* clang-format on */ + +layout(push_constant, binding = 1, std430) uniform Params { + vec4 section; + vec2 pixel_size; + bool flip_y; + bool use_section; + + bool force_luminance; + uint pad[3]; +} +params; + +void main() { + + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp = base_arr[gl_VertexIndex]; + + vec2 vpos = uv_interp; + if (params.use_section) { + vpos = params.section.xy + vpos * params.section.zw; + } + + gl_Position = vec4(vpos * 2.0 - 1.0, 0.0, 1.0); + + if (params.flip_y) { + uv_interp.y = 1.0 - uv_interp.y; + } +} + +/* clang-format off */ +[fragment] + +#version 450 + +VERSION_DEFINES + +layout(push_constant, binding = 1, std430) uniform Params { + vec4 section; + vec2 pixel_size; + bool flip_y; + bool use_section; + + bool force_luminance; + bool alpha_to_zero; + uint pad[2]; +} params; + + +layout(location = 0) in vec2 uv_interp; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform sampler2D source_color; + +layout(location = 0) out vec4 frag_color; + +void main() { + + vec2 uv = uv_interp; + +#ifdef MODE_PANORAMA_TO_DP + + //obtain normal from dual paraboloid uv +#define M_PI 3.14159265359 + + float side; + uv.y = modf(uv.y * 2.0, side); + side = side * 2.0 - 1.0; + vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); + normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + normal *= -side; + normal = normalize(normal); + + //now convert normal to panorama uv + + vec2 st = vec2(atan(normal.x, normal.z), acos(normal.y)); + + if (st.x < 0.0) + st.x += M_PI * 2.0; + + uv = st / vec2(M_PI * 2.0, M_PI); + + if (side < 0.0) { + //uv.y = 1.0 - uv.y; + uv = 1.0 - uv; + } +#endif + vec4 color = textureLod(source_color, uv, 0.0); + if (params.force_luminance) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + if (params.alpha_to_zero) { + color.rgb *= color.a; + } + frag_color = color; +} diff --git a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl new file mode 100644 index 0000000000..02ebe1a53b --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl @@ -0,0 +1,72 @@ +/* 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 */ + +layout(set = 0, binding = 0) uniform samplerCube source_cube; + +layout(push_constant, binding = 1, std430) uniform Params { + ivec2 screen_size; + ivec2 offset; + float bias; + float z_far; + float z_near; + bool z_flip; +} +params; + +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D depth_buffer; + +void main() { + + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pos, params.screen_size))) { //too large, do nothing + return; + } + + vec2 pixel_size = 1.0 / vec2(params.screen_size); + vec2 uv = (vec2(pos) + 0.5) * pixel_size; + + vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); + + normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + + normal.y = -normal.y; //needs to be flipped to match projection matrix + if (!params.z_flip) { + normal.z = -normal.z; + } + + float depth = texture(source_cube, normal).r; + + // absolute values for direction cosines, bigger value equals closer to basis axis + vec3 unorm = abs(normal); + + if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { + // x code + unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); + } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { + // y code + unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); + } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { + // z code + unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); + } else { + // oh-no we messed up code + // has to be + unorm = vec3(1.0, 0.0, 0.0); + } + + float depth_fix = 1.0 / dot(normal, unorm); + + 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 = (linear_depth * depth_fix) / params.z_far; + + imageStore(depth_buffer, pos + params.offset, vec4(depth)); +} diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 07f4770b14..ec47887036 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -20,9 +20,7 @@ layout(location = 2) in vec4 tangent_attrib; layout(location = 3) in vec4 color_attrib; #endif -#if defined(UV_USED) layout(location = 4) in vec2 uv_attrib; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 5) in vec2 uv2_attrib; @@ -39,9 +37,7 @@ layout(location = 1) out vec3 normal_interp; layout(location = 2) out vec4 color_interp; #endif -#if defined(UV_USED) layout(location = 3) out vec2 uv_interp; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) out vec2 uv2_interp; @@ -157,9 +153,7 @@ void main() { #endif } -#if defined(UV_USED) uv_interp = uv_attrib; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; @@ -244,19 +238,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 +255,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 */ @@ -288,9 +284,7 @@ layout(location = 1) in vec3 normal_interp; layout(location = 2) in vec4 color_interp; #endif -#if defined(UV_USED) layout(location = 3) in vec2 uv_interp; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) in vec2 uv2_interp; @@ -315,6 +309,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 +433,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 +473,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 +483,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 +544,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 +600,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 +620,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 +651,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 +665,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 +678,121 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS -float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { +// Produces cheap but low-quality white noise, nothing special +float quick_hash(vec2 pos) { + return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237); +} + +float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { - //todo optimize vec2 pos = coord.xy; float depth = coord.z; -#ifdef SHADOW_MODE_PCF_13 + //if only one sample is taken, take it from the center + if (scene_data.directional_soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.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 + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } -#ifdef SHADOW_MODE_PCF_5 + float avg = 0.0; - 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); + for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0)); + } -#endif + return avg * (1.0 / float(scene_data.directional_soft_shadow_samples)); +} -#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) +float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + vec2 pos = coord.xy; + float depth = coord.z; -#endif + //if only one sample is taken, take it from the center + if (scene_data.soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + + for (uint i = 0; i < scene_data.soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0)); + } + + return avg * (1.0 / float(scene_data.soft_shadow_samples)); +} + +float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { + + //find blocker + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { + + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * 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; + } + } + + 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.directional_penumbra_shadow_samples; i++) { + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; + s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0)); + } + + return s / float(scene_data.directional_penumbra_shadow_samples); + + } 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, +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_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, #endif #ifdef LIGHT_RIM_USED float rim, float rim_tint, @@ -707,45 +813,269 @@ 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 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = 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 * lights.data[idx].soft_shadow_scale; + bitangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; + + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; + + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.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; + } + } - clamp_rect.y += clamp_rect.w; + 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.penumbra_shadow_samples; i++) { + + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.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.penumbra_shadow_samples); + + } 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_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); + } + +#ifdef LIGHT_TRANSMITTANCE_USED + { + + vec4 clamp_rect = lights.data[idx].atlas_rect; + + //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.xyz); + splane = normalize(splane.xyz); + + 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 + + vec3 no_shadow = vec3(1.0); + + if (lights.data[idx].projector_rect != vec4(0.0)) { + + vec3 local_v = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; + local_v = normalize(local_v); + + vec4 atlas_rect = lights.data[idx].projector_rect; + + if (local_v.z >= 0.0) { + + local_v.z += 1.0; + atlas_rect.y += atlas_rect.w; + + } else { + + local_v.z = 1.0 - local_v.z; + } + + local_v.xy /= local_v.z; + local_v.xy = local_v.xy * 0.5 + 0.5; + vec2 proj_uv = local_v.xy * atlas_rect.zw; + + vec2 proj_uv_ddx; + vec2 proj_uv_ddy; + { + vec3 local_v_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; + local_v_ddx = normalize(local_v_ddx); + + if (local_v_ddx.z >= 0.0) { + + local_v_ddx.z += 1.0; + } else { + + local_v_ddx.z = 1.0 - local_v_ddx.z; + } + + local_v_ddx.xy /= local_v_ddx.z; + local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; + + proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; + + vec3 local_v_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; + local_v_ddy = normalize(local_v_ddy); + + if (local_v_ddy.z >= 0.0) { + + local_v_ddy.z += 1.0; + } else { - 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); + local_v_ddy.z = 1.0 - local_v_ddy.z; + } + + local_v_ddy.xy /= local_v_ddy.z; + local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; + + proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; + } + + vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); + no_shadow = mix(no_shadow, proj.rgb, proj.a); + } - light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, 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, @@ -763,9 +1093,15 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a specular_light); } -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, +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_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, #endif #ifdef LIGHT_RIM_USED float rim, float rim_tint, @@ -792,31 +1128,162 @@ 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 + + vec2 shadow_uv = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy; + + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale; + vec2 clamp_max = lights.data[idx].atlas_rect.xy + lights.data[idx].atlas_rect.zw; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max); + 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.penumbra_shadow_samples; i++) { + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max); + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); + } + + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + + } else { + //hard shadow + vec4 shadow_uv = vec4(splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy, z_norm, 1.0); + + shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); + } + + vec3 no_shadow = vec3(1.0); + + if (lights.data[idx].projector_rect != vec4(0.0)) { + + splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); + splane /= splane.w; + + vec2 proj_uv = splane.xy * lights.data[idx].projector_rect.zw; + + //ensure we have proper mipmaps + vec4 splane_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)); + splane_ddx /= splane_ddx.w; + vec2 proj_uv_ddx = splane_ddx.xy * lights.data[idx].projector_rect.zw - proj_uv; + + vec4 splane_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)); + splane_ddy /= splane_ddy.w; + vec2 proj_uv_ddy = splane_ddy.xy * lights.data[idx].projector_rect.zw - proj_uv; + + vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy); + no_shadow = mix(no_shadow, proj.rgb, proj.a); + } + + shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow); + +#ifdef LIGHT_TRANSMITTANCE_USED + { + + splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); + splane /= splane.w; + splane.xy = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy; + + 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 +1652,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); @@ -1223,9 +1694,7 @@ void main() { } #endif -#if defined(UV_USED) vec2 uv = uv_interp; -#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) vec2 uv2 = uv2_interp; @@ -1254,6 +1723,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) @@ -1299,7 +1776,81 @@ FRAGMENT_SHADER_CODE discard; } #endif + /////////////////////// DECALS //////////////////////////////// + +#ifndef MODE_RENDER_DEPTH + + uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near))); + //used for interpolating anything cluster related + vec3 vertex_ddx = dFdx(vertex); + vec3 vertex_ddy = dFdy(vertex); + + { // process decals + + uint decal_count = cluster_cell.w >> CLUSTER_COUNTER_SHIFT; + uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK; + + //do outside for performance and avoiding arctifacts + + for (uint i = 0; i < decal_count; i++) { + + uint decal_index = cluster_data.indices[decal_pointer + i]; + if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; + if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { + continue; //out of decal + } + + //we need ddx/ddy for mipmaps, so simulate them + vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; + vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; + + float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + + if (decals.data[decal_index].normal_fade > 0.0) { + fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); + } + + if (decals.data[decal_index].albedo_rect != vec4(0.0)) { + //has albedo + vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); + decal_albedo *= decals.data[decal_index].modulate; + decal_albedo.a *= fade; + albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); + + if (decals.data[decal_index].normal_rect != vec4(0.0)) { + + vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; + decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software + decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); + //convert to view space, use xzy because y is up + decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; + + normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + } + + if (decals.data[decal_index].orm_rect != vec4(0.0)) { + + vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; +#if defined(AO_USED) + ao = mix(ao, decal_orm.r, decal_albedo.a); +#endif + roughness = mix(roughness, decal_orm.g, decal_albedo.a); + metallic = mix(metallic, decal_orm.b, decal_albedo.a); + } + } + + if (decals.data[decal_index].emission_rect != vec4(0.0)) { + //emission is additive, so its independent from albedo + emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + } + } + } +#endif //not render depth /////////////////////// LIGHTING ////////////////////////////// //apply energy conservation @@ -1404,8 +1955,6 @@ FRAGMENT_SHADER_CODE } #endif - uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near))); - { // process reflections vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); @@ -1462,58 +2011,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 * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, 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 * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, 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 * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, 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); - float shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, 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; + + 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 * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, 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 * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, 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 * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, 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, @@ -1545,9 +2286,15 @@ FRAGMENT_SHADER_CODE continue; //not masked } - light_process_omni(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - transmission, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED rim, @@ -1578,9 +2325,15 @@ FRAGMENT_SHADER_CODE continue; //not masked } - light_process_spot(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity, -#ifdef LIGHT_TRANSMISSION_USED - transmission, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, +#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 +2450,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..ce4fabf9f2 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl @@ -37,13 +37,23 @@ 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 pad; + + //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted + vec4 directional_penumbra_shadow_kernel[32]; + vec4 directional_soft_shadow_kernel[32]; + vec4 penumbra_shadow_kernel[32]; + vec4 soft_shadow_kernel[32]; + + uint directional_penumbra_shadow_samples; + uint directional_soft_shadow_samples; + uint penumbra_shadow_samples; + uint soft_shadow_samples; + vec4 ambient_light_color_energy; float ambient_color_sky_mix; @@ -124,31 +134,39 @@ struct InstanceData { mat4 transform; mat4 normal_transform; uint flags; - uint instance_ofs; //instance_offset in instancing/skeleton buffer + uint instance_uniforms_ofs; //base offset in global buffer for instance variables uint gi_offset; //GI information when using lightmapping (VCT or lightmap) uint layer_mask; }; -layout(set = 0, binding = 4, std430) buffer Instances { +layout(set = 0, binding = 4, std430) restrict readonly buffer Instances { InstanceData data[]; } 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; // rect in the shadow atlas 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 + float soft_shadow_scale; // scales the shadow kernel for blurrier shadows + uint mask; + uint pad[2]; + vec4 projector_rect; //projector rect in srgb decal atlas }; -layout(set = 0, binding = 5, std140) uniform Lights { - LightData data[MAX_LIGHT_DATA_STRUCTS]; +layout(set = 0, binding = 5, std430) restrict readonly buffer Lights { + LightData data[]; } lights; @@ -173,18 +191,33 @@ struct DirectionalLightData { vec3 direction; float energy; vec3 color; + float size; float specular; - vec3 shadow_color; uint mask; + float softshadow_angle; + float soft_shadow_scale; 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 { @@ -219,14 +252,45 @@ layout(set = 0, binding = 9) uniform texture3D gi_probe_textures[MAX_GI_PROBE_TE #define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1) #define CLUSTER_COUNTER_MASK 0xfff -layout(set = 0, binding = 10) uniform utexture3D cluster_texture; +layout(set = 0, binding = 10) uniform texture2D decal_atlas; +layout(set = 0, binding = 11) uniform texture2D decal_atlas_srgb; + +struct DecalData { + mat4 xform; //to decal transform + vec3 inv_extents; + float albedo_mix; + vec4 albedo_rect; + vec4 normal_rect; + vec4 orm_rect; + vec4 emission_rect; + vec4 modulate; + float emission_energy; + uint mask; + float upper_fade; + float lower_fade; + mat3x4 normal_xform; + vec3 normal; + float normal_fade; +}; + +layout(set = 0, binding = 12, std430) restrict readonly buffer Decals { + DecalData data[]; +} +decals; + +layout(set = 0, binding = 13) uniform utexture3D cluster_texture; -layout(set = 0, binding = 11, std430) buffer ClusterData { +layout(set = 0, binding = 14, std430) restrict readonly buffer ClusterData { uint indices[]; } cluster_data; -layout(set = 0, binding = 12) uniform texture2D directional_shadow_atlas; +layout(set = 0, binding = 15) uniform texture2D directional_shadow_atlas; + +layout(set = 0, binding = 16, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; // decal atlas @@ -258,7 +322,7 @@ layout(set = 3, binding = 4) uniform texture2D ao_buffer; /* Set 4 Skeleton & Instancing (Multimesh) */ -layout(set = 4, binding = 0, std430) buffer Transforms { +layout(set = 4, binding = 0, std430) restrict readonly buffer Transforms { vec4 data[]; } transforms; diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl new file mode 100644 index 0000000000..e3c26c9b72 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl @@ -0,0 +1,262 @@ +/* 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 */ + +layout(rgba16f, set = 0, binding = 0) uniform restrict readonly image2D source_diffuse; +layout(r32f, set = 0, binding = 1) uniform restrict readonly image2D source_depth; +layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D ssr_image; +#ifdef MODE_ROUGH +layout(r8, set = 1, binding = 1) uniform restrict writeonly image2D blur_radius_image; +#endif +layout(rgba8, set = 2, binding = 0) uniform restrict readonly image2D source_normal; +layout(set = 3, binding = 0) uniform sampler2D source_metallic; +#ifdef MODE_ROUGH +layout(set = 3, binding = 1) uniform sampler2D source_roughness; +#endif + +layout(push_constant, binding = 2, std430) uniform Params { + + vec4 proj_info; + + ivec2 screen_size; + float camera_z_near; + float camera_z_far; + + int num_steps; + float depth_tolerance; + float distance_fade; + float curve_fade_in; + + bool orthogonal; + float filter_mipmap_levels; + bool use_half_res; + uint metallic_mask; + + mat4 projection; +} +params; + +vec2 view_to_screen(vec3 view_pos, out float w) { + vec4 projected = params.projection * vec4(view_pos, 1.0); + projected.xyz /= projected.w; + projected.xy = projected.xy * 0.5 + 0.5; + w = projected.w; + return projected.xy; +} + +#define M_PI 3.14159265359 + +vec3 reconstructCSPosition(vec2 S, float z) { + if (params.orthogonal) { + return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z); + } else { + return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z); + } +} + +void main() { + + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + + if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing + return; + } + + vec2 pixel_size = 1.0 / vec2(params.screen_size); + vec2 uv = vec2(ssC) * pixel_size; + + uv += pixel_size * 0.5; + + float base_depth = imageLoad(source_depth, ssC).r; + + // World space point being shaded + vec3 vertex = reconstructCSPosition(uv * vec2(params.screen_size), base_depth); + + vec3 normal = imageLoad(source_normal, ssC).xyz * 2.0 - 1.0; + normal = normalize(normal); + normal.y = -normal.y; //because this code reads flipped + + vec3 view_dir = normalize(vertex); + vec3 ray_dir = normalize(reflect(view_dir, normal)); + + if (dot(ray_dir, normal) < 0.001) { + imageStore(ssr_image, ssC, vec4(0.0)); + return; + } + //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0); + //ray_dir = normalize(vec3(1.0, 1.0, -1.0)); + + //////////////// + + // make ray length and clip it against the near plane (don't want to trace beyond visible) + float ray_len = (vertex.z + ray_dir.z * params.camera_z_far) > -params.camera_z_near ? (-params.camera_z_near - vertex.z) / ray_dir.z : params.camera_z_far; + vec3 ray_end = vertex + ray_dir * ray_len; + + float w_begin; + vec2 vp_line_begin = view_to_screen(vertex, w_begin); + float w_end; + vec2 vp_line_end = view_to_screen(ray_end, w_end); + vec2 vp_line_dir = vp_line_end - vp_line_begin; + + // we need to interpolate w along the ray, to generate perspective correct reflections + w_begin = 1.0 / w_begin; + w_end = 1.0 / w_end; + + float z_begin = vertex.z * w_begin; + float z_end = ray_end.z * w_end; + + vec2 line_begin = vp_line_begin / pixel_size; + vec2 line_dir = vp_line_dir / pixel_size; + float z_dir = z_end - z_begin; + float w_dir = w_end - w_begin; + + // clip the line to the viewport edges + + float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x)); + float scale_max_y = min(1.0, 0.99 * (1.0 - vp_line_begin.y) / max(1e-5, vp_line_dir.y)); + float scale_min_x = min(1.0, 0.99 * vp_line_begin.x / max(1e-5, -vp_line_dir.x)); + float scale_min_y = min(1.0, 0.99 * vp_line_begin.y / max(1e-5, -vp_line_dir.y)); + float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y); + line_dir *= line_clip; + z_dir *= line_clip; + w_dir *= line_clip; + + // clip z and w advance to line advance + vec2 line_advance = normalize(line_dir); // down to pixel + float step_size = length(line_advance) / length(line_dir); + float z_advance = z_dir * step_size; // adapt z advance to line advance + float w_advance = w_dir * step_size; // adapt w advance to line advance + + // make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice) + float advance_angle_adj = 1.0 / max(abs(line_advance.x), abs(line_advance.y)); + line_advance *= advance_angle_adj; // adapt z advance to line advance + z_advance *= advance_angle_adj; + w_advance *= advance_angle_adj; + + vec2 pos = line_begin; + float z = z_begin; + float w = w_begin; + float z_from = z / w; + float z_to = z_from; + float depth; + vec2 prev_pos = pos; + + bool found = false; + + float steps_taken = 0.0; + + for (int i = 0; i < params.num_steps; i++) { + + pos += line_advance; + z += z_advance; + w += w_advance; + + // convert to linear depth + + depth = imageLoad(source_depth, ivec2(pos - 0.5)).r; + + if (-depth >= params.camera_z_far) { //went beyond camera + break; + } + + z_from = z_to; + z_to = z / w; + + if (depth > z_to) { + // if depth was surpassed + if (depth <= max(z_to, z_from) + params.depth_tolerance) { + // check the depth tolerance + //check that normal is valid + found = true; + } + break; + } + + steps_taken += 1.0; + prev_pos = pos; + } + + if (found) { + + float margin_blend = 1.0; + + vec2 margin = vec2((params.screen_size.x + params.screen_size.y) * 0.5 * 0.05); // make a uniform margin + if (any(bvec4(lessThan(pos, -margin), greaterThan(pos, params.screen_size + margin)))) { + // clip outside screen + margin + imageStore(ssr_image, ssC, vec4(0.0)); + return; + } + + { + //blend fading out towards external margin + vec2 margin_grad = mix(pos - params.screen_size, -pos, lessThan(pos, vec2(0.0))); + margin_blend = 1.0 - smoothstep(0.0, margin.x, max(margin_grad.x, margin_grad.y)); + //margin_blend = 1.0; + } + + vec2 final_pos; + float grad; + grad = steps_taken / float(params.num_steps); + float initial_fade = params.curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), params.curve_fade_in); + float fade = pow(clamp(1.0 - grad, 0.0, 1.0), params.distance_fade) * initial_fade; + final_pos = pos; + + vec4 final_color; + +#ifdef MODE_ROUGH + + // if roughness is enabled, do screen space cone tracing + float blur_radius = 0.0; + float roughness = texelFetch(source_roughness, ssC << 1, 0).r; + + if (roughness > 0.001) { + + float cone_angle = min(roughness, 0.999) * M_PI * 0.5; + float cone_len = length(final_pos - line_begin); + float op_len = 2.0 * tan(cone_angle) * cone_len; // opposite side of iso triangle + { + // fit to sphere inside cone (sphere ends at end of cone), something like this: + // ___ + // \O/ + // V + // + // as it avoids bleeding from beyond the reflection as much as possible. As a plus + // it also makes the rough reflection more elongated. + float a = op_len; + float h = cone_len; + float a2 = a * a; + float fh2 = 4.0f * h * h; + blur_radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h); + } + } + + final_color = imageLoad(source_diffuse, ivec2((final_pos - 0.5) * pixel_size)); + + imageStore(blur_radius_image, ssC, vec4(blur_radius / 255.0)); //stored in r8 + +#endif + + final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb, fade * margin_blend); + //change blend by metallic + vec4 metallic_mask = unpackUnorm4x8(params.metallic_mask); + final_color.a *= dot(metallic_mask, texelFetch(source_metallic, ssC << 1, 0)); + + imageStore(ssr_image, ssC, final_color); + + } else { +#ifdef MODE_ROUGH + imageStore(blur_radius_image, ssC, vec4(0.0)); +#endif + imageStore(ssr_image, ssC, vec4(0.0)); + } +} diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl new file mode 100644 index 0000000000..1a5dd5ab55 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl @@ -0,0 +1,164 @@ +/* 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 */ + +layout(rgba16f, set = 0, binding = 0) uniform restrict readonly image2D source_ssr; +layout(r8, set = 0, binding = 1) uniform restrict readonly image2D source_radius; +layout(rgba8, set = 1, binding = 0) uniform restrict readonly image2D source_normal; + +layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_ssr; +#ifndef VERTICAL_PASS +layout(r8, set = 2, binding = 1) uniform restrict writeonly image2D dest_radius; +#endif +layout(r32f, set = 3, binding = 0) uniform restrict readonly image2D source_depth; + +layout(push_constant, binding = 2, std430) uniform Params { + + vec4 proj_info; + + bool orthogonal; + float edge_tolerance; + int increment; + uint pad; + + ivec2 screen_size; + bool vertical; + uint steps; +} +params; + +#define GAUSS_TABLE_SIZE 15 + +const float gauss_table[GAUSS_TABLE_SIZE + 1] = float[]( + 0.1847392078702266, + 0.16595854345772326, + 0.12031364177766891, + 0.07038755277896766, + 0.03322925565155569, + 0.012657819729901945, + 0.0038903040680094217, + 0.0009646503390864025, + 0.00019297087402915717, + 0.000031139936308099136, + 0.000004053309048174758, + 4.255228059965837e-7, + 3.602517634249573e-8, + 2.4592560765896795e-9, + 1.3534945386863618e-10, + 0.0 //one more for interpolation +); + +float gauss_weight(float p_val) { + + float idxf; + float c = modf(max(0.0, p_val * float(GAUSS_TABLE_SIZE)), idxf); + int idx = int(idxf); + if (idx >= GAUSS_TABLE_SIZE + 1) { + return 0.0; + } + + return mix(gauss_table[idx], gauss_table[idx + 1], c); +} + +#define M_PI 3.14159265359 + +vec3 reconstructCSPosition(vec2 S, float z) { + if (params.orthogonal) { + return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z); + } else { + return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z); + } +} + +void do_filter(inout vec4 accum, inout float accum_radius, inout float divisor, ivec2 texcoord, ivec2 increment, vec3 p_pos, vec3 normal, float p_limit_radius) { + + for (int i = 1; i < params.steps; i++) { + float d = float(i * params.increment); + ivec2 tc = texcoord + increment * i; + float depth = imageLoad(source_depth, tc).r; + vec3 view_pos = reconstructCSPosition(vec2(tc) + 0.5, depth); + vec3 view_normal = normalize(imageLoad(source_normal, tc).rgb * 2.0 - 1.0); + view_normal.y = -view_normal.y; + + float r = imageLoad(source_radius, tc).r; + float radius = round(r * 255.0); + + float angle_n = 1.0 - abs(dot(normal, view_normal)); + if (angle_n > params.edge_tolerance) { + break; + } + + float angle = abs(dot(normal, normalize(view_pos - p_pos))); + + if (angle > params.edge_tolerance) { + break; + } + + if (d < radius) { + + float w = gauss_weight(d / radius); + accum += imageLoad(source_ssr, tc) * w; +#ifndef VERTICAL_PASS + accum_radius += r * w; +#endif + 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; + } + + float base_contrib = gauss_table[0]; + + vec4 accum = imageLoad(source_ssr, ssC); + + float accum_radius = imageLoad(source_radius, ssC).r; + float radius = accum_radius * 255.0; + + float divisor = gauss_table[0]; + accum *= divisor; + accum_radius *= divisor; +#ifdef VERTICAL_PASS + ivec2 direction = ivec2(0, params.increment); +#else + ivec2 direction = ivec2(params.increment, 0); +#endif + float depth = imageLoad(source_depth, ssC).r; + vec3 pos = reconstructCSPosition(vec2(ssC) + 0.5, depth); + vec3 normal = imageLoad(source_normal, ssC).xyz * 2.0 - 1.0; + normal = normalize(normal); + normal.y = -normal.y; + + do_filter(accum, accum_radius, divisor, ssC, direction, pos, normal, radius); + do_filter(accum, accum_radius, divisor, ssC, -direction, pos, normal, radius); + + if (divisor > 0.0) { + accum /= divisor; + accum_radius /= divisor; + } else { + accum = vec4(0.0); + accum_radius = 0.0; + } + + imageStore(dest_ssr, ssC, accum); + +#ifndef VERTICAL_PASS + imageStore(dest_radius, ssC, vec4(accum_radius)); +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl new file mode 100644 index 0000000000..cec6c14c76 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl @@ -0,0 +1,96 @@ +/* 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 */ + +layout(set = 0, binding = 0) uniform sampler2D source_ssr; +layout(set = 1, binding = 0) uniform sampler2D source_depth; +layout(set = 1, binding = 1) uniform sampler2D source_normal; +layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_ssr; +layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_depth; +layout(rgba8, set = 3, binding = 1) uniform restrict writeonly image2D dest_normal; + +layout(push_constant, binding = 1, std430) uniform Params { + + ivec2 screen_size; + float camera_z_near; + float camera_z_far; + + bool orthogonal; + bool filtered; + uint pad[2]; +} +params; + +void main() { + + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + + if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing + return; + } + //do not filter, SSR will generate arctifacts if this is done + + float divisor = 0.0; + vec4 color; + float depth; + vec3 normal; + + if (params.filtered) { + + color = vec4(0.0); + depth = 0.0; + normal = vec3(0.0); + + for (int i = 0; i < 4; i++) { + + ivec2 ofs = ssC << 1; + if (bool(i & 1)) { + ofs.x += 1; + } + if (bool(i & 2)) { + ofs.y += 1; + } + color += texelFetch(source_ssr, ofs, 0); + float d = texelFetch(source_depth, ofs, 0).r; + normal += texelFetch(source_normal, ofs, 0).xyz * 2.0 - 1.0; + + d = d * 2.0 - 1.0; + if (params.orthogonal) { + d = ((d + (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; + } else { + d = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - d * (params.camera_z_far - params.camera_z_near)); + } + depth += -d; + } + + color /= 4.0; + depth /= 4.0; + normal = normalize(normal / 4.0) * 0.5 + 0.5; + + } else { + color = texelFetch(source_ssr, ssC << 1, 0); + depth = texelFetch(source_depth, ssC << 1, 0).r; + normal = texelFetch(source_normal, ssC << 1, 0).xyz; + + depth = depth * 2.0 - 1.0; + 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; + } 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 = -depth; + } + + imageStore(dest_ssr, ssC, color); + imageStore(dest_depth, ssC, vec4(depth)); + imageStore(dest_normal, ssC, vec4(normal, 0.0)); +} diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl index 3f433eb2ee..536077980d 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl @@ -58,6 +58,11 @@ params; layout(set = 0, binding = 0) uniform sampler material_samplers[12]; +layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + #ifdef USE_MATERIAL_UNIFORMS layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ /* clang-format off */ @@ -96,9 +101,8 @@ layout(set = 2, binding = 2) uniform texture2D quarter_res; #endif struct DirectionalLightData { - vec3 direction; - float energy; - vec3 color; + vec4 direction_energy; + vec4 color_size; bool enabled; }; @@ -141,15 +145,15 @@ void main() { vec4 quarter_res_color = vec4(1.0); #ifdef USE_CUBEMAP_PASS - float using_cubemap = 1.0; + vec3 inverted_cube_normal = cube_normal; + inverted_cube_normal.z *= -1.0; #ifdef USES_HALF_RES_COLOR - half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal); + half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal); #endif #ifdef USES_QUARTER_RES_COLOR - quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal); + quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal); #endif #else - float using_cubemap = 0.0; #ifdef USES_HALF_RES_COLOR half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0); #endif @@ -178,4 +182,10 @@ FRAGMENT_SHADER_CODE frag_color.rgb = color * params.position_multiplier.w; frag_color.a = alpha; + + // Blending is disabled for Sky, so alpha doesn't blend + // alpha is used for subsurface scattering so make sure it doesn't get applied to Sky + if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) { + frag_color.a = 0.0; + } } diff --git a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl b/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl new file mode 100644 index 0000000000..b24f7dccc7 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl @@ -0,0 +1,59 @@ +/* clang-format off */ +[vertex] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) out vec2 uv_interp; +/* clang-format on */ + +void main() { + + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp = base_arr[gl_VertexIndex]; + + gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); +} + +/* clang-format off */ +[fragment] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) in vec2 uv_interp; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform sampler2D specular; + +#ifdef MODE_SSR + +layout(set = 1, binding = 0) uniform sampler2D ssr; + +#endif + +#ifdef MODE_MERGE + +layout(set = 2, binding = 0) uniform sampler2D diffuse; + +#endif + +layout(location = 0) out vec4 frag_color; + +void main() { + + frag_color.rgb = texture(specular, uv_interp).rgb; + frag_color.a = 0.0; +#ifdef MODE_SSR + + vec4 ssr_color = texture(ssr, uv_interp); + frag_color.rgb = mix(frag_color.rgb, ssr_color.rgb, ssr_color.a); +#endif + +#ifdef MODE_MERGE + frag_color += texture(diffuse, uv_interp); +#endif + //added using additive blend +} 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/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl index 524ca5e2ea..a142d263e2 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl @@ -48,6 +48,10 @@ layout(push_constant, binding = 1, std430) uniform Params { float exposure; float white; float auto_exposure_grey; + + vec2 pixel_size; + bool use_fxaa; + uint pad; } params; @@ -255,16 +259,63 @@ vec3 apply_color_correction(vec3 color, sampler3D correction_tex) { return texture(correction_tex, color).rgb; } +vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { + + const float FXAA_REDUCE_MIN = (1.0 / 128.0); + const float FXAA_REDUCE_MUL = (1.0 / 8.0); + const float FXAA_SPAN_MAX = 8.0; + + vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbM = color; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), + FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * + params.pixel_size; + + vec3 rgbA = 0.5 * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz * exposure + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * exposure; + vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz * exposure + + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz * exposure); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + return rgbA; + else + return rgbB; +} + void main() { vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; // Exposure + float exposure = params.exposure; + if (params.use_auto_exposure) { - color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey; + exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey); } - color *= params.exposure; + color *= exposure; // Early Tonemap & SRGB Conversion @@ -274,6 +325,9 @@ void main() { color.rgb = mix(color.rgb, glow, params.glow_intensity); } + if (params.use_fxaa) { + color = do_fxaa(color, exposure, uv_interp); + } color = apply_tonemapping(color, params.white); color = linear_to_srgb(color); // regular linear -> SRGB conversion |