NiftyImage displaying ViewPort image doesn't show textured objects properly

Hello,

I’m trying to add a custom view port inside a game and have encountered an interesting issue. When I get a texture from buffer used by my view port, put it into a Quad and attach to guiNode, everything works fine, but when I take the same texture and put it into NiftyImage to be rendered as element in niftyGUI, parts that are covered in texture become transparent.

Here is a code of a small text case:

public class Main extends SimpleApplication {

public static void main(String[] args) {
    Main app = new Main();
    app.setShowSettings(false);
    AppSettings settings = new AppSettings(true);
    settings.put("Width", 1280);
    settings.put("Height", 720);
    settings.put("Title", "JME3 testing");
    settings.put("VSync", true);
    settings.put("Samples", 4);
    app.setSettings(settings);
    app.setPauseOnLostFocus(false);

    app.start();
}

@Override
public void simpleInitApp() {
    initLights();
    initBoxWithTexture();
    initBoxWithColor();

    initCameraWithRotation();

    Texture2D tex1 = initDirectViewPort();
    Geometry camView = new Geometry("selection camera view node", new Quad(300, 200));
    Material camMaterial = new Material(getAssetManager(),
            "Common/MatDefs/Misc/Unshaded.j3md");
    camMaterial.setTexture("ColorMap", tex1);
    camView.setMaterial(camMaterial);
    camView.setLocalTranslation(300, 100, 0);
    guiNode.attachChild(camView);

    Nifty nifty = initNifty();

    Element image1 = nifty.getScreen("start").findElementById("image1");
    image1.getRenderer(ImageRenderer.class).setImage(
            new NiftyImage(nifty.getRenderEngine(), new RenderImageJme(tex1)));
}

private Texture2D initDirectViewPort() {
    ViewPort modelView = getRenderManager().createMainView("view", cam);
    modelView.setClearFlags(true, true, true);
    Texture2D texture2D = new Texture2D(300, 200, Image.Format.RGBA8);
    FrameBuffer offBuffer = new FrameBuffer(300, 200, 1);
    offBuffer.setDepthBuffer(Image.Format.Depth);
    offBuffer.setColorTexture(texture2D);
    modelView.setOutputFrameBuffer(offBuffer);
    modelView.attachScene(rootNode);

    return texture2D;
}

private void initCameraWithRotation() {
    cam.setLocation(new Vector3f(0, -3, -5));
    cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

    stateManager.attach(new AbstractAppState() {

        private float rotation = 0;

        public void update(float tpf) {
            rotation += tpf/5;

            cam.setLocation(new Vector3f(5 * FastMath.sin(rotation), 3, 5 * FastMath.cos(rotation)));
            cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
        }

    });
}

private void initBoxWithTexture() {
    Geometry box = new Geometry("box", new Box(1, 1, 1));
    Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
    material.setTexture("DiffuseMap", assetManager.loadTexture("sun.jpg"));
    material.setBoolean("UseMaterialColors", true);
    material.setColor("Ambient", ColorRGBA.White);
    material.setFloat("Shininess", 0f);
    box.setMaterial(material);
    box.setLocalTranslation(1.2f, 0, 0);
    rootNode.attachChild(box);
}

private void initBoxWithColor() {
    Geometry box = new Geometry("box", new Box(1, 1, 1));
    Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
    material.setColor("Diffuse", ColorRGBA.Brown);
    material.setBoolean("UseMaterialColors", true);
    material.setColor("Ambient", ColorRGBA.White);
    material.setFloat("Shininess", 0f);
    box.setMaterial(material);
    box.setLocalTranslation(-1.2f, 0, 0);
    rootNode.attachChild(box);
}

private void initLights() {
    AmbientLight ambient = new AmbientLight();
    ambient.setColor(ColorRGBA.White.mult(0.3f));
    rootNode.addLight(ambient);

    DirectionalLight directionalLight = new DirectionalLight();
    directionalLight.setColor(ColorRGBA.White.mult(0.7f));
    directionalLight.setDirection(new Vector3f(1, -1, 1).normalize());
    rootNode.addLight(directionalLight);

}

private Nifty initNifty() {
    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(
            assetManager,
            inputManager,
            getAudioRenderer(),
            getGuiViewPort());
    Nifty nifty = niftyDisplay.getNifty();
    nifty.fromXml("nifty.xml", "start");

    Camera guiCam = new Camera(settings.getWidth(), settings.getHeight());
    ViewPort niftyGuiViewPort = getRenderManager().createPostView("Nifty GUI", guiCam);
    niftyGuiViewPort.addProcessor(niftyDisplay);
    niftyGuiViewPort.setClearFlags(false, false, false);

    return nifty;
}
}

plus nifty.xml:

