Seams around my transparent textures

Please advise how I can get rid of the ugly seams on the outer edge of my transparent images.  Depending on the background color, they look very bad.  If you look closely at the screen shot, there are lots of other seams there too.



I have verified that the images I am using for textures do not have any opaque border or such.



Probably filtering on the mipmaps is causing this. You might want to separate the leafs from eachover on the texture.

It looks like there's two different kinds of seems here, the ones that are colors over the background, and the ones circled in red that show through to the background… 



Do you have a black edge around the leaves?

sbook said:

It looks like there's two different kinds of seems here, the ones that are colors over the background, and the ones circled in red that show through to the background..  

Do you have a black edge around the leaves?


No.  I have no idea what is causing that.  I would be grateful if somebody can tell me how to fix that, but it isn't critical to me right now, because in practice (as one walks around the game world) that is less noticable than that these are 2D planes.  This is a reduced copy of one of the 2 branch images.  (This image is my own creation).

Momoko_Fan said:

Probably filtering on the mipmaps is causing this. You might want to separate the leafs from eachover on the texture.


I'll try other mipping settings.  What you see is using power-of-two texture images and Trilinear + Bilinear.

Could you please elaborate on what you mean by "separate the leafs frome eachover on the texture"?  Did you mean to type "from each other"?  If so, my goal is to show overlapping leaves with the performance cost of only a single image.  Are you suggesting that I manage one image of the leaves plus one image of the branches?  Surely I do not want to manage a hundred images for individual leaves in distinct positions.

I had a problem of black seams surrounding some of my png images.  It turns out they were being exported weird by Paint.Net, but if I used Photoshop they were perfectly fine.

Based on the picture you posted, the black edge you see is at the end of the image. I am thinking now maybe texture border or wrap/clamp being set incorrectly.

As for the blending issue, there's a industry-standard solution to fix it but I don't recall it right now. Search for "Vegetation rendering"

SomethingNew said:

I had a problem of black seams surrounding some of my png images.  It turns out they were being exported weird by Paint.Net, but if I used Photoshop they were perfectly fine.


I looked the image up and down, inverted it, played with the levels, examined the histogram, etc.  It's clean.

I've encountered this problem many times with java2d and with translucent images interpolation in general.



The perfect solution: use a premultiplied alpha blending pipeline (this means a little nightmare for your OpenGL implementation). That's what I'm doing in my implementation.



The quick solution: try to set the texture's translucent pixels (i.e. the pixels with alpha == 0) to 0x00ffffff (white transparent). This will produce a interpolation towards white instead of black. It should look nicer, but now you'll have a white border instead of black.



I wrote a report to SUN some time ago about a similar topic (now fixed): http://bugs.sun.com/view_bug.do?bug_id=4950176


Another thought that just occurred to me: What wrap mode are you using on your texture? Try EdgeClamp and Clamp if you haven't yet.

MikOfClassX, I don't think this is the problem blaine is having. The first one, with the black edge being visible, implies there's a black border around the texture, since otherwise the blackness would appear in other places, this leads me to believe wrap/clamp and border setting are incorrect. The 2nd problem, with parts of the leaves being see-through to skybox, are due to triangle-ordering in the mesh.

The triangles in front of the camera, are rendered first and write their Z value to the depth buffer, only near the edges (where alpha > 0) because alpha-test is turned on (turn off alpha test to magnify this problem), they are also blended correctly with the skybox where alpha < 1.

The triangles behind the camera, are rendered last and fail to pass the Z test near the leaves, thus instead of seeing the back triangles in that place you see skybox blended with front leaves.



The solution, which I found by searching "Vegetation rendering":

Pass1: Render tree with blending off, alphatest on, reference = 1 and test = equal (this renders opaque parts of tree only)

Pass2: Render tree with alphatest off, blending on, and depth write off (this will render the transparent parts and blend them correctly)

Thanks Momoko_Fan and despotes for the seam fix!  I had copy and pasted my bark texturing code and carelessly included the wrap mode setting.  Seams gone!



Now for the texture combining problems…

@Momoko_fan

yep, I see. I was too fast in reading the Blaine's post  . I only looked at the "tree on white" picture which indeed shows the problem I was referring to. Cheers!

Momoko_Fan said:

