Tranparency issues, with examples

My greeting to the community,
(feel free to skip over)
I’ve been reading this forum for months. I’ve learned heaps from everyone, thank you. Special appreciation goes out to Norman, who is tirelessly helping people on seemingly every post I read, and they go back years. I don’t know how you do it mate, but thank you for being so patient with all of us.

Transparency Issues:

Image#1:
This is a field of translucent cubes, as might be drawn by a cube-game engine with a chunk size of 10x10. What we see in this image is that the transparent meshes are cumulative with other meshes but we don’t see the meshes being cumulative with themselves. But this is only the case when we look in the positive-x, positive-z direction.


Image #2:
Same meshes viewed from the the other side, that is upstream into the negative-x, negative-z direction. From this direction they appear as expected. But as I will show, it’s not just about viewing direction.


Image #3:
Here we see a blob of blocks rendered as 1 or more custom meshes, (I wish I knew how many) with self accumulation working on one side and not on the other.


Image #4:
Same blob, same side, all I did was translate the camera to the left just a tad and the missing shading popped into view. If you look at the white crosshair in the red pickbox, you can see by how much the camera moved. The shading will reliably appear and disappear depending on the exact camera position. But that’s not the worst of it.


Image#5:
Data structure wise, we’re looking at some “land” blocks where they form a flat plain in the foreground and rise up a hill in the back. Then there is a layer of “water” blocks, exactly one block thick, laying over the land. So the water blocks form a stair-step pattern that mimics the land blocks The mesh renderer comes through intending to represent the water blocks as fully formed perfect cubes. Only the faces of the water cubes that are adjacent to air are drawn. Both the land and the water are on the same texture atlas and are drawn as the same mesh, with each individual mesh covering a 10x10 block area. So the water should as a whole form a closed skin with nothing inside. Each individual mesh however, is like a pair of floating blankets. One for the land skin and one for water skin.

Now this is the serious problem. At the edges of the individual meshes the transparent parts of the mesh will intermittently fail to render properly.


Image #6:
If I move the camera around a bit to get the error to flicker off, you can the see meshes are actually aligned and contiguous.

Things I’ve tried:
[java]setQueueBucket(Bucket.Transparent)[/java]
All 6 images are using Transparent QueueBucket.
If I don’t use Transparent QueueBucket, the problem is on every edge, everywhere, all the time. Using Transparent QueueBucket reduces the problem to about 10%, with flickering holes in some but not all meshes.

I’ve been through the settings on this page: Material Definitions Properties
[java]setDepthWrite[/java] The DepthWrite toggle did help with image #5, in that the cracks in the blue transparent water mesh
showed the brown mesh behind it instead of just showing sky. But it’s still horrible.

[java]setAlphaFallOff[/java] The setAlphaFallOff setting had no useful results. Tried values from 0.01 to 1.0. Values above 0.3 tended to make things disappear, if I recall correctly.

I tried putting the actual transparency into the texture, as well as getting there by setting the alpha of the verticies. No difference.

My research turned up this thread:
Transparency in Android
Even though I’m using a PC and not Android.

Thinking maybe my video card was the problem, I ran this program on another computer with different hardware. Same results. Both computers use Windows 7 ultimate 64bit.

I tried the “ShowNormals” material. The normals all appear to be correct.

I don’t know if these issues all stem from the same problem or if they’re 3 separate problems. They seem to all be related to the Z-buffer.
Thank you to anyone who bothers to try and help.

For transparency to render properly it has to be sorted back to front properly. The transparent bucket sorts at the Geometry level but that only goes so far.

Otherwise you have to do special tricks.

The water pictures concern me though since that implies that you are drawing the sides of your water blocks even when they abut another water block. Do you also draw the other invisible sides of your boxes? Block engines will never work well that way.

I’ve read a lot of your posts and interviews, it’s kind of an honor to get to talk with you.

The non-external surfaces of the “water blocks” are definitely not being drawn, just the faces adjacent to air. But I’ve tried it both ways, it doesn’t make any difference. It’s not like a z-fighting issue, it seems to happen when the edge of a mesh is transparent AND doesn’t form a closed shape AND there’s another mesh behind it. Closed shapes, no problem. Perfect 6-sided cubes work fine, even adjacent to themselves and solids. But for open edged meshes with transparency set for the edge verticies, edges don’t render properly when another mesh, either opaque or transparent, is behind it

In images 5 and 6, the solid faces and trans faces of each chunk are actually all part of one mesh per chunk. But later for pictures #1 through #4 I turned off the solid faces and had the engine just draw all external sides of the floating translucent blobs.

From your first two paragraphs it sounds like I’m supposed to be ordering my meshes somehow. But since they get attached to the root node literally several seconds apart as they get lighted and meshed, I can’t see where in the process I have an opportunity to sequence them.

If transparent objects are obscuring opaque objects then they are all in the transparent bucket somehow. For your water to be obscuring the sand or whatever, it had to have been drawn first. The opaque bucket is always (always) drawn before the transparent bucket. So I wonder if your opaque objects somehow ended up in the transparent bucket in those pictures.

