Jump to content

Some things behind semi-transparent model render strangely [1.7] [UNSOLVED]


Recommended Posts

Posted

Hi everyone.

 

I am working on a pipe that will transport items (like ItemDucts or Buildcrafts pipes, I haven't actually got to the actual item transport part yet, I am just working on rendering today) and I have decided to make the sides transparent so that you can see the items inside. I have successfully achieved this, but unfortunately, there is some weird rendering of the world behind it. Full blocks are fine, but anything else (for some reason, excluding lava) isn't rendered, so this includes water, and any other models.  Here are some screenshots to illustrate what I mean:

width=800 height=423yt7funb.png?1 [/img]

and

width=800 height=4235r6zj2r.png?1 [/img]

 

As you can see, the water behind, and my wind turbine model aren't getting rendered behind the transparent part of the pipe. There are also some transparent bits inside the pipe when looked at as some angles (seen in pic 1)

 

My current code for rendering this is this:

 

 

This is only my renderTileEntityAt method, I do no other lighting, blending, or colouring stuff in any of the other methods being called.

public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float f) {

	int meta = 0;

	if (tile instanceof TileEntityCable) meta = tile.getBlockMetadata();
	if (tile instanceof TileEntityPipe) meta = tile.getBlockMetadata() + 8; // add 8 because cables have 8 subtypes, and for the pipes, the first resource is 8 after the cables first resource.

	GL11.glPushMatrix();
	GL11.glTranslated(x, y, z);
	GL11.glScalef(0.5F, 0.5F, 0.5F);
	GL11.glTranslatef(1.0F, 0.0F, 1.0F);
	GL11.glDisable(GL11.GL_LIGHTING);
	//Calling all the render methods from here with the model and texture specified above.
	if (this.resource[meta][4] != null) {
		this.bindTexture(resource[meta][4]); {
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
			if (tile instanceof TileEntityCable) {

				TileEntityCable connectable = (TileEntityCable) tile;
				for (int i = 0; i < 6; i++) {
					//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
				}
				if ((!connectable.hasOppositeConnection(connectable.connections))) {
					if (this.model[meta][0] != null) this.drawCore(meta);
				} else if (this.model[meta][1] != null) {
					if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
					if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
					if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
				}

				for (int i = 0; i < connectable.connections.length; i++) {
					if (connectable.connections[i] != null) {
						if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
					}
				}
			} if (tile instanceof TileEntityPipe) {

				TileEntityPipe connectable = (TileEntityPipe) tile;
				for (int i = 0; i < 6; i++) {
					//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
				}

				if ((!connectable.hasOppositeConnection(connectable.connections))) {
					if (this.model[meta][0] != null) this.drawCore(meta);
				} else if (this.model[meta][1] != null) {
					if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
					if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
					if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
				}

				for (int i = 0; i < connectable.connections.length; i++) {
					if (connectable.connections[i] != null) {
						if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
					}
				}
			}
			GL11.glDisable(GL11.GL_BLEND);
		}
	}
	GL11.glEnable(GL11.GL_LIGHTING);
	GL11.glPopMatrix();
}

Note: This renderer class does handle all of my connecting blocks, and the one that is transparent uses metadata 8, metadata 0 to 7 are all of my cables, and have no problems.

 

 

 

Any suggestions on how to fix this?

 

Thanks.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Hi

 

It looks to me like the ol' rendering-order-is-important-for-alpha-blended-blocks problem.

 

http://www.minecraftforge.net/forum/index.php/topic,22368.msg113450.html#msg113450

 

Your alpha-blended pane is drawing before the water, and it is also writing to the depth buffer.  So when the water is drawn afterwards, it is behind the pane and gets culled.

 

You can turn off writing to the depth buffer while rendering your pane, using GL11.glDepthMask(false);, but that probably won't help much because then the water will render over the top of your pane which will probably look rather strange.

 

The only way  to correct this properly is to make sure that your panes are rendered last.  Unfortunately this will only work when the pipe is the closest alpha-blended object to the player, so you will need to hope that your pipes are never placed behind another alpha-blended object.

 

