Jump to content

[SOLVED][1.15.2] Updating world space rendering from 1.12 to 1.15


xChris6041x

Recommended Posts

Like it says in the title I am attempting to update my old mod which can render cubes of any position, rotation, and scale in world space to the new rendering engine in 1.15 with little success. I got it to start rendering the cubes by using the MatrixStack but it only renders them what appears to be screen space. I've also converted all of my GlStateManager calls to RenderSystem calls. Below is some of the code from the project which deals with cube rendering.

 

Render Entry

@SubscribeEvent
public static void onWorldRender(RenderWorldLastEvent event) {
	// Grab Minecraft instance and check if player exists (in world).
	Minecraft mc = Minecraft.getInstance();
	ClientPlayerEntity player = mc.player;
	if(player == null) return;
	
	CubeBatch batch = new CubeBatch();
	batch.begin(event.getMatrixStack(), mc.gameRenderer.getActiveRenderInfo().getProjectedView());
	for(ICubeScene scene : scenes) {
		if(!scene.isVisible()) continue;
		scene.render(batch, player, event.getPartialTicks());
	}
	batch.end();
}

 

Cube Batch

public class CubeBatch {
	private List<Cube> buffer;
	private Vec3d origin;
	private MatrixStack matrixStack;
	
	/**
	 * @return the current origin.
	 */
	public Vec3d getOrigin() {
		return origin;
	}
	/**
	 * @return the current matrix stack.
	 */
	public MatrixStack getMatrixStack() {
		return matrixStack;
	}
	
	/**
	 * Starts a CubeBatch instruction instance.
	 * @param matrixStack - 
	 * @param origin - The origin for the CubeRenderer.
	 */
	public void begin(MatrixStack matrixStack, Vec3d origin) {
		this.matrixStack = matrixStack;
		this.origin = origin;
		this.buffer = new ArrayList<Cube>();
	}
	/**
	 * Flushes the Cube Batch to the CubeRenderer.
	 */
	public void flush() {
		CuRender.begin(matrixStack, origin);
		for(Cube cube : buffer) {
			CuRender.cube(cube);
		}
		CuRender.end();
		buffer.clear();
	}
	/**
	 * Stops and flushes the CubeBatch.
	 */
	public void end() {
		flush();
		buffer = null;
		origin = null;
	}
	
	/**
	 * Renders this cube to the world when flushed.
	 * @param cube
	 */
	public void draw(Cube cube) {
		if(!cube.isVisible()) return;
		buffer.add(cube.clone());
	}
	
	/**
	 * Renders a blend of the two cubes to the world when flushed.
	 * @param cube1
	 * @param cube2
	 * @param blend - A number between 0 and 1 (0 - Only Cube1, 1 - Only Cube2)
	 */
	public void blend(Cube cube1, Cube cube2, float blend) {
		if(blend < 0) blend = 0;
		else if(blend > 1) blend = 1;
		
		Cube c1 = cube1.clone();
		Cube c2 = cube2.clone();
		c1.scaleOpacity(1 - blend);
		c2.scaleOpacity(blend);
		
		buffer.add(c1);
		buffer.add(c2);
	}
}

 

Rendering Process

public final class CuRender {
	private static boolean rendering = false;
	private static MatrixStack matrixStack;
	
	/**
	 * Sets up the OpenGL environment for rendering in world space.
	 * @param origin - Origin of the camera (typically player's eye position).
	 */
	public static void begin(MatrixStack matrixStack, Vec3d origin) {
		if(rendering) throw new IllegalStateException("Cannot begin while rendering.");
		rendering = true;
		CuRender.matrixStack = matrixStack;
		
		matrixStack.push();
		matrixStack.translate(0.5 - origin.x, 0.5 - origin.y, 0.5 - origin.z);
		RenderSystem.disableDepthTest();
		RenderSystem.disableTexture();
		RenderSystem.disableLighting();
		RenderSystem.enableBlend();
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
	}
	/**
	 * Returns the OpenGL environment back to normal.
	 */
	public static void end() {
		if(!rendering) return;
		
		RenderSystem.disableBlend();
		RenderSystem.enableLighting();
		RenderSystem.enableTexture();
		RenderSystem.enableDepthTest();
		matrixStack.pop();
		
		rendering = false;
	}
	