<?xml version="1.0" encoding="UTF-8"?>
<nifty xmlns="http://nifty-gui.sourceforge.net/nifty-1.3.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd">
<useStyles filename="nifty-default-styles.xml"/>
<useControls filename="nifty-default-controls.xml"/>

<screen id="start">
    <layer id="foreground" childLayout="center">
        <panel height="100%" width="100%" valign="center" align="center" childLayout="vertical">
            <panel width="100%" height="50px"/>
            <panel width="100%" height="200px" childLayout="horizontal">
                <panel width="300px" height="100%"/>
                <panel width="300px" height="100%" childLayout="center">
                    <image id="image1" width="100%" height="100%"/>
                </panel>
            </panel>
        </panel>
    </layer>
</screen>
</nifty>

result is following:

Both views are using the same texture and should look the same as main view. Top left view is one from niftyImage, bottom left is Quad on guiNode - as you can see, top one was displayed with transparent background and displayed part of textured box became transparent also - but colored box is displayed ok.

Is this some kind of bug in niftyGUI rendering images from view ports or some kind of misconfiguration on my part?

That code looks slightly different compared to the way I’ve found works with Nifty. I’ve noticed Nifty can be particular about the way you do things and a lot of code that looks like it should work ends up not working.

Try using this code instead to reference your texture as an asset - this works for me so hopefully it will work in your case.

String img = "Textures/someImage.png";
iamge1.getRenderer(ImageRenderer.class).setImage(nifty.createImage(img, true));

But he wants the image that he rendered… not an image in his assets folder.

You’re right I overlooked that part. Hopefully someone who’s tried this before can help and this isn’t just a broken Nifty feature, I’ve ran into a lot of trouble trying to figure out full-proof ways to do certain things with Nifty and encountered enough broken methods and controls within Nifty that I’d probably choose Lemur if I weren’t already in so far with Nifty myself, and if I had known about it when I started with JME.

You can use them together… Lemur is not some huge monolithic thing like Nifty anyway. If you want a button somewhere just put a button somewhere. No messing with screens or controllers or XML or anything.

Button b = new Button("my button");
b.setLocalTranslation(400, 400, 0);
guiNode.attachChild(b);

Or plopping an image on screen:

Panel p = new Panel();
p.setBackground(new QuadBackgroundComponent(theTexture));
p.setPreferredSize(new Vector3f(100, 100, 1));
p.setLocalTranslation(400, 400, 0);
guiNode.attachChild(p);

I always hesitate to glom onto nifty-related threads, though. It’s rarely helpful to say “change your whole UI library”… but in these simple cases, also remember that you don’t have to.

1 Like

That’s useful to know, I’ve previously looked at it as a “one or the other” type situation but I’ll have to keep that in mind and try out lemur the next time I’m having trouble doing something fancy or unusual with nifty.

In regards to the initial issue with Nifty, the only other thing I could think of is to try using this code and that could fix the transparency problem. Otherwise maybe try playing around with all the methods for your RendererEngine and your RenderImage object before you try generating the NiftyImage.

nifty.getRenderEngine().setBlendMode(BlendMode.Alpha);

True, but I can do something like:

    getAssetManager().addToCache(new TextureKey("image-key"), tex1);
    image1.getRenderer(ImageRenderer.class).setImage(nifty.createImage("image-key", true));

Which unfortunately renders the same result.

That unfortunately I can’t do, because Nifty’s BlendMode are not the same as JME3 BlendMode - there is no value BlendMode.Alpha - however value BlendMode.MULTIPLY (instead of default BlendMode.BLEND) brought interesting results.

Setting

nifty.getRenderEngine().setBlendMode(BlendMode.MULIPLY);

And adding white quad in the background to make the effect more visible

    Geometry background = new Geometry("selection camera view node", new Quad(200, 150));
    Material bgMaterial = new Material(getAssetManager(),
            "Common/MatDefs/Misc/Unshaded.j3md");
    bgMaterial.setColor("Color", ColorRGBA.White);
    background.setMaterial(bgMaterial);
    background.setLocalTranslation(300, 400, 0);
    guiNode.attachChild(background);

Rendered the following result:
https://ibin.co/w800/3ey2GEWdHIdr.png

Which means that textured parts are in fact somewhere in the rendered texture, they are just not displayed due to some problem with alpha channel.

Thanks, yaRnMcDonuts, for the suggestion, I will investigate more and get back with results.

Or depth or camera frustum?
For reference; I did a “recipe” for this in the Cookbook, but it was for a minimap, so the camera settings were different. It worked fine there. I glanced over the code for it and it seems to be set up pretty much in the same way as this. That said, it was made 3 years ago at least.

One difference I saw was this:
NiftyImage image = nifty.createImage(scene.getName() + "_mini.png", true);
screen.findElementByName("minimap").getRenderer(ImageRenderer.class).setImage(image);

1 Like

Pretty sure the create image step is important in nifty for displaying images. I know that’s how they do it on the wiki.