Questions about SDK, AssetManager and AbstractControl

Hi everyone,
I would like to exploit the potential of the SDK and I have a question to ask.
What’s the best way to instantiate the AssetManager inside an AbstractControl added to the scene via the SDK?
For example, let’s say I want to add some geometry to a node or I want to do some stuff with the SDK that requires an AssetManager instance.

Are there downsides or better ways to create an assetManager like this:
new DesktopAssetManager(true) ?

Thanks.

image

public class MyControl extends AbstractControl {

    protected final AssetManager assetManager;
    private Material wireMat;

    public MyControl() {
        this.assetManager = new DesktopAssetManager(true);
        wireMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        wireMat.setColor("Color", ColorRGBA.Green);
        wireMat.getAdditionalRenderState().setWireframe(true);
    }

    @Override
    public void setSpatial(Spatial sp) {
        super.setSpatial(sp);

        if (spatial != null) {
            Mesh mesh = ...;
            spatial.breadthFirstTraversal(new SceneGraphVisitorAdapter() {
                @Override
                public void visit(Node node) {
                    Geometry geom = new Geometry(node.getName() + "-geom", mesh);
                    geom.setMaterial(wireMat);
                    node.attachChild(geom);
                }
            });
        }
    }

    @Override
    protected void controlUpdate(float tpf) {
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
    }

}

Is the intention to only use this control inside the SDK?

1 Like

The downside with multiple asset managers is that they will cache assets separately which means more memory usage. So if you load the same model by different asset managers each will keep its own cache… a better approach might be to use the singleton pattern, for example, Lemur GuiGlobal has static methods for creating material,…

1 Like

Thanks for the quick replies.

Yes, at the moment I plan to use this trick only with the SDK to test the 3D models or view some elements of the files containing only animations. Once the scene editor is closed the cache is emptied right?

Edit:
Thanks @Ali_RS . Based on your explanation, my approach is definitely not recommended in a game application, but may be fine only for debugging purposes with the SDK.

AFAIK that’s the best way to do it.

I use the no-arg constructor in my automated tests, but that requires explicitly configuring the necessary locators and/or loaders.

1 Like

I’d still like to know more about the use-case. Perhaps it could be incorporated into the SDK somehow.

1 Like

Thanks so much for the advice guys.

Sure, give me some time and I’ll show you a video with all the details of the use case.

I think jme-sdk already has its own AssetManager; as it utilizes jMonkeyEngine core, idk if it’s accessible through your control, but why not using getApplication().getAssetManager() from your custom control?

Hi everyone,
here is a simple tutorial to visualize the nodes of a file containing only the animation data using the features provided by the jMonkeyEngine SDK.

Any suggestion is always welcome.

6 Likes

I tried to use the SkeletonVisualizer from the Heart library with the SDK but I get the following error.

Source Code:

package mygame.ui;

import com.jme3.anim.SkinningControl;
import com.jme3.asset.AssetManager;
import com.jme3.asset.DesktopAssetManager;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import java.util.Objects;
import jme3utilities.debug.SkeletonVisualizer;

/**
 *
 * @author capdevon
 */
public class SkeletonViewer extends AbstractControl {

    protected final AssetManager assetManager;
    private SkeletonVisualizer sv;

    public SkeletonViewer() {
        this.assetManager = new DesktopAssetManager(true);
    }

    @Override
    public void setSpatial(Spatial sp) {
        super.setSpatial(sp);

        if (spatial != null) {
            SkinningControl skinningControl = spatial.getControl(SkinningControl.class);
            Objects.requireNonNull(skinningControl, "SkinningControl not found: " + spatial);

            sv = new SkeletonVisualizer(assetManager, skinningControl);
            spatial.addControl(sv);
            sv.setEnabled(true);
            sv.setHeadColor(ColorRGBA.Green);
        }
    }

    @Override
    protected void controlUpdate(float f) {
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
    }

}

Stack Trace:

com.jme3.asset.AssetNotFoundException: MatDefs/wireframe/multicolor2.j3md
	at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:385)
	at com.jme3.material.Material.<init>(Material.java:105)
	at jme3utilities.MyAsset.createMulticolor2Material(MyAsset.java:235)
	at jme3utilities.debug.SkeletonVisualizer.<init>(SkeletonVisualizer.java:194)
	at mygame.ui.SkeletonViewer.setSpatial(SkeletonViewer.java:35)
	at com.jme3.scene.Spatial.addControl(Spatial.java:777)
	at com.jme3.gde.core.sceneexplorer.nodes.actions.AbstractNewControlWizardAction$1$1.call(AbstractNewControlWizardAction.java:75)
	at com.jme3.gde.core.sceneexplorer.nodes.actions.AbstractNewControlWizardAction$1$1.call(AbstractNewControlWizardAction.java:70)
	at com.jme3.app.AppTask.invoke(AppTask.java:147)
	at com.jme3.app.LegacyApplication.runQueuedTasks(LegacyApplication.java:759)
	at com.jme3.app.LegacyApplication.update(LegacyApplication.java:775)
	at com.jme3.gde.core.scene.SceneApplication.update(SceneApplication.java:296)
	at com.jme3.system.awt.AwtPanelsContext.updateInThread(AwtPanelsContext.java:237)
	at com.jme3.system.awt.AwtPanelsContext.access$200(AwtPanelsContext.java:46)
	at com.jme3.system.awt.AwtPanelsContext$AwtPanelsListener.update(AwtPanelsContext.java:80)
	at com.jme3.system.lwjgl.LwjglOffscreenBuffer.runLoop(LwjglOffscreenBuffer.java:126)
	at com.jme3.system.lwjgl.LwjglOffscreenBuffer.run(LwjglOffscreenBuffer.java:160)
	at java.base/java.lang.Thread.run(Thread.java:1589)

I added the Heart-8.3.2.jar to the project libraries as shown in the picture. Am I forgetting something?

The multicolor2.j3md file is contained in the Heart library jar file.

Edit:

Could it be due to this? How should I configure the AssetManager?

The first thing to check: does the asset manager in the stack trace include a classpath locator? If there’s no such locator, it won’t be able to load assets from the classpath.

2 Likes

I tried like this, but I get the same error.

    public SkeletonViewer() {
        this.assetManager = new DesktopAssetManager();
        assetManager.registerLoader(J3MLoader.class, "j3m", "j3md");
        assetManager.registerLocator(".", FileLocator.class);
        assetManager.registerLocator("/", ClasspathLocator.class);
    }

Edit:
I can’t use debug mode to check the assetManager variables, because I’m adding the controller to the node with the SDK. I’ve tried putting System.outs in the controller constructor, but nothing appears on the console.
Is there a way to print messages to the console when I add a controller to a node with the SDK?

I tried that too, but it doesn’t print anything to the console.

public class SkeletonViewer extends AbstractControl {

    private static final Logger logger = Logger.getLogger(SkeletonViewer.class.getName());

    protected final AssetManager assetManager;
    private SkeletonVisualizer sv;
	
    public SkeletonViewer() {
        ...
        System.out.println("Hello!");
        logger.log(Level.WARNING, "Hello!");
    }
	
}