	/**
	 * Renders the cube in world space.
	 * @param cube
	 */
	public static void cube(Cube cube) {
		matrixStack.push();
		// Position
		matrixStack.translate(-cube.getX(), -cube.getY(), -cube.getZ());
		// Rotate
//		GlStateManager.translated(cube.getOriginX() / 2, cube.getOriginY() / 2, cube.getOriginZ() / 2);
//		GlStateManager.rotatef(-cube.getYaw(), 0, 1, 0);
//		GlStateManager.rotatef(cube.getPitch(), 1, 0, 0);
//		GlStateManager.scaled(cube.getScaleX(), cube.getScaleY(), cube.getScaleZ()); // Scale
//		GlStateManager.translated(-cube.getOriginX() / 2, -cube.getOriginY() / 2, -cube.getOriginZ() / 2);
		matrixStack.scale(0.5f, 0.5f, 0.5f); // Normalize
		
		if(cube.isWired()) {
			// Wire Cube
			renderEdges(cube.getWireColor(), null);
		}
		else if(cube.isSolid()) {
			// Solid Cube
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
			}
		}
		else {
			// Mixed Cube
			boolean[] removedEdge = new boolean[UnitCube.EDGE_COUNT];
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				if(!cube.isFaceSolid(i)) continue;
				
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
				quad(cube.getFaceColor(i), face.v1, face.v4, face.v3, face.v2);
				
				for(Edge edge : face.edges) {
					int j = UnitCube.getEdgeIndex(edge);
					removedEdge[j] = true;
				}
			}
			renderEdges(cube.getWireColor(), removedEdge);
		}
		
		matrixStack.pop();
	}
	private static void renderEdges(Color4f color, boolean[] removedEdges) {
	    glColor4f(color);
		GL11.glBegin(GL11.GL_LINES);
		for(int i = 0; i < UnitCube.EDGE_COUNT; i++) {
			if(removedEdges != null && removedEdges[i]) continue;
			
			Edge edge = UnitCube.EDGES[i];
			glVertex3d(edge.v1);
			glVertex3d(edge.v2);
		}
		GL11.glEnd();
	}
	
	/**
	 * Renders a quad with the specified vertices. OpenGL must be in GL_QUADS mode to work.
	 * @param v1
	 * @param v2
	 * @param v3
	 * @param v4
	 */
	public static void quad(Color4f color, Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4) {
		glColor4f(color);
		GL11.glBegin(GL11.GL_QUADS);
	    glVertex3d(v1);
	    glVertex3d(v2);
	    glVertex3d(v3);
	    glVertex3d(v4);
		GL11.glEnd();
	}
	private static void glVertex3d(Vec3d v) {
		GL11.glVertex3d(v.x, v.y, v.z);
	}
	private static void glColor4f(Color4f c) {
		GL11.glColor4f(c.r, c.g, c.b, c.a);
	}
}

 

Sample Cube Scene

public class DebugScene extends CubeScene {
	public static final Cube CUBE_TEMPLATE = new Cube().wire().setColor(1f, 0f, 0f, 0.5f);
	
	@Override
	public void render(CubeBatch batch, ClientPlayerEntity player, float partialTicks) {
		World world = player.getEntityWorld();
		int px = (int) player.lastTickPosX;
		int pz = (int) player.lastTickPosZ;
		
		// Loop through all chunks in the chunk render distance.
		for(int x = px - 50; x <= px + 50; x++) {
			for(int z = pz - 50; z <= pz + 50; z++) {
				int maxY = world.getHeight(Type.WORLD_SURFACE, x, z);
				for(int y = 0; y <= maxY; y++) {
					BlockState state = world.getBlockState(new BlockPos(x, y, z));
					if(state.getBlock() instanceof OreBlock) {
						batch.draw(CUBE_TEMPLATE.clone().setPosition(x, y, z));
					}
				}
			}
		}
	}
}

 

 

Any direct help or even resources to how the new rendering system works is greatly appreciated. If anymore information is needed please don't hesitate to ask.

Edited by xChris6041x
Solution was found.
Link to comment
Share on other sites

3 hours ago, desht said:

I'd recommend looking at McJty's tutorials here, especially parts 13 - 15 for 1.15.x rendering topics.

I checked out his tutorials, but I don't think they will work in my case. The cubes that I am rendering are not custom TileEntities as they need to be rendered in any possible position. Using the RenderWorldLastEvent#getMatrixStack doesn't seem to have a matrix stack I can manipulate to get what I want. I ended up finding a solution which works, but uses the now deprecated GlStateManager methods.

 

Render Entry

@SubscribeEvent
public static void onWorldRender(RenderWorldLastEvent event) {
	// Grab Minecraft instance and check if player exists (in world).
	Minecraft mc = Minecraft.getInstance();
	ClientPlayerEntity player = mc.player;
	if(player == null) return;
	
	ActiveRenderInfo info = mc.gameRenderer.getActiveRenderInfo();
	CubeBatch batch = new CubeBatch();
	batch.begin(info.getProjectedView(), info.getPitch(), info.getYaw());
	for(ICubeScene scene : scenes) {
		if(!scene.isVisible()) continue;
		scene.render(batch, player, event.getPartialTicks());
	}
	batch.end();
}

 

