Jump to content

[1.16.5] Render lines to world


Silverminer

Recommended Posts

Hello,

this is my first post, so please be considerate of errors

The whole code is on my github too: https://github.com/Silverminer007/Shrines/blob/experimental/src/main/java/com/silverminer/shrines/events/ClientEvents.java

So, i want to draw boxes to the world which don't depent on any block/tileentity in the world. I've written a method that should draw the lines. I'm calling it from RenderWorldLastEvent event. Here is my code:

public static void renderBounds(MatrixStack ms) {
			// Enable depth test first
			RenderSystem.depthMask(false);

			// Get Minecraft and store it locally for multiple use
			Minecraft mc = Minecraft.getInstance();

			// Get dimension to draw only bounds of the correct dimension
			RegistryKey<World> dim;
			if (mc.level != null) {
				dim = mc.level.dimension();
			} else {
				dim = null;
			}

			// This doesn't work in both ways. What's the correct / working way to do that?
			RenderSystem.lineWidth(30.0f);

			// Translate coordinates from players system to world system
			Vector3d vec = mc.gameRenderer.getMainCamera().getPosition();
			double renderPosX = vec.x();
			double renderPosY = vec.y();
			double renderPosZ = vec.z();
			ms.pushPose();
			ms.translate(-renderPosX, -renderPosY, -renderPosZ);

			// Get vertex builder
			IRenderTypeBuffer irendertypebuffer1 = mc.renderBuffers().bufferSource();
			IVertexBuilder vb = irendertypebuffer1.getBuffer(RenderType.lines());

			// Color of the bound (White)
			Color c = new Color(Utils.properties.bound_color);
			// Split up in red, green and blue and transform it to 0.0 - 1.0
			float red = c.getRed() / 255.0f;
			float green = c.getGreen() / 255.0f;
			float blue = c.getBlue() / 255.0f;

			// Iterate over all bounds to draw
			for (CustomStructureData data : Utils.DATAS_FROM_SERVER) {
				for (ResourceData rd : data.PIECES_ON_FLY) {
					if (rd.getDimension() == dim) {
						MutableBoundingBox mbb = rd.getBounds();
						// Drawing a line box as in StructureTileEntityRenderer#render
						WorldRenderer.renderLineBox(ms, vb, mbb.x0, mbb.y0, mbb.z0, mbb.x1, mbb.y1, mbb.z1, red, green,
								blue, 1.0f, red, green, blue);
					}
				}
			}
			ms.popPose();
		}

The lines were drawn, but are in the wrong color (Dark Green/Black instead of White) until the inventory is opened. After opening they turn white. The lines are also moving while flying, sprinting and bobbing. Looks like i've missed something, but what?
I've tested to call my method from DrawHighlightEvent.HighlightBlock and suprisingly everything worked fine! I've searched in vanilla code and saw, DrawHighlightEvent.HighlightBlock is called in WorldRenderer#renderLevel and RenderWorldLastEvent from GameRenderer#render. GameRenderer calls first WorldRenderer#renderLevel and then DrawHighlightEvent.HighlightBlock is fired, so something seems to change inside #renderLevel. I think it's MatrixStack, because it's the only parameter i use from RenderWorldLastEvent and DrawHighlightEvent.HighlightBlock. It could also be any variable from Minecraft Instance, but i'm not sure how to check that.


In the image, you see two boxes, one from DrawHighlightEvent.HighlightBlock(the inner white) and one from RenderWorldLastEvent(The outer)

 

Does anyone have an idea how to fix or what to check?

Thanks for all the help in advance

2021-05-18_12.31.35.png

Link to comment
Share on other sites

2 hours ago, Silverminer said:

The lines are also moving while flying, sprinting and bobbing. Looks like i've missed something, but what?

Doing these things moves the camera.

Your code subtracts the camera's position value from the MatrixStack.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

I just need to translate the matrixstack back to the world coordinates. How should i do it instead? Were is the difference between the MatrixStacks of the two events?
To me it looks like Minecraft does some translations in #renderLevel, but i can see which ones.  Am i wrong?
Is the translation using render entities position and partial ticks better?

Or is the translation completly useless?

Link to comment
Share on other sites

Translation matrix stuff is annoyingly complex to figure out what's not working correctly. All I know is that the symptom you mention is a result of always rendering at 0,0,0 relative to the camera, as opposed to relative to a block in the world, the way the DrawHighlightEvent.HighlightBlock event works.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

EDIT: I'm wrong.

 