There may not be an easy answer unfortunately.  It is for sure possible if you grasp deep into the rendering code to sort all the pass 1 rendering by depth.  I'd suggest trying the depth mask fix or the render-last fix and seeing if you can live with one of them.

 

-TGG

 

Posted

Okay this is a fair bit beyond my understanding of GL11 and the way java handles this, so I guess I have a bit of research to do to truly understand what is happening and to find a solution to this.

 

Thanks anyway.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

setting depth mast to true resulted in this:

width=800 height=412lOaJzKB.png?1 [/img]

and

width=800 height=4126jjahUi.png?1 [/img]

So the water and other TESR models behind it such as the wind turbine, are now getting rendered, but now the pipe itself has really odd transparency. Things like the inside of the pipe looks like it is in front of the outside of the pipe, and in image two, the pipe in the background looks to be in front of the pipe in the foreground.Also, there are really annoying and messy looking dark and light bits.

 

What can I do? I either need a way to fix this, or how do I do the render last fix that you suggested?

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

TheGreyGhost already explained it.  If you think about it, for the graphics engine to calculate the picture when there are transparent things in the background, the only trustworthy way is to draw the stuff in the background first then blend the transparent stuff on top.  Imagine you were painting something and you did a light wash of color first (i.e. the transparent part) and then painted over it with thick paint, versus doing it the other way around -- doing a wash of color over thick paint.  The results are not the same: the order matters.

 

If you leave depth mask as true, then when it comes time to render the transparent stuff there is a chance that it has will be "painted" in the scene before something in the background and then when the background is checked it is considered "behind" the transparent part so is not rendered at all (this is called culling).

 

If you disable depth mask with false, then it will render everything even if it was supposed to be behind.  This can screw things up.

 

The fundamental problem is that Minecraft should ideally render things in order based on depth, but instead does several passes.  So your entity may be rendered before water, even if the water is farther back in the background.  There isn't really an easy solution to this.

 

You can however control the order of depth and rendering within your own rendering code.  I don't know how your pipes are rendered, but you could theoretically draw the transparent parts and solid parts with and without depth checking as needed.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

This is a TileEntity, right? Try to override

shouldRenderInPass(int pass)

in your TileEntity class and return [if pass equals 1]. It fixed the rendering issues of my semi-transparent tileentity.

 

I actually took it a step further and saved the pass which the method was called in and rendered solid parts on pass 0 and the transparent parts on pass 1:

https://github.com/SanAndreasP/EnderStuffPlus/blob/master/java/de/sanandrew/mods/enderstuffplus/tileentity/TileEntityBiomeChanger.java#L584-L589

https://github.com/SanAndreasP/EnderStuffPlus/blob/master/java/de/sanandrew/mods/enderstuffplus/client/render/tileentity/RenderTileEntityBiomeChanger.java#L103-L132

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Posted

I already have done shouldRenderInPass(int pass) and in the block class, getRnderPass() { return 1; } and it still looks really weird. I think, as suggested above, my best option is to somehow make sure my pipe is rendered last. I only need a way to do this.

 

