Update: you can launch a WebStart version of the demo.
Have you ever wondered how to use nice 3D components with Swing? Java3D is the way to go. Yet, at a first glance, Java3D does not let you integrate 3D scenes smoothly in your UI. If you saw the Microsoft's Avalon demo videos you know what I'm talking about. Avalon won't be available before months (some say years) but Java and Java3D are already here.
With a simple trick you can create visual stunning Swing applications. Here is an example:
Notice the gradient background I've put here to show the unity between Swing and Java3D. Before getting into the details, let's see what this application is capable of. I called this demo AmazonPick because it would be a great UI for a book searching application. When books match your query, they are displayed as buttons at the bottom of the window (in this case, the buttons are hard coded). Whenever you click one of them, the 3D “book” flips to show a new cover on the other side. Neat effect.
To achieve this I simply created a Java3D texture on which I painted the frame's background. Here is the source code,
xpanel being the frame's content pane and
c3d being the
Canvas3D in which the scene is rendered:
BufferedImage image = new BufferedImage(xpanel.getWidth(), xpanel.getHeight(), BufferedImage.TYPE_INT_RGB); getContentPane().paint(image.getGraphics()); BufferedImage subImage = new BufferedImage(CANVAS3D_WIDTH, CANVAS3D_HEIGHT, BufferedImage.TYPE_INT_RGB); ((Graphics2D) subImage.getGraphics()).drawImage(image, null, -c3d.getX(), -c3d.getY()); Background bg = new Background(new ImageComponent2D(ImageComponent2D.FORMAT_RGB, subImage)); BoundingSphere bounds = new BoundingSphere(); bounds.setRadius(100.0); bg.setApplicationBounds(bounds); BranchGroup objRoot = new BranchGroup(); objRoot.addChild(bg);
Although this is easy to implement this trick requires the component used a background texture to be realized. In our case, this means we need to show the frame. The user will therefore see a gray canvas for a little while.
Using Java3D has many advantages but requires a little trick to work perfectly. A Java3D Canvas is an heavyweight component whereas Swing is made of lightweight components. The result is all the Swing components are drawn below the Java3D Canvas. The Swing and Java3D teams are aware of this problem and there is a simple solution.
As of Java3D 1.3.1 a better solution exists. You can use offscreen
Canvas3D to perform offscreen rendering. This means we could do all the rendering job in a buffer and paint the resulting frames directly within a Swing component (with a customized
JComponent or an
ImageIcon). This, however, requires more work.
You can download the demo and its source code to see how to achieve this effect. You'll need Java3D 1.3 and J2SE 1.4 (maybe less, more is good too). If you have only J2SE 1.4, you can change one or two lines of code in
BooksDemo.java to get rid of generics and recompile it safely.
Let me know if you successfully use this trick!