Here is a little sample to show you how to create 3D content in JavaFX 2.0. More complex and fun examples will be coming in the future.
The main thing to learn here is any node in the JavaFX scene can be translated and rotated in 3D space. Basic transforms are provided for convenance on the Node class itself with translateX/Y/Z and rotate/rotateAxis properties. For more complex transforms you can get the Transforms list from a node with getTransforms() and add javafx.scene.transform.* classes. In this case I am adding javafx.scene.transform.Rotate transforms so that I can set the pivot point around which the node is rotated. By default if you use the rotate property on node it translates around the center of the node, which is the most common case for 2D but may not be what you want for 3D.
To setup a scene for doing 3D there are two things you need to set: stage.initDepthBuffer(true) and scene.setCamera(new PerspectiveCamera()). The first enables 3D Z-Ordering or Depth Testing this means that what ever is nearest the camera is drawn on top, with the furthest away stuff behind just as you would expect in a 3D world. The second means use a camera with perspective which means that two parallel lines will look closer together the further they are away from the camera. These two properties make the scene resemble the everyday 3D world we live in.
Complete Code
import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.application.Application; import javafx.builders.RectangleBuilder; import javafx.scene.Group; import javafx.scene.PerspectiveCamera; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.transform.Rotate; import javafx.stage.Stage; import javafx.util.Duration; /** * @author Jasper Potts */ public class Cube3D extends Application{ @Override public void start(Stage stage) throws Exception { stage.setTitle("Cube 3D"); stage.initDepthBuffer(true); Cube c = new Cube(50,Color.RED,1); c.rx.setAngle(45); c.ry.setAngle(45); Cube c2 = new Cube(50,Color.GREEN,1); c2.setTranslateX(100); c2.rx.setAngle(45); c2.ry.setAngle(45); Cube c3 = new Cube(50,Color.ORANGE,1); c3.setTranslateX(-100); c3.rx.setAngle(45); c3.ry.setAngle(45); Timeline animation = new Timeline(); animation.getKeyFrames().addAll( new KeyFrame(Duration.ZERO, new KeyValue(c.ry.angleProperty(), 0d), new KeyValue(c2.rx.angleProperty(), 0d), new KeyValue(c3.rz.angleProperty(), 0d) ), new KeyFrame(Duration.valueOf(1000), new KeyValue(c.ry.angleProperty(), 360d), new KeyValue(c2.rx.angleProperty(), 360d), new KeyValue(c3.rz.angleProperty(), 360d) )); animation.setCycleCount(Animation.INDEFINITE); // create root group Group root = new Group(c,c2,c3); // translate and rotate group so that origin is center and +Y is up root.setTranslateX(400/2); root.setTranslateY(150/2); root.getTransforms().add(new Rotate(180,Rotate.X_AXIS)); // create scene Scene scene = new Scene(root, 400,150); scene.setCamera(new PerspectiveCamera()); stage.setScene(scene); stage.setVisible(true); // start spining animation animation.play(); } public static void main(String[] args) { launch(args); } public class Cube extends Group { final Rotate rx = new Rotate(0,Rotate.X_AXIS); final Rotate ry = new Rotate(0,Rotate.Y_AXIS); final Rotate rz = new Rotate(0,Rotate.Z_AXIS); public Cube(double size, Color color, double shade) { getTransforms().addAll(rz, ry, rx); getChildren().addAll( new RectangleBuilder() // back face .width(size).height(size) .fill(color.deriveColor(0.0, 1.0, (1 - 0.5*shade), 1.0)) .translateX(-0.5*size) .translateY(-0.5*size) .translateZ(0.5*size) .build(), new RectangleBuilder() // bottom face .width(size).height(size) .fill(color.deriveColor(0.0, 1.0, (1 - 0.4*shade), 1.0)) .translateX(-0.5*size) .translateY(0) .rotationAxis(Rotate.X_AXIS) .rotate(90) .build(), new RectangleBuilder() // right face .width(size).height(size) .fill(color.deriveColor(0.0, 1.0, (1 - 0.3*shade), 1.0)) .translateX(-1*size) .translateY(-0.5*size) .rotationAxis(Rotate.Y_AXIS) .rotate(90) .build(), new RectangleBuilder() // left face .width(size).height(size) .fill(color.deriveColor(0.0, 1.0, (1 - 0.2*shade), 1.0)) .translateX(0) .translateY(-0.5*size) .rotationAxis(Rotate.Y_AXIS) .rotate(90) .build(), new RectangleBuilder() // top face .width(size).height(size) .fill(color.deriveColor(0.0, 1.0, (1 - 0.1*shade), 1.0)) .translateX(-0.5*size) .translateY(-1*size) .rotationAxis(Rotate.X_AXIS) .rotate(90) .build(), new RectangleBuilder() // top face .width(size).height(size) .fill(color) .translateX(-0.5*size) .translateY(-0.5*size) .translateZ(-0.5*size) .build() ); } } }
how are running it in mac-os?
I do my internal day to day development on Mac but not ETA for public release yet.
I wonder, how can you in 2011 show a picture of cubes with that kind of aliasing? I looks absolutely awful. Haven’t you learned anything from Apple?
Everyone that’s event a tad designer savvy will immediately start wondering, doesn’t JavaFX 2.0 have anti-aliasing?
A CRUD example will be very much welcomed
@Bill Justin
Anti-aliasing can be turned on and off by the smooth property. It should be set to true by default so I’m not sure what is with the image at the top. JavaFX 1.3 at least worked fine in that regard. Maybe it’s something in 2.0 that hasn’t been fixed yet or the image itself has been scaled.
@aidreamer
The image is not scaled, I would recognize that.
If they don’t have aa in the beta they should comment it and say it will be in the final since no aa will make designer/developer people laugh.
Is it possible to use images instead of rectangles?
Yes, you should be able to use *anything*, including WebViews, MediaViews, controls, panes, etc.
Should I use ImageViewBuilder for building cube with images on its sides&
You can use ImageView’s directly or use the ImageViewBuilder to create them. Basically you will need to swap out the rectangles in the code with ImageViews. You could do the same with any other node, for example MediaViews or WebViews.
is there a Cube Primitive ?
Not yet, but in the next major release we have been talking about having 3D primitives, lighting, etc. Our plans for the next release are not finished and are still in flux, but if this is something you are interested in it is probably a good idea to file a JIRA and vote for it (or find an existing JIRA and vote for it)
Is it possible to render another 3d scene on the side of a cube?
Could not get this to compile, does this code need to be updated? I do think I have the most recent for Mac OS X.
I got it to run on my own by fishing around a bit. RecatngleBuilder.create() needs to replace the constructor new which is “protected.” Couldn’t use setVisibe(true), but show() may be similar? Duration.valueOf(…) takes a string with units added to a number, not a number, e.g.: I used Duration.valueOf(“2000ms”).
Once running, I found the perspective odd, and set the viewing angle of the perspective camera to 5.0 for less weird visual effect. I still see what looks like screwed up zBuffered draws in the red and green cubes for about half their orientations. (What should be hidden faces are being rendered on top.)
Cube3D.java has compile errors at JavaFX 2.1.0 b-07
The method valueOf(String) in the type Duration is not applicable for the arguments (int) Cube3D.java line 43 Java Problem
The method setVisible(boolean) is undefined for the type Stage Cube3D.java /JavaFX-1 etc line 59 Java Problem
The method initDepthBuffer(boolean) is undefined for the type Stage Cube3D.java /JavaFX-1 etc line 22 Java Problem
The import javafx.builders cannot be resolved Cube3D.java line 6
RectangleBuilder cannot be resolved to a type Cube3D.java line 75
RectangleBuilder cannot be resolved to a type Cube3D.java line 82
RectangleBuilder cannot be resolved to a type Cube3D.java line 90
RectangleBuilder cannot be resolved to a type Cube3D.java line 98
RectangleBuilder cannot be resolved to a type Cube3D.java line 106
RectangleBuilder cannot be resolved to a type Cube3D.java line 114
I dont really se the point of JavaFX anymore.
You cannot create iPad apps with it.
You cannot create Android apps with it.
You cannot create Web OS apps with it.
You cannot create Linux apps with it.
You cannot create Mac apps with it.
..and looking towards the examples shown so far, Web UI’s are a far better bet.
They say that JavaFx for Mac and Linux is coming along, but so it flying cars…
You should see the post I made about 2011 New Years resolutions. Web OS doesn’t matter. Linux and Mac will both be GA this year, no question about it. Embedded work is being done as we speak. I cannot comment in iPad / Android development, but can say we do recognize the critical importance of tablets and smart phones.
It gives me an exception with this instruction stage.initDepthBuffer(true)
“Can not find symbol?!”
It gives me an exception on this instruction stage.initDepthBuffer(true)
“Can not find symbol?!”
This does not seem to work with the latest 2.2.4. I get no package for import javafx.builders.RectangleBuilder;
It give some problems like:
*import javafx.builders.RectangleBuilder; not found
*stage.initDepthBuffer(true) can not find symbol.
I think this Simple 3D Cubes in JavaFX 2.0 need to be updated.