If needed I'll post my code later, I don't have access to it right now.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Okay, I have solved the problem of things behind getting culled, or rendering on top of the pipe. SanAndreasP's suggestion worked, with some tweaking of my GL11 methods too. I also removed the getRenderPass() method from my block class. This is my updated renderTileEntityAt method:

        public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float f) {

	int meta = 0;

	if (tile instanceof TileEntityCable) meta = tile.getBlockMetadata();
	if (tile instanceof TileEntityPipe) meta = tile.getBlockMetadata() + 8; // add 8 because cables have 8 subtypes, and for the pipes, the first resource is 8 after the cables first resource.

	GL11.glPushMatrix();
	GL11.glTranslated(x, y, z);
	GL11.glScalef(0.5F, 0.5F, 0.5F);
	GL11.glTranslatef(1.0F, 0.0F, 1.0F);
	GL11.glDisable(GL11.GL_LIGHTING);
	//Calling all the render methods from here with the model and texture specified above.
	//if (this.resource[meta][4] != null) {
	if (tile instanceof TileEntityCable) {

		TileEntityCable connectable = (TileEntityCable) tile;
		for (int i = 0; i < 6; i++) {
			//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
		}

		if (resource[meta][4] != null) this.bindTexture(resource[meta][4]);
		if ((!connectable.hasOppositeConnection(connectable.connections))) {
			if (this.model[meta][0] != null) this.drawCore(meta);
		} else if (this.model[meta][1] != null) {
			if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
			if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
			if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
		}

		for (int i = 0; i < connectable.connections.length; i++) {
			if (connectable.connections[i] != null) {
				if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
			}
		}
	} if (tile instanceof TileEntityPipe) {
		TileEntityPipe connectable = (TileEntityPipe) tile;
		for (int i = 0; i < 6; i++) {
			//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
		}
		if (connectable.renderPass == 1) {
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glEnable(GL11.GL_DEPTH_TEST);
			//System.out.println("test");
			GL11.glDepthMask(true);

			GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);

			this.renderTravelingItem(connectable, (float)x, (float)y, (float)z);

			GL11.glShadeModel(GL11.GL_SMOOTH);
			if (resource[meta][4] != null) this.bindTexture(resource[meta][4]);

			if ((!connectable.hasOppositeConnection(connectable.connections))) {
				if (this.model[meta][0] != null) this.drawCore(meta);
			} else if (this.model[meta][1] != null) {
				if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
				if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
				if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
			}

			for (int i = 0; i < connectable.connections.length; i++) {
				if (connectable.connections[i] != null) {
					if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
				}
			}
			GL11.glEnable(GL11.GL_CULL_FACE);
			GL11.glDepthMask(false);
			GL11.glDisable(GL11.GL_BLEND);

		}
	}
	//}
	GL11.glEnable(GL11.GL_LIGHTING);
	GL11.glPopMatrix();
}

 

Again, relevant code starts from "if (tile instanceof TileEntityPipe)", the rest is for my cables.

 

This is now what it looks like:

 

width=800 height=423ELLJ6K9.png?1 [/img]

 

So, the water, and other things in the background look fine, they're rendered behind the pipe as they should be.

But....

Now there is another problem. You can also see in the screenshot, that the inside of the pipe itself looks slightly strange, there are bits of the inside that are missing, and this is only from certain angles, the missing bits move when looked at from another angle. I think they are getting culled, but I am not sure what by, and disabling culling makes it look weird again. Also, another problem, you can see in my code, I have commented out the line this.renderTravelingItem. This was also causing some of the rendering issues, the item renders fine, without any transparency issues, but is rendered behind the pipe. This is what happens when renderTravelingItem isn't commented out:

 

width=800 height=4234bcY6Wb.png?1 [/img]

 

The iron ingot is positioned inside the pipe, but is rendered behind the pipe.

 

This is my travelling item method:

        public void renderTravelingItem(TileEntityPipe pipe, float x, float y, float z) {
	GL11.glPushMatrix();
	GL11.glDisable(GL11.GL_LIGHTING);
	GL11.glDisable(GL11.GL_CULL_FACE);

	TravelingItem itemToRender1 = new TravelingItem(new ItemStack(Items.iron_ingot, 5), 0.0F, 0.0F, 0.0F, 0.05F); //Testing with an item
	TravelingItem itemToRender2 = new TravelingItem(new ItemStack(Blocks.stone, 5), 0.0F, 0.0F, 0.0F, 0.05F); //Testing with a block

	//List<TravelingItem> items = new ArrayList<TravelingItem>();

	/*for (ItemStack s : pipe.getStoredItems()) {
		TravelingItem item = new TravelingItem(s, 0.0F, 0.0F, 0.0F, 0.05F);
		items.add(item);
	}*/

	float scale = 1.25F;

	this.renderTravelingItem(itemToRender1, x, y, z, 0.05F, scale);

	GL11.glEnable(GL11.GL_CULL_FACE);
	GL11.glEnable(GL11.GL_LIGHTING);
	GL11.glPopMatrix();
}

