@@ -64,13 +64,6 @@ public class BlockRenderer {
6464
6565 private final int [] quadColors = new int [4 ];
6666
67- /**
68- * Tracks whether the MC-138211 quad reorienting fix should be applied during emission of quad geometry.
69- * This fix must be disabled with certain modded models that use superimposed quads, as it can alter the triangulation
70- * of some layers but not others, resulting in Z-fighting.
71- */
72- private boolean useReorienting ;
73-
7467 /**
7568 * The list of registered custom block renderers. These may augment or fully bypass the model system for the
7669 * block.
@@ -81,7 +74,37 @@ public class BlockRenderer {
8174
8275 private final ChunkColorWriter colorEncoder = ChunkColorWriter .get ();
8376
84- private final boolean useRenderPassOptimization ;
77+ /**
78+ * If {@code true}, the {@link #QUAD_RENDER_PASS_OPTIMIZATION} flag will be enabled.
79+ */
80+ private final boolean enableRenderPassOptimization ;
81+
82+ /**
83+ * No changes should be applied when rendering quads.
84+ */
85+ private static final int QUAD_FLAGS_NONE = 0x0 ;
86+ /**
87+ * If specified, the MC-138211 quad reorienting fix should be applied during emission of quad geometry.
88+ * This fix must be disabled with certain modded models that use superimposed quads, as it can alter the triangulation
89+ * of some layers but not others, resulting in Z-fighting.
90+ */
91+ private static final int QUAD_REORIENTING = 0x1 ;
92+ /**
93+ * If specified, quads will be placed in differing render passes than what is specified. This can help avoid
94+ * GPU bottlenecks by running the fragment shader on pixels which aren't visible anyway.
95+ * @see <a href="https://www.khronos.org/opengl/wiki/Early_Fragment_Test">Early Fragment Test</a>
96+ */
97+ private static final int QUAD_RENDER_PASS_OPTIMIZATION = 0x2 ;
98+ /**
99+ * If specified, all changes should be applied when rendering quads.
100+ */
101+ private static final int QUAD_FLAGS_ALL = QUAD_REORIENTING | QUAD_RENDER_PASS_OPTIMIZATION ;
102+
103+ /**
104+ * Quad flags used to control how quads are emitted/rendered.
105+ * These take the values of the {@code QUAD_} constants specified in this class.
106+ */
107+ private int quadRenderingFlags = QUAD_FLAGS_NONE ;
85108
86109 public BlockRenderer (ColorProviderRegistry colorRegistry , LightPipelineProvider lighters ) {
87110 this .colorProviderRegistry = colorRegistry ;
@@ -90,7 +113,7 @@ public BlockRenderer(ColorProviderRegistry colorRegistry, LightPipelineProvider
90113 this .occlusionCache = new BlockOcclusionCache ();
91114 this .useAmbientOcclusion = Minecraft .useAmbientOcclusion ();
92115 this .fabricModelRenderingHandler = FRAPIRenderHandler .INDIGO_PRESENT ? new IndigoBlockRenderContext (this .occlusionCache , lighters .getLightData ()) : null ;
93- this .useRenderPassOptimization = Embeddium .options ().performance .useRenderPassOptimization && !ShaderModBridge .areShadersEnabled ();
116+ this .enableRenderPassOptimization = Embeddium .options ().performance .useRenderPassOptimization && !ShaderModBridge .areShadersEnabled ();
94117 }
95118
96119 /**
@@ -137,26 +160,22 @@ public void renderModel(BlockRenderContext ctx, ChunkBuildBuffers buffers) {
137160 return ;
138161 }
139162
140- boolean canReorientNullCullface = true ;
163+ var nullCullfaceFlags = QUAD_FLAGS_ALL ;
141164
142165 for (Direction face : DirectionUtil .ALL_DIRECTIONS ) {
143166 List <BakedQuad > quads = this .getGeometry (ctx , face );
144167
145168 if (!quads .isEmpty () && this .isFaceVisible (ctx , face )) {
146- this .useReorienting = true ;
169+ this .quadRenderingFlags = QUAD_FLAGS_ALL ;
147170 this .renderQuadList (ctx , material , lighter , colorizer , renderOffset , buffers , meshBuilder , quads , face );
148- if (!this .useReorienting ) {
149- // Reorienting was disabled on this side, make sure it's disabled for the null cullface too, in case
150- // a mod layers textures in different lists
151- canReorientNullCullface = false ;
152- }
171+ nullCullfaceFlags &= this .quadRenderingFlags ;
153172 }
154173 }
155174
156175 List <BakedQuad > all = this .getGeometry (ctx , null );
157176
158177 if (!all .isEmpty ()) {
159- this .useReorienting = canReorientNullCullface ;
178+ this .quadRenderingFlags = nullCullfaceFlags ;
160179 this .renderQuadList (ctx , material , lighter , colorizer , renderOffset , buffers , meshBuilder , all , null );
161180 }
162181 }
@@ -186,32 +205,54 @@ private static int computeLightFlagMask(BakedQuad quad) {
186205 return flag ;
187206 }
188207
189- /**
190- * {@return true if all quads in the given list use similar enough lighting configuration that reorientation is
191- * unlikely to lead to z-fighting}
192- */
193- private static boolean checkQuadsHaveSameLightingConfig (List <BakedQuad > quads ) {
208+ private SpriteTransparencyLevel getQuadTransparencyLevel (BakedQuadView quad ) {
209+ if ((quad .getFlags () & ModelQuadFlags .IS_PASS_OPTIMIZABLE ) == 0 || quad .getSprite () == null ) {
210+ return SpriteTransparencyLevel .TRANSLUCENT ;
211+ }
212+
213+ return SpriteTransparencyLevelHolder .getTransparencyLevel (quad .getSprite ());
214+ }
215+
216+ private void checkQuadsHaveSameLightingConfig (List <BakedQuad > quads ) {
194217 int quadsSize = quads .size ();
195218
196219 // By definition, singleton or empty lists of quads have a common lighting config. Only check larger lists
197220 if (quadsSize >= 2 ) {
198221 int flagMask = -1 ;
222+
223+ var highestSeenLevel = SpriteTransparencyLevel .OPAQUE ;
224+
199225 // noinspection ForLoopReplaceableByForEach
200226 for (int i = 0 ; i < quadsSize ; i ++) {
201- int newFlag = computeLightFlagMask (quads .get (i ));
227+ var quad = quads .get (i );
228+ int newFlag = computeLightFlagMask (quad );
202229 if (flagMask == -1 ) {
203230 flagMask = newFlag ;
204231 } else if (newFlag != flagMask ) {
205- return false ;
232+ this .quadRenderingFlags &= ~QUAD_REORIENTING ;
233+ }
234+
235+ var seenLevel = getQuadTransparencyLevel ((BakedQuadView )quad );
236+
237+ if (seenLevel .ordinal () < highestSeenLevel .ordinal ()) {
238+ this .quadRenderingFlags &= ~QUAD_RENDER_PASS_OPTIMIZATION ;
239+ } else {
240+ highestSeenLevel = seenLevel ;
206241 }
207242 }
208243 }
209244
210- return true ;
245+ if (!this .enableRenderPassOptimization ) {
246+ this .quadRenderingFlags &= ~QUAD_RENDER_PASS_OPTIMIZATION ;
247+ }
211248 }
212249
213250 private ChunkModelBuilder chooseOptimalBuilder (Material defaultMaterial , ChunkBuildBuffers buffers , ChunkModelBuilder defaultBuilder , BakedQuadView quad ) {
214- if (defaultMaterial == DefaultMaterials .SOLID || !this .useRenderPassOptimization || (quad .getFlags () & ModelQuadFlags .IS_TRUSTED_SPRITE ) == 0 || quad .getSprite () == null ) {
251+ if (defaultMaterial == DefaultMaterials .SOLID ||
252+ ((this .quadRenderingFlags & QUAD_RENDER_PASS_OPTIMIZATION ) == 0 ) ||
253+ (quad .getFlags () & ModelQuadFlags .IS_PASS_OPTIMIZABLE ) == 0 ||
254+ quad .getSprite () == null ) {
255+
215256 // No improvement possible
216257 return defaultBuilder ;
217258 }
@@ -233,11 +274,7 @@ private ChunkModelBuilder chooseOptimalBuilder(Material defaultMaterial, ChunkBu
233274 private void renderQuadList (BlockRenderContext ctx , Material material , LightPipeline lighter , ColorProvider <BlockState > colorizer , Vec3 offset ,
234275 ChunkBuildBuffers buffers , ChunkModelBuilder defaultBuilder , List <BakedQuad > quads , Direction cullFace ) {
235276
236- if (!checkQuadsHaveSameLightingConfig (quads )) {
237- // Disable reorienting if quads use different light configurations, as otherwise layered quads
238- // may be triangulated differently from others in the stack, and that will cause z-fighting.
239- this .useReorienting = false ;
240- }
277+ checkQuadsHaveSameLightingConfig (quads );
241278
242279 // This is a very hot allocation, iterate over it manually
243280 // noinspection ForLoopReplaceableByForEach
@@ -290,7 +327,7 @@ private void writeGeometry(BlockRenderContext ctx,
290327 int [] colors ,
291328 QuadLightData light )
292329 {
293- ModelQuadOrientation orientation = this .useReorienting ? ModelQuadOrientation .orientByBrightness (light .br , light .lm ) : ModelQuadOrientation .NORMAL ;
330+ ModelQuadOrientation orientation = (( this .quadRenderingFlags & QUAD_REORIENTING ) != 0 ) ? ModelQuadOrientation .orientByBrightness (light .br , light .lm ) : ModelQuadOrientation .NORMAL ;
294331 var vertices = this .vertices ;
295332
296333 ModelQuadFacing normalFace = quad .getNormalFace ();
0 commit comments