Question

I'm using Java3D to visualize a room with some primitives in it. I have an image background that I tile so that it fills the entire frame using background.setImageScaleMode(Background.SCALE_REPEAT);. Now I would like to add another semitransparent background on top of this background, and I would like to stretch it to cover the screen using SCALE_FIT_ALL. This will create an image effect that I cannot otherwise achieve. However, when I try to do this Java 3D complains that Group.addChild: child already has a parent.

Other ways of doing the same thing without using backgrounds (e.g. draw it on a 2D primitive) would be a interest too.

So my question is how can I achieve what I want with Java3D?

MWE: Image are available here. I want to draw bg-stars.png with Background.SCALE_REPEAT and then on top of that bg-glow.png with Background.SCALE_FIT_ALL.

Was it helpful?

Solution

Probably not what you actually want to achieve, but too long for a comment:

I did a test of adding multiple Backgrounds, and it "worked" basically (that is: it did not cause an error message). But the documentation of Background says

If multiple Background nodes are active, the Background node that is "closest" to the eye will be used.

Thus, I assume that it is not possible at all to display multiple backgrounds simulataneously at all.

Depending on what you want to achieve, there are probably several possibilities. The following it one approach that might be "close" to what you want. But I am not familiar with Backgrounds in Java3D, and assume that there are more elegant, efficient, flexible (or simply: better) approaches (like creating a huge, semi-transparent quad with the overlay texture or whatever...)

However, the idea here was to create the background as a single image. Composing BufferedImages is rather easy and offers a lot of possibilities. So I'm taking the bg-stars.png image and create a "tiled" version of this image (large enough to fill a certain area - in practice, this could simply be made as large as the maximum screen size). Then I'm composing this with the "overlay" image, bg-glow.png, by just painting it over the tiled image.

The resulting image can then be used to create the Background.

At the first glance, the result may look like what you want to achieve, but of course, there may be some caveats. E.g. one has to think about how this could be implemented to adapt to changes of the window size. (Listening for this with a ComponentListener and updating the image would be easy, but ... well).

And again: There certainly are better solutions. But maybe this can at least serve as a workaround until you find the better solution.

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class SimpleBackgroundTest extends Applet
{
    private static final int WIDTH = 1200;
    private static final int HEIGHT = 1200;

    public static void main(String[] args) throws IOException
    {
        System.setProperty("sun.awt.noerasebackground", "true");
        Frame frame = new MainFrame(new SimpleBackgroundTest(), WIDTH, HEIGHT);
    }

    public SimpleBackgroundTest()
    {
        setLayout(new BorderLayout());
        Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
        add("Center", c);

        BranchGroup group = new BranchGroup();
        group.addChild(createSomeCube());

        BufferedImage stars = null;
        BufferedImage glow = null;
        try
        {
            stars = ImageIO.read(new File("bg-stars.png"));
            glow = ImageIO.read(new File("bg-glow.png"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        BufferedImage tiled = createTiled(stars, WIDTH, HEIGHT);
        BufferedImage overlay = createOverlay(tiled, glow);

        Background background = createBackground(overlay);
        group.addChild(background);

        SimpleUniverse universe = new SimpleUniverse(c);
        universe.addBranchGraph(group);
        universe.getViewingPlatform().setNominalViewingTransform();
    }

    private static BufferedImage createTiled(
        BufferedImage image, int targetSizeX, int targetSizeY)
    {
        BufferedImage result = new BufferedImage(
            targetSizeX, targetSizeY,
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = result.createGraphics();
        for (int x = 0; x < targetSizeX; x += image.getWidth())
        {
            for (int y = 0; y < targetSizeY; y += image.getHeight())
            {
                g.drawImage(image, x, y, null);
            }
        }
        g.dispose();
        return result;
    }

    private static BufferedImage createOverlay(
        BufferedImage image, BufferedImage overlay)
    {
        BufferedImage result = new BufferedImage(
            image.getWidth(), image.getHeight(), 
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = result.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.drawImage(overlay, 0, 0, image.getWidth(), image.getHeight(), null);
        g.dispose();
        return result;
    }

    private static Background createBackground(BufferedImage image)
    {
        TextureLoader textureLoader = new TextureLoader(image);
        ImageComponent2D imageComponent = textureLoader.getImage();
        Background background = new Background();
        background.setImage(imageComponent);
        background.setImageScaleMode(Background.SCALE_FIT_ALL);
        background.setCapability(Background.ALLOW_IMAGE_WRITE);
        background.setApplicationBounds(new BoundingSphere());
        return background;
    }

    private TransformGroup createSomeCube()
    {
        ColorCube cube = new ColorCube(0.5f);
        Transform3D t = new Transform3D();
        t.rotY(0.2);
        t.setScale(0.1);
        TransformGroup tg = new TransformGroup();
        tg.setTransform(t);
        tg.removeAllChildren();
        tg.addChild(cube);
        return tg;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top