How to show a javafx 3D object? - animation

I wrote a javafx object "Ball" to create a Sphere. I'm now trying to make the object appear in my main class.
Ideally, I would use a key listener to create/destroy balls. But I can't even get the balls to appear on the screen, or even make my 1500x900 screen appear at all.
Here my code for the ball:
// ball object
package bouncingballs;
import javafx.animation.Interpolator;
import javafx.animation.PathTransition;
import javafx.animation.Timeline;
import javafx.scene.layout.Pane;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Sphere;
import javafx.util.Duration;
import static javafx.util.Duration.seconds;
public class Ball extends Pane {
//Create 3D ball
private Sphere ball;
private Double radius;
private PhongMaterial color;
private Polygon poly;
private PathTransition path;
private Integer speed;
//Create path and animate ball in constructor
public Ball(Double radius, PhongMaterial color, Polygon poly) {
this.radius = radius;
this.color = color;
ball.setRadius(radius);
ball.setMaterial(color);
this.poly = poly;
speed = 10;
path.setPath(poly);
path.setNode(ball);
path.setInterpolator(Interpolator.LINEAR);
path.setDuration(Duration.seconds(speed));
path.setCycleCount(Timeline.INDEFINITE);
path.play();
}
//some test accessors/mutators
public void setRadius(Double radius) {
this.radius = radius;
}
public Double getRadius() {
return radius;
}
}
Here is my code for my main class, it should create Ball objects and display them animated. The animation should follow the Polygon object poly to simulate a bouncing ball.
//main object to show Balls to screen
package bouncingballs;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;
public class BouncingBalls extends Application {
#Override
public void start(Stage primaryStage) {
//create path to simulate bouncing ball
Polygon poly = new Polygon(750, 850, 50, 675, 500, 50, 750, 850, 1000, 50, 1450, 675);//creates path to simulate bouncing ball on 1500x900 screen
Double radius = 50.0;
PhongMaterial color = new PhongMaterial();
color.setDiffuseColor(Color.OLIVE);
Ball ball = new Ball(radius, color, poly);
StackPane root = new StackPane();
root.getChildren().add(ball);
Scene scene = new Scene(root, 1500, 900);
primaryStage.setTitle("Bouncing Balls");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{launch(args);
}
}

You have a bunch of errors or otherwise weird things:
Your Ball class creates a Sphere, but you never add that Sphere to the scene graph (so it could never be seen).
Your Ball class extends Pane, which is weird because a Ball isn't really a Pane. If you are to extend anything, probably Sphere would be best.
You use a StackPane for your root. It is probably not best to do that for 3D graphics, as the Pane subclasses are really designed for laying out 2D systems. For 3D, you probably just want to stick to basic Groups as containers.
When you have a 3D scene, you probably want to use the constructor which switches depth buffering on.
For 3D work, you want to set a PerspectiveCamera on the scene.
You probably want some lighting on your scene. JavaFX will add some default lighting, but it may not match what you need.
You should check the Scene3D ConditionalFeature to see if 3D is supported on your platform.
You probably want to set the Z co-ordinates of your Sphere appropriately and ensure that it is something which will lie within your perspective camera's field of view.
You can find some sample code which displays a Sphere (the earth), here:
JavaFX material's bump and spec maps
The sample demonstrates some of the points made above.

Related

Getting rotateTransition and pathtransition to work on a resizable window

I had a bit of a problem developing a test Javafx program that deals with passing rectangle objects across the screen from different directions. In order to make this work, I created the rectangle objects and then three line objects. I then created a PathTransition object that would have a rectangle travel along each line object. From there, I created a Pane object and added both the three rectangles and three lines on top of it.
To simulate that the rectangles were coming from different directions, I used a RotateTransition object and used the Pane object as its node. Basically, the program is just a rotating pane that carries three lines that each have a rectangle moving down the path of said line. However, when I want to resize the window, I don't know how to exactly cause the size of the pane to change with it without messing up the animations. Any help would be greatly appreciated. Thanks! Here is the code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.animation.PathTransition;
import javafx.animation.RotateTransition;
import javafx.animation.Timeline;
public class Test extends Application {
#Override
public void start(Stage primaryStage) {
// Pane object
Pane pane = new Pane();
// Rectangle objects
Rectangle yellowRectangle = new Rectangle(10,10,10,10);
yellowRectangle.setFill(Color.YELLOW);
Rectangle greenRectangle = new Rectangle(10,10,10,10);
greenRectangle.setFill(Color.GREEN);
Rectangle blueRectangle = new Rectangle(10,10,10,10);
blueRectangle.setFill(Color.BLUE);
Line yellowLine = new Line(0,0,500,500);
yellowLine.setStroke(Color.YELLOW);
Line greenLine = new Line(500,0,0,500);
greenLine.setStroke(Color.GREEN);
Line blueLine = new Line(0,250,500,250);
blueLine.setStroke(Color.BLUE);
pane.getChildren().addAll(yellowRectangle, greenRectangle, blueRectangle, yellowLine, greenLine, blueLine);
// Pathtransitions
PathTransition yellowPath = new PathTransition();
yellowPath.setDuration(Duration.millis(4000));
yellowPath.setPath(yellowLine);
yellowPath.setNode(yellowRectangle);
yellowPath.setCycleCount(Timeline.INDEFINITE);
yellowPath.setAutoReverse(true);
yellowPath.play();
PathTransition greenPath = new PathTransition();
greenPath.setDuration(Duration.millis(4000));
greenPath.setPath(greenLine);
greenPath.setNode(greenRectangle);
greenPath.setCycleCount(Timeline.INDEFINITE);
greenPath.setAutoReverse(true);
greenPath.play();
PathTransition bluePath = new PathTransition();
bluePath.setDuration(Duration.millis(4000));
bluePath.setPath(blueLine);
bluePath.setNode(blueRectangle);
bluePath.setCycleCount(Timeline.INDEFINITE);
bluePath.setAutoReverse(true);
bluePath.play();
// Rotate Transition
RotateTransition yellowRotate = new RotateTransition();
yellowRotate.setAxis(Rotate.Z_AXIS);
yellowRotate.setByAngle(360);
yellowRotate.setCycleCount(500);
yellowRotate.setDuration(Duration.millis(10000));
yellowRotate.setAutoReverse(true);
yellowRotate.setNode(pane);
yellowRotate.play();
// Borderpane
BorderPane borderPane = new BorderPane();
borderPane.setCenter(pane);
Scene scene = new Scene(borderPane, 1000, 1000);
// Bind the BorderPane to the scene
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
primaryStage.setTitle("Test");
primaryStage.setScene(scene);
primaryStage.setResizable(true);
primaryStage.show();
}
}

JavaFX - Borders of ImageView and Pane do not scale / zoom properly inside ScrollPane

in order to achieve something like a minimap, I used a StackPane to layer a Pane on top of an ImageView. I bound the the scaling x- and y-properties of the StackPane to a Slider in order to achieve a zooming effect. I added a few Circle objects to the Pane. These circles should of course also be zoomable (which they are), but in this case more importantly, they should stay at their relative position when scaling happens. The following picture shows what the GUI looks like so far.
As of yet, I have distinguished two problematic cases.
Problem A - Correct positions but 'out of bounds'
In this more simple case, everything works fine, except for the fact that zooming in on the image seemingly makes it exceed the bounds of the StackPane. As a result, you cannot scroll to the image's border anymore. Check the next screenshot to see what I mean.
Problem B - 'In bounds' but out of position
To make the StackPane grow appropriately, I bound its size properties to the zoom factor multiplied with the image's size. However, I am pretty sure that this approach somehow messes with the underlying coordinate structure, because now the circle 'leaves' its position at a scale factor > 1. Said behaviour is depicted in the last screenshot.
I have added my code below. Any help would be greatly appreciated :)
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ScalingProblem extends Application {
private static final String IMAGE_URL = "https://st2.depositphotos.com/3034795/10774/i/950/depositphotos_107745620-stock-photo-labyrinth-or-maze.jpg";
#Override
public void start(Stage primaryStage) throws Exception {
// Prepare the main part of the GUI.
Image backgroundImage = new Image(IMAGE_URL);
ImageView imageView = new ImageView(backgroundImage);
Circle circle = new Circle(40, Color.ORANGE);
circle.setStroke(Color.BLUE);
circle.setStrokeWidth(5);
Pane layer = new Pane(circle);
StackPane stackPane = new StackPane(imageView, layer);
ScrollPane scrollPane = new ScrollPane(stackPane);
scrollPane.setPannable(true);
// Prepare the controls on the left side.
Slider xSlider = new Slider();
Slider ySlider = new Slider();
Slider radiusSlider = new Slider();
Slider zoomSlider = new Slider();
VBox vBox = new VBox(xSlider, ySlider, radiusSlider, zoomSlider);
vBox.setSpacing(10);
vBox.setPrefWidth(200);
// Adjust the sliders.
adjustSlider(xSlider, 0, 1000, 50);
adjustSlider(ySlider, 0, 1000, 50);
adjustSlider(radiusSlider, 0, 100, 15);
adjustSlider(zoomSlider, 0, 3, 1);
zoomSlider.setMajorTickUnit(1);
zoomSlider.setMinorTickCount(1);
zoomSlider.setShowTickMarks(true);
zoomSlider.setShowTickLabels(true);
// Do all necessary binding.
circle.centerXProperty().bind(xSlider.valueProperty());
circle.centerYProperty().bind(ySlider.valueProperty());
circle.radiusProperty().bind(radiusSlider.valueProperty());
stackPane.scaleXProperty().bind(zoomSlider.valueProperty());
stackPane.scaleYProperty().bind(zoomSlider.valueProperty());
/*
* So far, I always needed to make the StackPane's size grow / shrink depending on the zoom level. If the
* following two lines are commented out, zooming in will make the ImageView exceed the bounds of the StackPane.
* As a result, the StackPane does not 'grow' appropriately so that you cannot pan the view to see the edges of
* the background.
*/
stackPane.prefWidthProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getWidth()));
stackPane.prefHeightProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getHeight()));
// Piece the GUI together.
BorderPane root = new BorderPane();
root.setCenter(scrollPane);
root.setLeft(vBox);
root.setPrefHeight(300);
root.setPrefWidth(500);
// Show the stage.
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private void adjustSlider(Slider slider, double min, double max, double start) {
slider.setMin(min);
slider.setMax(max);
slider.setValue(start);
}
public static void main(String[] args) {
launch();
}
}
ScrollPane uses the unmodified layout bounds to determine the content size. This does not include the scaling transformation. To prevent the content from growing beyond the scrollable area, wrap the scaled node in a Group.
Modify the ScrollPane creation like this:
ScrollPane scrollPane = new ScrollPane(new Group(stackPane));
and remove the binding to the prefWidth/prefHeight, i.e. delete the following lines:
stackPane.prefWidthProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getWidth()));
stackPane.prefHeightProperty().bind(zoomSlider.valueProperty().multiply(backgroundImage.getHeight()));

