Attaching Indicators (Healthbars) to rootNode/SceneGraph

Is the first image with or without billboard? if with, then what is the billboard setup? What does it look like without the billboard control?

For the second, what did you set the preferred size too?

I think ultimately the setLocalScale() you want will be closer to 0.01.

It’s all without billboard currently and for the prefered size I tried multiple: (2f, 0.2f, 0f), (1f, 0.1f, 0f) and something with a z value but the output was always the same.

So you think it’s a scaling error? [Without scaling at all it looks like the first pic, only bigger]

Edit: localScale of 0.01 makes the bar look quite realistic and good but the Problem with the preferedSize stays
Edit2: The above picture #2 was taken with the line setSize(getPreferedSize()). It does make a difference. Without it I dont’t have the four edges z-fighting but still some rectangulars fighting somehow

Preferred size should be something like: 100, 10, 1

…then with a scale of 0.01.

Can you post a pic of that?

(Note: I started writing a Lemur Gem for this last night but didn’t finish… hopefully will finish tonight.)

Your scene is normal y up, yes?

Paul you’re the best :smiley: <3
It’s hard to wrap my head around the concept of scale vs. size though and why a too small size looks too huge (but I guess that might be because lemur doesn’t check for stupid users^^)

If I get that right, I now have: Size.x == 100 → 100 * 0.01 → 1 World Unit. Size.y == 10 → 0.1 World Unit etc. so it’s basically the multiplicator?

For the Billboard “Problem”: I have implemented an CameraAppState which basically takes the girl’s loc/rot and does some quaternion magic to have that over-the-sholder view.

What my problem is: When I don’t use Alignment.AXIS_Y, the pBar moves up and down as the camera/toon is looking up and down. I don’t want that. I want that it moves accordingly to my camera’s location only, Like when I am flying in the air, the tags have to point upwards, but other than that, they shoudn’t be bothered by my camera rotation.

I guess I just need to adopt the Billboard Control a bit :slight_smile:

Yeah, JME’s BillboardControl positions based on view angle and not based on relative location. I agree it’s unnerving to see things swerve around as you turn your head, if I get your description right. You will have to tweak your own BillboardControl if you want something different, I guess.

Regarding size versus scale, you can change the size of the progress bar too but then you basically have to change everything. All of the margins of the backgrounds, the z offsets, etc. are all defaulted to things that make sense in screen space. In screen space, a progress bar of 100x10 looks pretty good. So generally, it’s easier to make the progress bar look good in the easiest way and then scale the whole thing down for the scene.

That’s true for a lot of the default UI elements. Way easier to scale them down versus trying to catch all of the different ‘sizes’ that you’d have to change.

FYI: I’ve finished coding a Lemur Gems for adding decorators like this. The test app looks like this:

And here is a link to the commented source:

I will try to write up an official article soon.

Edit: note that some things like setting the default style and other things discussed in this thread may not work properly on the 3.0 compatible Lemur that you used. This demo was written with the latest Lemur release as of the writing… version: 1.5.1

1 Like

Hey again,
I am unable to Clone the spatial I attached the progress bar to because lemur.core.guiControl throws a CloneNotSupportedException, was this already fixed in a newer Version?

Sorry about that. A newer version won’t fix it either, I guess. Cloning GuiControl is not necessarily as straight-forward as one might think.

Can you give me more information about why you are cloning?

Sorry for the late reply, I was quite busy in the last days :confused:

Basically you can reproduce it by simply adding a progressBar somewhere in the SceneGraph (as a child to any spatial) and then trying to clone the spatial. This will recursively invoke clone on all children.

There is an easy workaround to this, you simply remove the progressBar from the Spatial and then rebuild the GUI for the cloned object.

In my case, I decided to not use clone as my other Controls weren’t really clone-friendly either and it would be a special case where cloning is needed (I now create a new instance or reuse the spatial when possible).

If I remember correctly, you need clonable for save/load anyway, so you might look into that, as basic load/save of a GUI won’t work then (An usecase would be to have a user-customizable (movable) gui. There you could simply save the elements)

Yes, which is why I’ve looked into it before.

The issue is that it’s hard to fix-up the layout’s children with the spatial’s children once cloned. Java cloning doesn’t easily support this kind of cross-referencing either… and JME’s is basically Java’s. I thought of (and designed) a different cloning mechanism that was more like serialization. It has a registry where you can find shared objects. It’s a pretty invasive change, though.

Anyway, there is a solution even within regular serialization, it’s just not trivial or straight forward and so far has been low priority.

Two question I came up with :smiley:

  1. When the NPCs walk (that essentially means: Changing their localRotation), the BillboardControl starts failing as it doesn’t take the parent’s rotation into account.

