From 62a5cd90a7804ce063d30514c3753b7934f1ffec Mon Sep 17 00:00:00 2001 From: Apples <2352020+apples@users.noreply.github.com> Date: Fri, 27 Jun 2025 06:26:39 -0500 Subject: [PATCH] Fix opaque stencil rendering --- drivers/gles3/rasterizer_scene_gles3.cpp | 4 +--- .../scene_shader_forward_clustered.cpp | 5 +++-- .../scene_shader_forward_clustered.h | 2 +- .../forward_mobile/render_forward_mobile.cpp | 13 ++++++++++++- .../forward_mobile/render_forward_mobile.h | 18 ++++++++++++++++++ .../scene_shader_forward_mobile.h | 2 +- 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index d04142dea18..0b4ac0ee55d 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2529,7 +2529,6 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ scene_state.set_gl_depth_func(GL_GEQUAL); scene_state.enable_gl_scissor_test(false); scene_state.enable_gl_stencil_test(false); - scene_state.set_gl_stencil_write_mask(255); glColorMask(0, 0, 0, 0); RasterizerGLES3::clear_depth(0.0); @@ -3084,7 +3083,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } // Stencil. - if (shader->stencil_enabled) { + if (p_pass_mode != PASS_MODE_DEPTH && shader->stencil_enabled) { static const GLenum stencil_compare_table[GLES3::SceneShaderData::STENCIL_COMPARE_MAX] = { GL_LESS, GL_EQUAL, @@ -3121,7 +3120,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, scene_state.set_gl_stencil_op(GL_KEEP, stencil_op_dpfail, stencil_op_dppass); } else { scene_state.enable_gl_stencil_test(false); - scene_state.set_gl_stencil_write_mask(255); } if constexpr (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) { diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 80178f3664e..8154f6ab51d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -359,8 +359,9 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip } } - depth_stencil_state.enable_stencil = stencil_enabled; - if (stencil_enabled) { + bool use_stencil = stencil_enabled && p_pipeline_key.version == PIPELINE_VERSION_COLOR_PASS; + depth_stencil_state.enable_stencil = use_stencil; + if (use_stencil) { static const RD::CompareOperator stencil_compare_rd_table[STENCIL_COMPARE_MAX] = { RD::COMPARE_OP_LESS, RD::COMPARE_OP_EQUAL, diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index e646916a7fd..d2a771ca3e5 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -293,7 +293,7 @@ public: _FORCE_INLINE_ bool uses_shared_shadow_material() const { bool backface_culling = cull_mode == RS::CULL_MODE_BACK; - return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_position && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && backface_culling && !uses_point_size && !uses_world_coordinates && !wireframe && !uses_z_clip_scale; + return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_position && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && backface_culling && !uses_point_size && !uses_world_coordinates && !wireframe && !uses_z_clip_scale && !stencil_enabled; } virtual void set_code(const String &p_Code); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index e00e0294186..5106db267c3 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -889,7 +889,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color // fill our render lists early so we can find out if we use various features _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); - render_list[RENDER_LIST_OPAQUE].sort_by_key(); + if (scene_state.used_opaque_stencil) { + render_list[RENDER_LIST_OPAQUE].sort_by_key_and_stencil(); + } else { + render_list[RENDER_LIST_OPAQUE].sort_by_key(); + } render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority(); _fill_instance_data(RENDER_LIST_OPAQUE); _fill_instance_data(RENDER_LIST_ALPHA); @@ -2149,6 +2153,9 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { scene_state.used_depth_texture = true; } + if ((surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_STENCIL) && !force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) { + scene_state.used_opaque_stencil = true; + } } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) { if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { @@ -2672,6 +2679,10 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; } + if (p_material->shader_data->stencil_enabled) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_STENCIL; + } + if (p_material->shader_data->uses_alpha_pass()) { flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; if (p_material->shader_data->uses_depth_in_alpha_pass()) { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 5aa536c7df6..8f6142f51ae 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -289,6 +289,7 @@ private: bool used_screen_texture = false; bool used_depth_texture = false; bool used_lightmap = false; + bool used_opaque_stencil = false; struct ShadowPass { uint32_t element_from; @@ -338,6 +339,22 @@ private: sorter.sort(elements.ptr() + p_from, p_size); } + struct SortByKeyAndStencil { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + bool a_stencil = A->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_STENCIL; + bool b_stencil = B->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_STENCIL; + if (a_stencil != b_stencil) { + return a_stencil < b_stencil; + } + return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2); + } + }; + + void sort_by_key_and_stencil() { + SortArray sorter; + sorter.sort(elements.ptr(), elements.size()); + } + struct SortByDepth { _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { return (A->owner->depth < B->owner->depth); @@ -448,6 +465,7 @@ protected: FLAG_USES_NORMAL_TEXTURE = 16384, FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, FLAG_USES_PARTICLE_TRAILS = 65536, + FLAG_USES_STENCIL = 131072, }; union { diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index ac0f8973278..98ab09a1629 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -290,7 +290,7 @@ public: } _FORCE_INLINE_ bool uses_shared_shadow_material() const { - return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && !uses_world_coordinates && !wireframe; + return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && !uses_world_coordinates && !wireframe && !stencil_enabled; } virtual void set_code(const String &p_Code);