JavaFX - Multiple lights on a dark background

I'm attempting to create something like a minimap with JavaFX, i.e. a (darkened) background image with some circles layered on top of it. Some of these circles need to be able to shed light on the background, revealing a small part of it. The following figure shows what I am aiming at.
I have worked my way forward using this SO solution, but at the moment, I am stuck because it seems that you can only set one instance of javafx.scene.effect.Lighting on the underlying StackPane.
I would really like to keep this as simple as possible and ideally only employ JavaFX. Any help is greatly appreciated :)
I recommend adding together Circles filled with a RadialGradient on a Pane with black background using BlendMode.LIGHTEN and combining this with a ImageView containing the "map" using BlendMode.MULTIPLY:
private Circle circle;
// gradient with yellow in the center and black on the border
private final static RadialGradient GRADIENT = new RadialGradient(0, 0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE, new Stop(0, Color.YELLOW), new Stop(1, Color.BLACK));
private void newCircle(Pane container) {
circle = new Circle(50, GRADIENT);
circle.setBlendMode(BlendMode.LIGHTEN);
circle.setManaged(false);
container.getChildren().add(circle);
}
private void setCirclePosition(MouseEvent event) {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
}
#Override
public void start(Stage primaryStage) {
Image image = new Image(imageURL);
ImageView imageView = new ImageView(image);
Pane mask = new Pane();
mask.setBlendMode(BlendMode.MULTIPLY);
mask.setStyle("-fx-background-color: black;");
mask.setOnMouseMoved(this::setCirclePosition); // move cricle with mouse
newCircle(mask);
// create new circle on mouse click
mask.setOnMouseClicked(evt -> {
newCircle(mask);
setCirclePosition(evt);
});
StackPane root = new StackPane(imageView, mask);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

How to restrict rotation projection in android?

I have used Animation() method to make my view with the animation of scaling and Rotation. With the Rotation based on the Y axis, the default height and width of my view has been changed. It looks like the parallelogram.
rotation of rectangle along y-axis transformed to a parallelogram.
myview.Animate().RotationY(rotationangle)
.X(xposition)
.SetDuration(mduration)
.WithLayer()
.SetInterpolator(interpolate).Start();
My requirement:
I just want the rotation of my view no need to change its projection. How to restrict the rotation of rectangle along y-axis transformed to a parallelogram.
For more reference, please check the attached sample
now view be like,
Image
Please share your idea.
Thanks in Advance.
Note: while using PivotX and PivotY, there is no parallelogram shape. But I don't know the exact usage of that.
Regards,
Hemalatha Marikumar
is that not what are you looking for ?
it may work if you put this code in your current activity
Android: Temporarily disable orientation changes in an Activity
Do you want to create a 2D rotation?
You could try to use ScaleAnimation to rotate the view. If you want to rotate 360 degrees, you could use AnimationListener.
For example:
Button myview = (Button)FindViewById(Resource.Id.button2);
ScaleAnimation scaleAnimation = new ScaleAnimation(1, 0, 1, 1,
Android.Views.Animations.Dimension.RelativeToParent, 0.5f, Android.Views.Animations.Dimension.RelativeToParent, 0.5f);
ScaleAnimation scaleAnimation2 = new ScaleAnimation(0, 1, 1, 1,
Android.Views.Animations.Dimension.RelativeToParent, 0.5f, Android.Views.Animations.Dimension.RelativeToParent, 0.5f);
scaleAnimation.Duration = 4000;
scaleAnimation.SetAnimationListener(new AnimationListener(myview, scaleAnimation2));
scaleAnimation2.Duration = 4000;
myview.StartAnimation(scaleAnimation);
The Listener:
public class AnimationListener :Java.Lang.Object, IAnimationListener
{
View view;
Animation animation2;
public AnimationListener(View view, Animation animation)
{
this.view = view;
this.animation2 = animation;
}
public void OnAnimationEnd(Animation animation)
{
view.StartAnimation(animation2);
}
public void OnAnimationRepeat(Animation animation)
{
}
public void OnAnimationStart(Animation animation)
{
}
}

Draw ellipse and rounded rectangle in GEF eclipse editor

I want to draw an ellipse and a rounded rectangle in GEF editor.
I am not using Canvas and am using XY layout.I am able to draw rectangle in this layout but not the other two.
Please guide
To draw a rounded rectangle you need to extend Figure and inside this figure draw a rectangle with rounded borders
(Disclaimer - This is a reduced version of the code I use for a rounded rectangle here. Pretty sure it will work but I didn't test it)
public class RoundedRectangle extends Figure {
private final RoundedRectangle rectangle;
public RoundedRectangle() {
super();
setLayoutManager(new XYLayout());
rectangle = new RoundedRectangle();
rectangle.setCornerDimensions(new Dimension(20, 20)); // This is where the rounding happens
// Anything else you want to customize
add(rectangle);
}
#Override
protected void paintFigure(Graphics graphics) {
Rectangle r = getBounds().getCopy();
setConstraint(rectangle, new Rectangle(0, 0, r.width, r.height));
}
}

Resources