I basically know that multiplying quaternions means applying those “one by one”. So If I would modify the billboard’s localRotation by multiplying it with the negated parents Rotation, would that fix the issue?

  1. I tried to change the Color of the progress but the online ressources mainly focus on defining a style, but I want to change it during runtime.

My approach was:

Attributes attr = GuiGlobals.getInstance().getStyles().getSelector(progressBar.getValueIndicator().getElementId(), "glass");
attr.set("color", ColorRGBA.Red);
GuiGlobals.getInstance().getStyles().applyStyles(progressBar, progressBar.getValueIndicator().getElementId());

But that simply removed the outer (blackish) bar. I then tried it without the ValueIndicator but that didn’t change anything.

Where is my fault? :slight_smile:

Uh… JME’s billboard control should face the camera no matter what. Or is this a custom billboard control that you’ve written?

The javadoc would probably be helpful… don’t be afraid to poke at it.

Specifically:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/ProgressBar.html#getValueIndicator()

Styles won’t help you as they only setup the component during creation and not at runtime. To set the bar color at runtime set it’s color.

((ColoredComponent)myBar.getValueIndicator().getBackground()).setColor(someColor);

Presumes that the background component is one of the ColoredComponent implementations (QuadBackgroundComponent, TbtBackgroundComponent, etc.)… which it will be with any of the default stylings.

That solved it :smile:
Jep it’s still the JME Billboard Control under the following Setup:

Spatial
 -> BetterCharacterControl
 -> MyNPCControl
   -> Node nStatsBar (Transparent Bucket, has BillBoardControl)
     -> Lemur ProgressBar

Now the thing is, when I move the spatial (BCC.setViewDirection), the Billboard-Control isn’t facing the Camera. When the Spatial then rotates so it walks in the direction it intentionally spawned, the BillboardControl is facing the Camera again.

BillboardControl seems horribly broken then as it’s totally not supposed to work that way.

If it hasn’t been done yet then my question for that issue is, will JME saving/loading ever be abstracted so that custom implementations can be done by the developer? If it is already done I apologize, I have been away. Just got my hands on the alpha and liking it. :smiley:

You can already customize saving/loading of the classes you create. Is that what you are asking?

…which has nothing directly to do with cloning.

Holy shizzle, this new forum layout is so weird. You reply to a topic but it also posts your reply at the bottom.

My original reply to you:
If you already can then my question is moot. Good to know for my current little experiment. Just getting back into JME after a venture into LibGDX. JME seems more efficient for a big project.

So I created a test case and could track it down. Before opening a thread could you maybe confirm whether it’s broken or just misuse?

b.setAlignment(BillboardControl.Alignment.Screen); // This works fully
b.setAlignment(BillboardControl.Alignment.AxialZ); // Couldn't check, does wierd things :P 
b.setAlignment(BillboardControl.Alignment.AxialY); // This is the one I am using, leads to trouble
b.setAlignment(BillboardControl.Alignment.Camera); // This is like without BillBoard (and I used the flyCam here)

Note: They all work when applied to the parent axis (where they basically override the actual rotation) but not as a child axis.

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.control.BillboardControl;
import com.jme3.scene.shape.Quad;

public class Main extends SimpleApplication {

    Node n;
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp()
    {
        n = new Node("myNode");
        Node o = new Node("subNode");
        
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        
        Quad q = new Quad(1f, 1f);
        Geometry geom = new Geometry("Box", q);
        geom.setMaterial(mat);
        
        o.attachChild(geom);
        BillboardControl b = new BillboardControl();
        b.setAlignment(BillboardControl.Alignment.AxialY);
        o.addControl(b);
        
        n.attachChild(o);
        n.rotate(0f, FastMath.HALF_PI, 0f);
        
        rootNode.attachChild(n);        
        flyCam.setMoveSpeed(flyCam.getMoveSpeed() * 5f);
    }

    @Override
    public void simpleUpdate(float tpf)
    {
        n.rotate(0f, FastMath.HALF_PI * tpf, 0f);
    }
}

Edit: Checked the Code that comes with my 3.0 SDK:

In rotateScreenAligned (the one that works), there is:

if ( parent != null ) {
        rot =  parent.getWorldRotation().inverse().multLocal(rot);
        rot.normalizeLocal();
    }

This however is missing in rotateCameraAligned and rotateAxial. I will try to fix it and see if i can do it with my humble Quaternion skills :stuck_out_tongue:

Edit2: Adding that did partially work (Screen and Camera work, Axial only works if you DONT rotate the spatial (but you can move the camera))

I’m surprised they don’t all do this. If you want to take world space rotation and make it local then that’s what you have to do.

Not sure why it doesn’t work for axial Y.