public void renderTravelingItem(TravelingItem item, float x, float y, float z, float speed, float scale) {
	//TravelingItem item = new TravelingItem(stack, x, y, z, speed);
	if (item == null || item.getStack() == null) {
		return;
	}

	ItemStack stack = item.getStack();

	GL11.glPushMatrix();
	GL11.glTranslatef(x, y, z);
	GL11.glTranslatef(0.5F, 0.9F, 0.5F);
	GL11.glScalef(scale, scale, scale);
	fakeItem.setEntityItemStack(stack);
	renderItem.doRender(fakeItem, 0.0D, 0.0D, 0.0D, 0.0F, 0.0F);
	GL11.glPopMatrix();
}

And the TravelingItem class just stores the ItemStack, its position, and I will soon make it also store NBT data.

 

So, one major problem is solved, but now there are two annoying problems to solve.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Hi

>Now there is another problem. You can also see in the screenshot, that the inside of the pipe itself looks slightly strange, there are bits of the inside that are missing, and this is only from certain angles, the missing bits move when looked at from another angle.

 

This is probably the same rendering-order problem again.

 

When you render your TileEntity, draw the rearmost faces first, i.e. the face that is furthest from the player.  As the player moves around the pipe, the "rearmost" face will change.  This might be difficult with a model; you may need to split the model into the six flat faces.

 

> the item renders fine, without any transparency issues, but is rendered behind the pipe

 

That's because you have turned off writing to the depth buffer during rendering of the item (GL11.glDepthMask(false); ), so when you draw the model, it draws over the top of your item since the depth buffer doesn't know the item is there.

 

Just to check - do you understand the difference between

GL11.glDisable(GL11.GL_DEPTH_TEST);

and

GL11.glDepthMask(false);

 

-TGG

Posted

Just to check - do you understand the difference between

GL11.glDisable(GL11.GL_DEPTH_TEST);

and

GL11.glDepthMask(false);

 

No...

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Just to check - do you understand the difference between

GL11.glDisable(GL11.GL_DEPTH_TEST);

and

GL11.glDepthMask(false);

 

No...

Ah ok.

 

GL11.glDisable(GL11.GL_DEPTH_TEST); makes your object draw on top of everything that has been drawn previously, i.e. it ignores the depth of everything that has already been drawn.

 

GL11.glDepthMask(false); turns off writing to the depth buffer when you're drawing an object, so that anything you draw afterwards doesn't know the object is there and writes over the top of it, regardless of whether depth_test is true or not.

 

-TGG

 

 

 

 

 

 

Posted

Okay, that makes sense now.

 

This is probably the same rendering-order problem again.

 

When you render your TileEntity, draw the rearmost faces first, i.e. the face that is furthest from the player.  As the player moves around the pipe, the "rearmost" face will change.  This might be difficult with a model; you may need to split the model into the six flat faces.

 

Okay, so my model is an OBJ model, if I split it into the separate faces in Maya, and then export it as an OBJ, would I be able to somehow control the render order of the faces? If so, how would I achieve this?

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

I know that, but I mean, how would I make it render the furthest face from the player first? or would I need to do this?

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Hi

 

When you render in a tile entity, the origin is at your eyes (yours, not the player's), and the dx,dy,dz in the renderAt method tells you where the tileentity is relative to your eyes.

 

So for example, if your cube only has four sides: east (+x), west(-x), north (-z), south (+z), then you need to look at the relativex (dx) and relativez  (dz)

http://greyminecraftcoder.blogspot.com.au/2013/07/blocks.html

The cube is 1 wide (x) by 1 deep (z)

 

If we consider just the east/west faces:

if dx > 0, then the cubeis to the east of our eyes, so we see the west face closest --> draw the west face last

if dx < -1, then the cube is to the west of our eyes, so we see the east face closest --> draw the east face last

if dx is between -1 and 0, then our eyes are between the two faces and they can't possibly overlap each other so it doesn't matter which one we draw last.  They can't possibly overlap any of the other faces either so we can always draw them first.

 

Similar logic for north/south (z) and up/down (dy).

 

For a cube (or rectangular prism) it's pretty straightforward. 

If you're between two faces (eg -1 < dx < 0) then draw those first.

Next, draw all the furthest-away faces

Last, draw all the closest faces.

 

Other shapes are harder and usually need maths calcs.

 

-TGG

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.