I actually kind of have trouble following what’s going on in those water pictures. Is it solid water or the water is also in a stair-step pattern like the land?

Anyway, the transparent bucket is sorted for you from back to front at the Geometry level. It is sorted based on the point nearest to the camera on the bounding shape… which isn’t always right but there is no correct answer that works in all cases. Getting batched meshes to sort properly is tricky… and things like water blocks will really never self-sort properly when batched. Even in Mythruna it’s possible to construct arrangements of water blocks where one disappears when behind the other…

…but that being said, the worst of your issues (the opaque holes) is solvable. The others are just a glitch you may have to deal with. For most cases it doesn’t come up very often… or you start to see why people implement glass as fully transparent with some highlight splats. (By the way, the alphaDiscardThreshold or the AlphaFallof stuff is to handle the case where you have some fully or nearly-fully transparent pixels in your texture and want them to be discarded completely… like for leaves, grass, etc… or when you have glass implemented as fully transparent with a few highlight splats.)

re: the water and opaque stuff… are you using a texture atlas?

If so, you will have to have two separate atlases and batch opaque and transparent separately. There is no way around that.

I’m sorry I wasn’t clearer about images 5 and 6. Before I created my topic, I did read the posting FAQ on writing good questions. I’ve tried to be complete and include more instead of less, but it’s really difficult. heh.

Under image #5 I’ve added a lot of description to clarify what’s in the image. Both to answer your question and to aid future readers.

re: the water and opaque stuff… are you using a texture atlas?

I’m using a texture atlas, just like the documentation and tutorials taught me. I did put the transparent water in the same atlas with the opaque land and drew them as one mesh. I’m not using any “batching” yet, at least I don’t think so.

I gather you’re telling me I have to render water as a separate mesh so that I can put the water in the transparent bucket and the land in the opaque bucket. Even though this will increase the number of meshes and of course that is the worst thing for frame rate. But it sounds like you’re telling me that’s the way it has to be done. I assume it doesn’t matter if I use the same texture atlas for water, or no material at all, but I need the separate buckets.

This is kind of a different question, but occasionally I see people recommend a “Texture Array”. I see the class for it, but I can’t understand when to use it. Is this something I should be interested in?

1 Like

In order for your opaque geometry to be rendered correctly it will need to be rendered before the transparent geometry. The best way to do that is to have separate opaque and transparent geometry and put opaque in the opaque bucket and transparent in the transparent bucket.

Do you kind of understand what is happening with those gaps?

In general I understand the concepts you have been describing. I can imagine an arrangement like this:

where each object is occluding the other at the same time. No matter which object is drawn first, it will be wrong.

This would explain images 3 and 4. But honestly, the sky gaps in 5 and 6 make no sense to me. In image 5, even if every pixel in both meshes were drawn in random order, each pixel should represent either mesh A or mesh B or some combination. For the sky to show through, I guess meaning nothing at all was rendered for those pixels, seems very odd to me.

I do thank you for having taken the time to guide me to a solution though.

@viewedclearly said: In general I understand the concepts you have been describing. I can imagine an arrangement like this: where each object is occluding the other at the same time. No matter which object is drawn first, it will be wrong.

This would explain images 3 and 4. But honestly, the sky gaps in 5 and 6 make no sense to me. In image 5, even if every pixel in both meshes were drawn in random order, each pixel should represent either mesh A or mesh B or some combination. For the sky to show through, I guess meaning nothing at all was rendered for those pixels, seems very odd to me.

I do thank you for having taken the time to guide me to a solution though.

The sky shows through but is tinted by the transparency of the water. So the transparent triangles were rendered first and filled the z-buffer and then nothing else behind it was rendered after that. You can even see the highlighting of top face versus side face in some places.

P.S.: You can come up with an even simpler case where no sorting will work properly just by having two triangles intersect each other at an angle.

So the transparent triangles were rendered first and filled the z-buffer and then nothing else behind it was rendered after that

There it is, I get it now.

You’re right, the sky isn’t just sky. It’s water over sky. The problem with image 5 isn’t that one mesh is next to or in front of another mesh. The problem is that the mesh occludes itself and the JM Engine doesn’t know which part of the mesh to render first. It would have to sort every triangle in a mesh, far to near. It could do that, but apparently it does not.

If true, that would now also explain images 1 and 2, in that self accumulation of opacity is not a given. It occurs arbitrarily based on the order the triangles of a mesh are drawn. And that, apparently has a lot to do with their absolute positions on the coordinate grid.

Am I on the right track, the JM Engine could sort the triangles of a mesh by their individual distance from the camera, but it doesn’t?

@viewedclearly said: There it is, I get it now.

You’re right, the sky isn’t just sky. It’s water over sky. The problem with image 5 isn’t that one mesh is next to or in front of another mesh. The problem is that the mesh occludes itself and the JM Engine doesn’t know which part of the mesh to render first. It would have to sort every triangle in a mesh, far to near. It could do that, but apparently it does not.

