Jump to content

[1.15.2] World Render Transparency Issue


nanorover59

Recommended Posts

Hello!

While working on a mod that renders some blocks in the world using a render class called by a RenderWorldLastEvent (my "sub-world" project), I noticed that the objects I am rendering are not visible behind semi-transparent blocks. These include stained glass, water, nether portal blocks, etc... but not blocks with full transparency like regular glass blocks. My render code (posted below) does not activate or deactivate any effects to do with transparency, and I am wondering if that is what I need to add to make this work properly.

Spoiler

public void render(MatrixStack matrixStack, DimensionType dimension, float partialTicks)
	{
		if(!data.isDataValid())
			return;
		
		MinecraftServer server = minecraft.getIntegratedServer();
		World world = DimensionManager.getWorld(server, dimension, false, false);

		// Get the projected view coordinates.
		Vec3d projectedView = minecraft.gameRenderer.getActiveRenderInfo().getProjectedView();

		matrixStack.push();

		matrixStack.translate(-projectedView.x + data.centerX + data.translationX, -projectedView.y + data.centerY + data.translationY, -projectedView.z + data.centerZ + data.translationZ);	
		matrixStack.rotate(new Quaternion((float) data.rotationX, (float) data.rotationY, (float) data.rotationZ, false));
		matrixStack.scale((float) data.scale, (float) data.scale, (float) data.scale);	
		matrixStack.translate(-data.centerX, -data.centerY, -data.centerZ);

		Impl renderTypeBuffer = IRenderTypeBuffer.getImpl(Tessellator.getInstance().getBuffer());

		int i = OverlayTexture.NO_OVERLAY;

		// Render all normal block models.
		for(RenderType renderType : RenderType.getBlockRenderTypes())
		{
			for(BlockRenderData blockRenderData : blockRenderMap.get(renderType))
			{
				BlockPos pos = blockRenderData.getBlockPos();
				BlockState blockState = blockRenderData.getBlockState();

				matrixStack.push();
				matrixStack.translate(pos.getX(), pos.getY(), pos.getZ());
				blockRenderer.renderModel(world, blockRenderData, matrixStack, renderTypeBuffer.getBuffer(renderType), new Random(), blockState.getPositionRandom(pos), i);
				matrixStack.pop();
			}
		}
		
		// Render all TERs.
		for(TileEntity tileEntity : world.loadedTileEntityList)
		{
			BlockPos pos = tileEntity.getPos();
			matrixStack.push();
			matrixStack.translate(pos.getX(), pos.getY(), pos.getZ());
			blockRenderer.renderTileEntity(tileEntity, partialTicks, matrixStack, renderTypeBuffer);
			matrixStack.pop();
		}
		
		renderTypeBuffer.finish();

		matrixStack.pop();
	}

 

 

Here is a screenshot of the rendering problem:

S1bCaUL.png

Link to comment
Share on other sites

Howdy

Rendering of translucent objects is quite difficult because it is important to render the faces in the correct order.

 

Normally, with opaque faces, it is straightforward because you can draw the faces in any order you like.  When OpenGL draws a face, it checks the z-buffer to see whether the face is behind any other faces which are already in the scene.

 

With translucent faces, this straight-forward approach doesn't work because the drawing order is important.  Drawing face A then blending face B over the top of it gives a different appearance to drawing face B then blending face A over the top of B.  For this reason, minecraft sorts translucent faces so that the ones which are furthest away are rendered first.  You can see this by browsing through WorldRenderer::renderBlockLayer.  I think (but haven't confirmed) that translucent faces still write to the depth buffer.

 

It looks to me like, because you are rendering in last event which is after the translucent blocks have been rendered, your faces are being hidden behind the translucent faces, which have written to the depth buffer and will hence obscure anything that is behind them.

This doesn't happen for some "transparent" textures like glass, because these use cutout textures not alpha blending.  I.e. each pixel is either fully opaque, or fully transparent and doesn't write to the depth buffer.

 

I don't know of an easy way to fix this, unfortunately.  The most robust way to fix it is to render your blocks earlier, i.e. before renderBlockLayer is called in updateCameraAndRender.  Perhaps a TileEntityRenderer might be the easiest way.

 

-TGG

 

  • Like 1
Link to comment
Share on other sites

5 hours ago, Rikka0_0 said:

Can you render your blocks in the Solid or Cutout layer?

The render code iterates through all of the layers to render blocks. I should also note that there have been no problems rendering translucent blocks that are part of sub-worlds, the problem is translucent blocks in the main world blocking sub-worlds from rendering.

 

7 hours ago, TheGreyGhost said:

The most robust way to fix it is to render your blocks earlier, i.e. before renderBlockLayer is called in updateCameraAndRender.

If there was an event very similar to RenderWorldLastEvent except it is called before renderBlockLayer (essentially a "RenderWorldFirstEvent") I would use that instead. After looking at the vanilla render code, I have not found any events that would allow me to run my render code before renderBlockLayer.

Edited by nanorover59
Link to comment
Share on other sites

2 hours ago, nanorover59 said:

If there was an event very similar to RenderWorldLastEvent except it is called before renderBlockLayer (essentially a "RenderWorldFirstEvent") I would use that instead. After looking at the vanilla render code, I have not found any events that would allow me to run my render code before renderBlockLayer.

You could consider putting in a feature request to Forge to add an event at the appropriate place in updateCameraAndRender (or even better - fork the Forge source, add the event yourself, and submit a pull request).  Or find another way to ensure that your code gets called at the right time; eg ensure that your miniworld is always associated with a TileEntity and TileEntityRenderer.

 

Just a note -

renderBlockLayer is called in several places, and you only need to ensure you have drawn before the call to the translucent renderBlockLayer, i.e. this one

iprofiler.endStartSection("translucent"); 

this.renderBlockLayer(RenderType.getTranslucent(), matrixStackIn, d0, d1, d2);

So you might have some success with DrawHighlightEvent for example

 

-TGG

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.