The solution, which I found by searching "Vegetation rendering":
Pass1: Render tree with blending off, alphatest on, reference = 1 and test = equal (this renders opaque parts of tree only)
Pass2: Render tree with alphatest off, blending on, and depth write off (this will render the transparent parts and blend them correctly)

I tried.  May I have another serving of help please?

Most importantly, this completely destroys the trees if there is an interceding SharedNode, which is definitely a requirement in this case.  Here's what 2 SharedNode trees look like (this does not happen if I use standalone Tree instances without a SharedNode):



IF I can get around that problem, after I attempted to implement the Vegetation rendering technique suggested, I still have Z ordering or transparency problems.  I probably have done something wrong in the setup of RenderStates here.  (I see that even without a game engine inbetween, behavior like this is implemented so esoterically by OpenGL that even the OpenGL Gurus usually resort to just trying things until something works).


        ZBufferState zState = renderer.createZBufferState();
        zState.setEnabled(true);
        zState.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
        ZBufferState noZState = renderer.createZBufferState();
        noZState.setEnabled(false);

        BlendState blendState1 = renderer.createBlendState();
        blendState1.setEnabled(true);
        blendState1.setBlendEnabled(false);
        blendState1.setTestEnabled(true);
        blendState1.setReference(1f);
        blendState1.setTestFunction(BlendState.TestFunction.EqualTo);
        blendState1.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
        blendState1.setDestinationFunction(
                BlendState.DestinationFunction.OneMinusSourceAlpha);
        BlendState blendState2 = renderer.createBlendState();
        blendState2.setEnabled(true);
        blendState2.setBlendEnabled(true);

        PassNodeState passNodeState;
        passNodeState = new PassNodeState();
        passNodeState.setPassState(lBranchTexState);
        passNodeState.setPassState(blendState1);
        passNodeState.setPassState(zState);
        PassNode lbranches = new PassNode("passedLeftBranches");
        lbranches.addPass(passNodeState);
        passNodeState = new PassNodeState();
        passNodeState.setPassState(lBranchTexState);
        passNodeState.setPassState(blendState2);
        passNodeState.setPassState(noZState);
        lbranches.addPass(passNodeState);
        attachChild(lbranches);
        // ... and the same thing for the right side of branches, rBranch* etc.

noZState.setEnabled(false);


No, I said no Z-write, not no Z-test.


noZWriteState.setWriteEnabled(false);
noZWriteState.setFunction(TestFunction.Less);


this is correct ^

Momoko_Fan said:

noZState.setEnabled(false);


No, I said no Z-write, not no Z-test.


noZWriteState.setWriteEnabled(false);
noZWriteState.setFunction(TestFunction.Less);


this is correct ^


Thanks very much.  Works great for a standalone Tree.

The problem shown below where the tree is shared via SharedNode is preventing me from using this though.  I'll try moving around the RenderStates to satisfy ShareNode sharing-- if anybody has any tips, let me know.

I'm having the same problem with a transparent tree - it has a border around it that shows through the skybox texture even if another object is in between the tree and the skybox.



I'm following the advice from this thread it renders fine in a SimpleGame test but in my full game I get the skybox bleeding through and i'm using the same code to load the model and set up the passnode in the game as in the test yet I get different result.



Here's my code for setting up the passnode


      BlendState as = DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
      as.setBlendEnabled(true);
      as.setTestEnabled(true);
      as.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
      as.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
      as.setEnabled(true);
      as.setTestFunction(TestFunction.GreaterThan);
      treeNode.setRenderState(as);

      ZBufferState zState = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
      zState.setEnabled(true);
      zState.setFunction(ZBufferState.TestFunction.EqualTo);

      ZBufferState noZState = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
      noZState.setWritable(true);

      treeNode.setRenderState(noZState);
      PassNode passNode = new PassNode("treepassnode");
      passNode.attachChild(treeNode);

      BlendState disabledBlendState = DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
      disabledBlendState.setBlendEnabled(false);
      disabledBlendState.setEnabled(true);
      disabledBlendState.setReference(1f);

      passNode.setRenderState(disabledBlendState);
      passNode.setRenderState(zState);
      PassNodeState baseNodeState = new PassNodeState();
      baseNodeState.setPassState(noZState);
      passNode.addPass(baseNodeState);
      parentNode.attachChild(passNode);
      passNode.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);