On 5/18/2021 at 11:39 AM, Silverminer said:

The lines are also moving while flying, sprinting and bobbing.

These days, instead of manually interpolating between tick positions, there's a method Entity#getPosition(float), which returns an interpolated Vector3d. That is the vector which you should use to translate the MatrixStack back to world-space, from entity-space. Passing the last matrix pose in as a parameter to IVertexBuilder#vertex(Matrix4f, float, float, float) will transform from camera-space to entity-space (while using IVertexBuilder#vertex(float, float, float) operates in camera-space).

Here is an example of rendering a translucent white quad near the world origin.

Spoiler

@EventBusSubscriber(Dist.CLIENT)
public class SpellRenderEventSubscriber
{
	@SubscribeEvent
	public static void worldRender(RenderWorldLastEvent event)
	{
		IRenderTypeBuffer.Impl buffer = Minecraft.getInstance().renderBuffers().bufferSource();
		IVertexBuilder builder = buffer.getBuffer(SpellRender.QUADS); //SpellRender.QUADS is a personal RenderType, of VertexFormat POSITION_COLOR.
		
		MatrixStack stack = event.getMatrixStack();
		
		stack.pushPose();
		
		Vector3d player = Minecraft.getInstance().player.getPosition(event.getPartialTicks());
		stack.translate(-player.x, -player.y, -player.z);
		
		Matrix4f mat = stack.last().pose();
		
		builder.vertex(mat, 0, 0, -2).color(255, 255, 255, 150).endVertex();
		builder.vertex(mat, 1, 0, -2).color(255, 255, 255, 150).endVertex();
		builder.vertex(mat, 1, 1, -2).color(255, 255, 255, 150).endVertex();
		builder.vertex(mat, 0, 1, -2).color(255, 255, 255, 150).endVertex();
		
		stack.popPose();
	}
}

 

 

Edited by SerpentDagger
Wrongness

Fancy 3D Graphing Calculator mod, with many different coordinate systems.

Lightweight 3D/2D position/vector transformations library, also with support for different coordinate systems.

Link to comment
Share on other sites

Thanks for the replys. I was using the same translation as minecraft, but i've tried yours too and it still does not work. The lines are still moving while flying and so on, but now sneaking does affect it too. The lines were also in the middle of the block instead of beeing at the side.

Vector3d vec = mc.gameRenderer.getMainCamera().getPosition();
double renderPosX = vec.x();
double renderPosY = vec.y();
double renderPosZ = vec.z();
ms.pushPose();
ms.translate(-renderPosX, -renderPosY, -renderPosZ);

Right now i was using this translation and i've checked, the Minecraft function (WorldRenderer#renderLineBox) uses MatrixStack#last#pose in vertexbuilder.

I'll keep on searching for the right translation and any idea would be nice.

Any idea about the colour or the lineWidth?

Thanks for all the help again

Link to comment
Share on other sites

Looks like it is an issue with FOV, because when disabling FOV effects the box is rendered fine. Changing fov in options screen, does move the world but not my box, when i use worldrender last event. It looks like #renderWorld does implement fov anywhere, but i can't figure out where. Do i need to implement fov myself and if yes how to do it?

Or do i need something else, what BlockHighlight Event already implements? Anybody an idea, or an idea where to look? An working example would help too.

Thanks in advance

Link to comment
Share on other sites

First I need to apologize for the previous post. It looked to hold true while I was writing it, but with further testing it would seem I don't know what I'm talking about. Sorry about that mess.

I'm working on a similar problem, and (apparently) haven't figured out how to solve it yet, but have a couple clues that might help...

● TileEntityRenderers render in block-space, which means that their MatrixStack has to get that way somehow. GameRenderer#renderLevel calls WorldRender#renderLevel, which activates the TileEntityRendererDispatcher, which activates the TileEntityRenderers.

● GameRenderer#renderLevel receives a new MatrixStack() as a parameter. It also creates a new MatrixStack(), which is multiplied by the projection matrix of the main camera and bobbing/portal effects. The RenderSystem is then reset to that projection matrix pose, and the GameRender.mainCamera is setup to include information about the view entity and camera (not including projection information). It then multiplies the parameter stack by rotations of the camera, making it a rotation matrix.

● I would expect the application of the projection matrix to RenderSystem to be effective globally, since it's internally a process of GlStateManager.

● GameRenderer#renderLevel passes both the projection Matrix4f and the rotation MatrixStack to WorldRender#renderLevel, as well as the ActiveRenderInfo. We in RenderWorldLastEvent just get the projection and rotation matrices, but the ActiveRenderInfo in question is just a reference to GameRenderer.mainCamera.

