I’m building a voxel game which involves generating cube shaped chunks, each with a mesh. Each mesh vertex has a colour generated, and at the moment, all colours have alpha set to 0.5, so that the entire world is transparent.
The problem is that the transparency changes around the chunk borders:
The brick pattern marks the edges of the chunk and mesh. Note the top right corner of the platform having different alpha blending compared to the left and right corners, the unwanted effect changes at the chunk border.
This strange blending flickers to other chunks as I rotate the camera around the central point.
Here’s my Material code:
Texture tex = assetManager.loadTexture("Textures/blocks.png");
Material mat = new Material(assetManager, "Materials/SassLighting.j3md");
mat.setBoolean("UseVertexColor", true); // activates our custom colour lighting
mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); // just for debugging
// ... for each chunk, create mesh and geom. then for chunk:
If I comment out
geom.updateModelBound() there’s a clue, it suddenly looks acceptable, albiet missing nearer chunks:
If I rotate the camera now, the black nearby bits flicker in the same pattern as the artifacts in the previous image.
I suspect the problem might be something to do with culling?
Any ideas are most welcome!
Have you read “Transparency for dummies”? There’s a link at the top of this webpage.
Aye, I got some of my code from that thread. But seem to be missing something.
I changed this:
Also got rid of the FaceCullMode.Off param
EDIT: It looks better but now the thing in front is all washed out
float extent = 4;
geom.setModelBound(new BoundingBox(new Vector3f(extent, extent, extent), extent, extent, extent));
This fixes my test case. My problem was that updateModelBound() was calculating the center of the mesh according to the geom inside, when it should have been the boundaries of the whole chunk.
But there are still problems when individual blocks are placed. This seems because the bucket sorter only works on entire geoms, rather than vertices within the geom.
It seems like segregating meshes into one per face will solve it, since the bucket sorter will be able to work on the individual faces rather than whole chunks… more computationally expensive but seems like the only solution
You have to render all of the opaque geometry first. Your opaque surfaces should go into mesh/geometry in the Opaque bucket.
Then render all of the transparent geometry. Your transparent surfaces should go into mesh/geometry in the Transparent bucket… AND be sorted from back to front within a mesh.
The transparencty for dummies article lays this out pretty well. If something is drawn first, it fills the Z-buffer… nothing else will be drawn there. Transparency must be rendered back to front or… you can disable depth write but then you will have other artifacts.
Yeah it seems to be all about the render order.
I’ve just solved it using separate Geoms for each cube face, rather than one per chunk, so I can get the order right on a cube face level. I have assigned all those face Geoms to the Transparent QueueBucket.
But now one of my CPUs is getting chewed out. Looks like I’ve now got a lot more Geoms in the queue, and they are having to get sorted every frame.
makes an order of magnitude more geometries… then wonders about whether there are a lot of them…
Heheh… Obviously that is not a solution. But I think you know that. But I already said the solution so I won’t repeat it here.
Aye, I can probably save a lot of cycles by using the 2 buckets like you said.
What I’m aiming for though is a way to arbitrarily change the alpha on every face, so I can hide bits of scenery depending on the field of view. That’s why I set the alpha on everything, to test the worst case scenario.
Then you will need to sort all of your faces back to front.
I just added an opaque object and after trying both the Opaque and Transparent buckets, found it must go into Transparent for it to render correctly against the rest of the transparent scene.
I wonder whether the sorting already automatically excludes stuff outside the view frustum? If it doesn’t, I could prune out the geoms that are out of camera range and potentially get a performance improvement
A teeny teeny tiny itsy bitsy one maybe.
Your whole approach is flawed for a few reasons:
- draw calls are going to kill performance… always. You should be targeting around 100 geometries for a scene like this.
- the sorting that JME does for Geometries is actually going to be really bad for flat surfaces like you have… it’s going to get the answer wrong sometimes. There is no perfect way to sort transparent objects and JME makes a compromise.
To perform well you are going to need to construct your own mesh with the surfaces pre-sorted.
You have three options, really:
- bad visuals
- abysmally slow visuals
- do it like I said
Thanks for the advice!
I would like to try the pre-sorted mesh approach that you have described. But I guess I’d need to build a new one for each camera angle? E.g. if the camera is pointing N, and it is rotated to S, I imagine the sorting will be wrong and need to be corrected?
Thankfully the mesh create code is really fast, so it shouldn’t be a problem. I can swap the pre-created meshes as the camera rotates.
Your screen shots made it look like your game was from a fixed camera angle.
I suspect going forward that your love-hate relationship with transparency is going to turn into a hate-hate as you figure out why no games do what you are trying to do.
You might be right. I want to keep trying though. The presorted meshes are going to be faster, so worth a shot at implementing.