Rendering Process

@SuppressWarnings("deprecation")
public final class CuRender {
	private static boolean rendering = false;
	
	/**
	 * Sets up the OpenGL environment for rendering in world space.
	 * @param origin - Origin of the camera (typically player's eye position).
	 */
	public static void begin(Vec3d origin, Vec2f angle) {
		if(rendering) throw new IllegalStateException("Cannot begin while rendering.");
		rendering = true;
		
		GlStateManager.pushMatrix();
		GlStateManager.rotatef(angle.x, 1, 0, 0); // Fixes camera rotation.
		GlStateManager.rotatef(angle.y + 180, 0, 1, 0); // Fixes camera rotation.
		GlStateManager.translated(0.5 - origin.x, 0.5 - origin.y, 0.5 - origin.z);
		GlStateManager.disableDepthTest();
		GlStateManager.disableTexture();
		GlStateManager.disableLighting();
		GlStateManager.enableBlend();
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
	}
	/**
	 * Returns the OpenGL environment back to normal.
	 */
	public static void end() {
		if(!rendering) return;
		
		GlStateManager.disableBlend();
		GlStateManager.enableLighting();
		GlStateManager.enableTexture();
		GlStateManager.enableDepthTest();
		GlStateManager.popMatrix();
		
		rendering = false;
	}
	
	/**
	 * Renders the cube in world space.
	 * @param cube
	 */
	public static void cube(Cube cube) {
		GlStateManager.pushMatrix();
		// Position
		GlStateManager.translated(cube.getX(), cube.getY(), cube.getZ());
		// Rotate
		GlStateManager.translated(cube.getOriginX() / 2, cube.getOriginY() / 2, cube.getOriginZ() / 2);
		GlStateManager.rotatef(-cube.getYaw(), 0, 1, 0);
		GlStateManager.rotatef(cube.getPitch(), 1, 0, 0);
		GlStateManager.scaled(cube.getScaleX(), cube.getScaleY(), cube.getScaleZ()); // Scale
		GlStateManager.translated(-cube.getOriginX() / 2, -cube.getOriginY() / 2, -cube.getOriginZ() / 2);
		GlStateManager.scaled(0.5, 0.5, 0.5); // Normalize
		
		if(cube.isWired()) {
			// Wire Cube
			renderEdges(cube.getWireColor(), null);
		}
		else if(cube.isSolid()) {
			// Solid Cube
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
			}
		}
		else {
			// Mixed Cube
			boolean[] removedEdge = new boolean[UnitCube.EDGE_COUNT];
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				if(!cube.isFaceSolid(i)) continue;
				
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
				quad(cube.getFaceColor(i), face.v1, face.v4, face.v3, face.v2);
				
				for(Edge edge : face.edges) {
					int j = UnitCube.getEdgeIndex(edge);
					removedEdge[j] = true;
				}
			}
			renderEdges(cube.getWireColor(), removedEdge);
		}
		
		GlStateManager.popMatrix();
	}
	private static void renderEdges(Color4f color, boolean[] removedEdges) {
	    glColor4f(color);
		GL11.glBegin(GL11.GL_LINES);
		for(int i = 0; i < UnitCube.EDGE_COUNT; i++) {
			if(removedEdges != null && removedEdges[i]) continue;
			
			Edge edge = UnitCube.EDGES[i];
			glVertex3d(edge.v1);
			glVertex3d(edge.v2);
		}
		GL11.glEnd();
	}
	
	/**
	 * Renders a quad with the specified vertices. OpenGL must be in GL_QUADS mode to work.
	 * @param v1
	 * @param v2
	 * @param v3
	 * @param v4
	 */
	public static void quad(Color4f color, Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4) {
		glColor4f(color);
		GL11.glBegin(GL11.GL_QUADS);
	    glVertex3d(v1);
	    glVertex3d(v2);
	    glVertex3d(v3);
	    glVertex3d(v4);
		GL11.glEnd();
	}
	private static void glVertex3d(Vec3d v) {
		GL11.glVertex3d(v.x, v.y, v.z);
	}
	private static void glColor4f(Color4f c) {
		GL11.glColor4f(c.r, c.g, c.b, c.a);
	}
}

 

This code is mostly 1.12 code, but 1.15 didn't maintain the player head rotation in the matrix. Passing in the pitch and yaw I was able to rotate the matrix to have the illusion of world space rendering.

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.

Announcements



×
×
  • Create New...

Important Information

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