● From what I can tell, no change persists to either of the matrices between the calling of WorldRender#renderLevel and RenderWorldLastEvent, which means that we should be able to follow the TileEntityRendererDispatcher's transforms.

● Unfortunately, the only transform applied is a translation of the matrix by the position of the TileEntity in question minus the ActiveRenderInfo's position, which is the equivalent of exactly what we're doing already. This is all I would expect to be necessary, though. If the projection matrix is globally applied, and the stack already contains rotational information, then translation is all that ought to be needed.

I don't understand why applying the same transformations as the TileEntitys receive doesn't yield a comparable result. I suppose they must not be the same transformations, but I can't figure out where they differ (and I've spent a long time looking). Hopefully this information is helpful to someone, because I'm just about out of ideas.

 

On the same topic, the most I've been able to conjure is a location that's sort of right in first person, and entirely wrong in 3rd person if you have an item in your hotbar. That suggests to me that the item rendering interferes with RenderWorldLastEvent's matrices, which I suppose is where I'll spend my next bout of free time. Does your render have the same problem? You never specified exactly how things are moving wrong.

 

As for the line width, it looks like that's a fixed property of the LineState set on creation of RenderType.LINES, which is loaded into the RenderSystem every time the buffer begins drawing. In order to change it, that means you would need to create your own RenderType. Botania has an example of how to do this.

 

The color is a bit more odd. I had a similar problem when I accidentally used IVertexBuilder#color(int, int, int, int), instead of IVertexBuilder#color(float, float, float, float), but WorldRender#renderLineBox shouldn't have that issue.

 

Sorry I'm not able to be more helpful. 😕

Fancy 3D Graphing Calculator mod, with many different coordinate systems.

Lightweight 3D/2D position/vector transformations library, also with support for different coordinate systems.

Link to comment
Share on other sites

I've finally got a solution to the positional problem. It turns out DrawHighlightEvent is fired before all the relevant batches are drawn, while RenderWorldLastEvent is fired after all the buffers have been drawn. (I would consider this a bug.) That means that while your buffer's waiting patiently to be drawn, other parts of the code can change the global projection matrix. Notably, GameRenderer#renderItemInHand starts mucking about with the projection matrix naught but 4 lines later. The result is all this unpredictable failure.

The solution is to draw your buffer at the end of writing to it, with Impl#endBatch(RenderType). Here is a working (and more thoroughly tested) example:

@EventBusSubscriber(Dist.CLIENT)
public class SpellRenderEventSubscriber
{	
	@SubscribeEvent
	public static void worldRender(RenderWorldLastEvent event)
	{
		Impl buffer = Minecraft.getInstance().renderBuffers().bufferSource();
		IVertexBuilder builder = buffer.getBuffer(SpellRender.QUADS); //SpellRender.QUADS is a personal RenderType, of VertexFormat POSITION_COLOR.
		
		MatrixStack stack = event.getMatrixStack();
		
		stack.pushPose();
		
		Vector3d cam = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition();
		stack.translate(-cam.x, -cam.y, -cam.z);
		
		Matrix4f mat = stack.last().pose();
		
		builder.vertex(mat, 0, 57, 0).color(0, 255, 255, 150).endVertex();
		builder.vertex(mat, 1, 57, 0).color(0, 255, 255, 150).endVertex();
		builder.vertex(mat, 1, 58, 0).color(0, 255, 255, 150).endVertex();
		builder.vertex(mat, 0, 58, 0).color(0, 255, 255, 150).endVertex();
		
		stack.popPose();
		
		buffer.endBatch(SpellRender.QUADS);
	}
}

And the result, which stays where it's told despite all manner of character-scooching/FOV-changing:

Success.png.1b0d048f1a3f68c5d374cacb2adecd45.png

  • Thanks 1

Fancy 3D Graphing Calculator mod, with many different coordinate systems.

Lightweight 3D/2D position/vector transformations library, also with support for different coordinate systems.

Link to comment
Share on other sites

You're welcome! 🙂

51 minutes ago, Silverminer said:

The only problem is, that i can't see my box through water

I think that may also be fixable with a custom RenderType. They can specify layering, blending, masking, etc.

  • Thanks 1

Fancy 3D Graphing Calculator mod, with many different coordinate systems.

Lightweight 3D/2D position/vector transformations library, also with support for different coordinate systems.

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.