Overlaying transpatent pictures in GUI node

I’m trying to add some icons to the GUI node. I use two Pictures, one for the background and one for the actual content. Both the background and icon have transparency (useAlpha set to true when loading the image for Picture). Then I try to bring the content forward on Z axis so it would be in the foreground. No matter what value I use, the result is always completely random. Some of the icons are proper, but most are not. Which ones are correct also changes every time I relaunch the app.


I have checked out the Transparency for Dummies section but that looks like more for models than for GUI.
Here is the code I use to create Pictures:

    for (int i = 0; i < names.size(); i++){
        //Inset adding part pictures here
        Picture pic = new Picture("pic"), partPic = new Picture("part");
        pic.setImage(app.getAssetManager(), "Textures/partBG.png", true);
        pic.move(0, 0, -1);
        pic.setPosition(partPicSpacing * i, 0.07f);
        partPic.move(0, 0, 0.001f);
        partPic.setPosition(partPicSpacing * i, 0.07f);
        partPic.setImage(app.getAssetManager(), "Textures/parts/" + names.get(i), true);
        partsNode.attachChild(partPic);
        partsNode.attachChild(pic);
    }
    Spatial lastPic = partsNode.getChild(partsNode.getChildren().size() - 1);
    partsNode.setUserData("lastX", lastPic.getLocalTranslation().x);
    partsNode.setUserData("lastScale", lastPic.getLocalScale().x);
    partsNode.setUserData("originalScale", partsNode.getLocalScale().clone());
    
    GeometryBatchFactory.optimize(partsNode);
    this.app.getGuiNode().attachChild(partsNode);

EDIT: Seems like the problem is the GeometryBatchFactory.optimize() line. Anyone knows why?

Probably because it takes your nicely sortable separate objects and turns them into one big object that can no longer be sorted by Z value. So you get whatever sort order it decided to batch.

In my opinion, it would be nice if it provided a way to sort the geometries (custom comparator or whatever)… but I think the version that takes a list probably leaves them in that list order. So you might be able to hack around it.

Thanks for the explanation. Looks like I won’t be able to do a batch :frowning:

Why?
Did you try what paul said?

Sorting them by z-value, putting them into a list and then batch them with that list?

No, I didn’t really try it since I’m running low on time and I have things with higher priority to do right now than worrying about one batch not working. After I finish the actual editor I will revisit this.

I made a GeometryBatchFactoryUtil that can check useData to see if a geometry should be batched. Pretty happy of the results. Sure could be made better.

package com.cis.pipesandstuff.common;

import com.jme3.math.Transform;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import jme3tools.optimize.GeometryBatchFactory;

/**
 *
 * @author jo
 */
public class GeometryBatchFactoryUtil {
    public final static String FLAG_FOR_OPTIMIZE = "OPTIMIZE";
    
    public enum OptimizeFilter {
        OPAQUE, FLAGGED_FOR_OPTIMIZATION;
    }
    
    public static Node optimize(Node scene, boolean useLods, OptimizeFilter optimizeFilter){
        ArrayList<Geometry> geoms = new ArrayList<Geometry>();

        switch(optimizeFilter){
            case OPAQUE:
                gatherGeomsOpaque(scene, geoms);
                break;
            case FLAGGED_FOR_OPTIMIZATION:
                gatherGeomsFlagged(scene, geoms);
                break;
        }

        List<Geometry> batchedGeoms = GeometryBatchFactory.makeBatches(geoms, useLods);
        for (Geometry geom : batchedGeoms) {
            scene.attachChild(geom);
        }

        for (Iterator<Geometry> it = geoms.iterator(); it.hasNext();) {
            Geometry geometry = it.next();
            geometry.removeFromParent();
        }

        // Since the scene is returned unaltered the transform must be reset
        scene.setLocalTransform(Transform.IDENTITY);

        return scene;
    }
    
    private static void gatherGeomsOpaque(Spatial scene, List<Geometry> geoms) {
        if (scene instanceof Node) {
            Node node = (Node) scene;
            for (Spatial child : node.getChildren()) {
                gatherGeomsOpaque(child, geoms);
            }
        } else if (scene instanceof Geometry) {
            Geometry geometry = (Geometry)scene;
            if ( geometry.getQueueBucket() == Bucket.Opaque ) {
                geoms.add((Geometry) scene);
            }
        }
    }
    
    private static void gatherGeomsFlagged(Spatial scene, List<Geometry> geoms) {
        if (scene instanceof Node) {
            Node node = (Node) scene;
            for (Spatial child : node.getChildren()) {
                gatherGeomsFlagged(child, geoms);
            }
        } else if (scene instanceof Geometry) {
            Geometry geometry = (Geometry)scene;
            if ( geometry.getUserData(FLAG_FOR_OPTIMIZE) != null ) {
                geoms.add((Geometry) scene);
            }
        }
    }
    
}
1 Like

I think I can abandon this, since I don’t need batching anymore. For some reason my phone was falling back to OpenGL ES 1.0. Forcing it to use 2.0 increased my fps a ton and now I’m not really worrying about batching.