I don’t really understand why it happens. I guess it is due to my shader. When moving the camera, inPosition in WorldViewProjection may be have some rounding error when calculate floating-point numbers.
Are your maps batched as one geometry or are they separate geometries? I guess they are not in the Gui bucket?
As to your gaps, I’m not sure what you mean about “moving the camera” as the most logical thing would have been to put all of this in the Gui bucket and just move them around instead of moving a camera. Gaps shouldn’t happen unless the right coordinate of one tile doesn’t exactly match the left coordinate of the next tile.
Just a note: once you’ve batched tiles together then they are rendered in the order they were batched.
Also a note: distance based sorting in the Transparent bucket is based on nearest distance to camera.
For tiles, it should be 100% possible to sort them properly presuming you can get JME to render them in the proper order. You shouldn’t even need any alpha discard threshold.
The Gui bucket is more forgiving for 2D stuff as it will sort based solely on the world Z of the object and not “nearest point to camera”.
Edit: also because there is no z-buffer in the GUI bucket there is no ambiguity about tile order. It’s either rendered properly or not, not partially rendered with odd borders.
I set the QueueBucket of BatchNode to Transparent before batch, then some thing interesting happend.
The spatial become transparent when I move camera location into their “area”.
I think I need some other solutions before I can handle this messs. I need to read the source of com.jme3.renderer.*. The transparency makes me crazy.:chimpanzee_lobotized:
Maybe I can paint the layers to an Image with ImageRaster, or move to XOY plane again and use Gui bucket as your advice.
Before everything I’m going to play DOTA2 and kill as many noobs as I can…:chimpanzee_mad:
It’s not hard. The renderer has nothing to do with this.
Spatials get sorted. They are sorted before rendering. So they are rendered in sorted order.
In the opaque bucket, they are rendered front to back… based on the closest point to the camera.
In the transparent bucket, they are rendered back to front… based on the closest point to the camera. Note this may not always be what you might logically think is the closest point. For 2D objects it is the single dumbest way to sort objects. I mean, other than just randomly sorting them however.
In the Gui bucket, they are rendered back to front by their getWorldTransform().z position. This is the simplest sorting ever and the simplest to control… and makes perfect sense in 2D objects. Also, there is no z-buffer… so you won’t ever (never ever) get the weird ‘halos leaking colors’ stuff you do in other buckets.
Once objects are batched, they are never sorted again. Never. They are batched. They are part of one big mesh now. The mesh will always render those triangles in exactly the same order… the order they were batched. Setting the bucket before is identical to setting the bucket after. It makes no difference.
Only the outer batched spatial is ever sorted… by ‘point nearest to camera’… which is now even more bizarre than it was before.
Ultimately, you will be a thousand times better off (and a thousand times more efficient) creating your own already-batched meshes in exactly the order you want… then putting things in the Gui bucket.
Thank you paul, it works! This is what I did (after killing 12 noobs in DOTA2).
First I change every geometry’s queuebucket to Bucket.Gui.
Geometry geometry = new Geometry(name, mesh);
geometry.setQueueBucket(Bucket.Gui);
if (useSharedImage) {
geometry.setMaterial(sharedMat);
} else {
geometry.setMaterial(tile.getMaterial());
}
Then render the map as usual.
Node node = new Node("Tiled Map");
int len = map.getLayerCount();
int layerCnt = 0;
for (int i = 0; i < len; i++) {
Layer layer = map.getLayer(i);
// skip invisible layer
if (!layer.isVisible()) {
continue;
}
Spatial visual = null;
if (layer instanceof TileLayer) {
visual = mapRender.render((TileLayer) layer);
}
if (layer instanceof ObjectLayer) {
visual = mapRender.render((ObjectLayer) layer);
}
if (layer instanceof ImageLayer) {
visual = mapRender.render((ImageLayer) layer);
}
if (visual != null) {
node.attachChild(visual);
// this is a little magic to make let top layer block off the
// bottom layer
visual.setLocalTranslation(0, layerCnt++, 0);
}
}
Rotate the map π/2 clockwise alone the X axis.
node.rotate(FastMath.HALF_PI, 0, 0);
move it to screen space.
Point size = mapRender.getSize();
int w = cam.getWidth();
int h = cam.getHeight();
node.move((w-size.x) * 0.5f, (h+size.y)*0.5f, 0);