Merge pull request #108044 from apples/107935-stencil-fixes

Fix opaque stencil rendering
This commit is contained in:
Thaddeus Crews 2025-07-31 10:39:08 -05:00
commit 5787f6fb6a
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
6 changed files with 36 additions and 8 deletions

View file

@ -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,

View file

@ -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);

View file

@ -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()) {

View file

@ -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<GeometryInstanceSurfaceDataCache *, SortByKeyAndStencil> 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 {

View file

@ -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);