a) it could not do that. It hands the mesh to your graphics card which renders it. JME would have to turn it into one Geometry per triangle to sort them.
b) it doesn’t 100% solve the problem anyway since even triangles can mutually occlude each other.

@viewedclearly said: If true, that would now also explain images 1 and 2, in that self accumulation of opacity is not a given. It occurs arbitrarily based on the order the triangles of a mesh are drawn. And that, apparently has a lot to do with their absolute positions on the coordinate grid.

The order of the triangles drawn has 100% to do with the order they are in the mesh.

@viewedclearly said: Am I on the right track, the JM Engine could sort the triangles of a mesh by their individual distance from the camera, but it doesn't?

No, it could not. Well, it could but frame times would be measured in days instead of milliseconds.

Note: transparency sorting has been a 3D graphics bugaboo almost as long as there has been 3D graphics. For some other approaches to the problem you can look up things like screen door rendering and stuff.

For accurate results, the graphics card would have to sort at the pixel level. Given how massively parallel things are going, it would not surprise me to see this someday… though it is not likely, I guess.

The order of the triangles drawn has 100% to do with the order they are in the mesh.

Hmm. The meshes in Image 5 were created by adding all the land faces first, and then a second pass through the data to add the water faces.

If i put all this together it means I’m still wrong. The problem isn’t with the meshes occluding themselves. That just happens to work correctly because of the order I’ve added the triangles to the mesh. The problem is the far meshes are being rendered first, but at their leading edges the water faces of the rear meshes are drawn before the land faces of the closer meshes. So the land isn’t getting drawn behind the water. This is why the gaps only manifest at the nearer edges of the meshes and not randomly all over the mesh.

Except that the explanation I just gave would cause the gaps to appear in a regular grid along all the leading edges, all the time. And this is exactly what happens when I use the [java]setDepthWrite(false)[/java] setting. So why then does the default setting of True for DepthWrite cause the gaps to be greatly reduced but not eliminated?

If you don’t write depth then there is no z-buffering at all. Whatever is drawn last is on top. If you do write depth then only things with less depth than what was rendered before will get drawn.

Where the two edges of the blocks meet, it looks like the closer ones are drawn first or something. I don’t know why.

I can only tell you the realities of how OpenGL rendering works and that if done properly, you can arrange things to look better than what you’ve got.

You will definitely want to separate the opaque mesh from the transparent mesh. You can’t always rely on tile sorting to handle every situation and opaque geometry is more efficient drawn front to back (as JME does it)… while transparent geometry needs to be drawn back to front. That’s why the different buckets exist.

Just a question - Do you use the “Cubes” plugin for jME? Cause there were a few transparency issues that I fixed in the newest version yesterday.

<cite>@pspeed said:</cite> Note: transparency sorting has been a 3D graphics bugaboo almost as long as there has been 3D graphics. For some other approaches to the problem you can look up things like screen door rendering and stuff.

For accurate results, the graphics card would have to sort at the pixel level. Given how massively parallel things are going, it would not surprise me to see this someday… though it is not likely, I guess.

Actually I was throwing around a concept for a layered z buffer last year, may have even posted it here somewhere.

The basic idea was that for each pixel you store rgbaz X times. When writing a new value to the pixel use the z value to sort it into them correctly. if a is 1 then wipe out everything beneath.

That would handle overlapping transparency for up to X objects. When adding an X+1 overlapping object you would use the same algorithm and then discard (merge?) the two “least significant” layers.

It does increase memory usage significantly (5*X values per pixel instead of 4 values) but should be fast and handle any possible transparency situation.

@zarch said: Actually I was throwing around a concept for a layered z buffer last year, may have even posted it here somewhere.

The basic idea was that for each pixel you store rgbaz X times. When writing a new value to the pixel use the z value to sort it into them correctly. if a is 1 then wipe out everything beneath.

That would handle overlapping transparency for up to X objects. When adding an X+1 overlapping object you would use the same algorithm and then discard (merge?) the two “least significant” layers.

It does increase memory usage significantly (5*X values per pixel instead of 4 values) but should be fast and handle any possible transparency situation.

Are you talking about something that a user could implement or something that graphics cards would have to implement? It would be interesting to see the graphics architecture that lets you read and write to the same buffer in the same pass. The Z-buffer is kind of a special thing.

<cite>@pspeed said:</cite> Are you talking about something that a user could implement or something that graphics cards would have to implement? It would be interesting to see the graphics architecture that lets you read and write to the same buffer in the same pass. The Z-buffer is kind of a special thing.

afaik http://www.opengl.org/registry/specs/EXT/shader_image_load_store.txt should do it

Okay Paul. I guess it’s enough to know what’s happening, if not exactly why. I’ve already re-coded for the things you’ve taught me here, the gaps are gone. The self shading issues, I can work around now that I understand them.

You’ve been a terrific help, I feel like my eyes have been opened. And you’ve made a friend today.