TheEpicTekkit Posted October 18, 2014 Posted October 18, 2014 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: [/img] and [/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. Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
TheGreyGhost Posted October 19, 2014 Posted October 19, 2014 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 Quote
TheEpicTekkit Posted October 19, 2014 Author Posted October 19, 2014 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. Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
TheEpicTekkit Posted October 19, 2014 Author Posted October 19, 2014 setting depth mast to true resulted in this: [/img] and [/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? Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
TheEpicTekkit Posted October 19, 2014 Author Posted October 19, 2014 Bump* Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
jabelar Posted October 20, 2014 Posted October 20, 2014 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. Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
SanAndreaP Posted October 20, 2014 Posted October 20, 2014 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 Quote 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.
TheEpicTekkit Posted October 20, 2014 Author Posted October 20, 2014 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. Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
TheEpicTekkit Posted October 20, 2014 Author Posted October 20, 2014 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: [/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: [/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. Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
TheGreyGhost Posted October 21, 2014 Posted October 21, 2014 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 Quote
TheEpicTekkit Posted October 21, 2014 Author Posted October 21, 2014 Just to check - do you understand the difference between GL11.glDisable(GL11.GL_DEPTH_TEST); and GL11.glDepthMask(false); No... Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
TheGreyGhost Posted October 22, 2014 Posted October 22, 2014 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 Quote
TheEpicTekkit Posted October 22, 2014 Author Posted October 22, 2014 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? Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
MultiMote Posted October 22, 2014 Posted October 22, 2014 obj supports model parts. Use yourmodel.renderPart("some_part") Quote
TheEpicTekkit Posted October 23, 2014 Author Posted October 23, 2014 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? Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
TheGreyGhost Posted October 23, 2014 Posted October 23, 2014 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 Quote
TheEpicTekkit Posted October 23, 2014 Author Posted October 23, 2014 Okay, thanks. I'll work on this, and post here if I get any problems. Quote I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.
Recommended Posts
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.