JavaFX Graphics Effects
JavaFX provides many features for graphics work. This section summarizes special effects such as transforming display position and direction, making shapes transparent, and applying blur or shadow effects.
Transformation
The basic shapes of shape objects are very simple. For example, a rectangle only has horizontal and vertical sides. There is no component such as “a slightly tilted rectangle.” How should such a thing be created?
In that case, use transformation. Transformation is a feature for moving, rotating, enlarging, and shrinking the display of a shape. The Node class, which is the superclass of shapes, provides the following methods for this.
Translation
"Node".setTranslateX(movement);
"Node".setTranslateY(movement);
"Node".setTranslateZ(movement);
Rotation
"Node".setRotate(rotationAngle);
Scaling
"Node".setScaleX(scale);
"Node".setScaleY(scale);
"Node".setScaleY(scale);
Translation moves the object along the X, Y, and Z axes. You may wonder why there is a Z axis; it is because JavaFX also includes 3D graphics features.
Rotation specifies the rotation angle. If you want reverse rotation, specify a negative angle.
Scaling is also prepared for each of the X, Y, and Z axes. Since this is a scale factor, values larger than 1.0 enlarge the shape, and values smaller than 1.0 shrink it.
A simple example is shown below. It rewrites the createShape method used earlier.
public void createShape(Pane root){
for(int i = 0;i < 100;i++){
Rectangle r = new Rectangle(10, 10, 25, 25);
r.setFill(Color.YELLOW);
r.setStroke(Color.GREEN);
r.setStrokeWidth(3);
r.setRotate(10 * i);
r.setTranslateX(5 * i);
r.setTranslateY(2.5 * i);
r.setScaleX(1 + 0.05 * i);
root.getChildren().add(r);
}
}
When you run it, you can see rectangles drawn while changing little by little.
The rectangles are created and then shifted by translation, rotation, and scaling. The position and size of the shapes created with new Rectangle are all the same, but their displayed appearance changes gradually.
Shape Transparency
So far, shapes have been filled with fixed colors. If shapes overlap, the shape underneath is naturally hidden. What should you do if you want a shape to be translucent so that the object below can be seen through it?
Use the setOpacity method. It sets the opacity of a shape and is used as follows.
"Node".setOpacity(opacity);
The argument is a real number (double) between 0 and 1. A value of 0 is transparent, and 1 is opaque.
This makes it easy to make a shape translucent. However, if you try it, you will see that this does not mean “draw only the outline and make the inside translucent.” It makes the entire shape transparent in the same way, including both the inside and the outline.
If you want only the inside of the shape to be transparent, use setFill. Specify Color.TRANSPARENT to make the inside transparent and draw only the outline.
The following source code is an example.
public void createShape(Pane root){
for(int i = 0;i < 20;i++){
Rectangle r = new Rectangle(10, 10, 50, 50);
r.setFill(Color.BLUE);
r.setStroke(Color.WHITE);
r.setTranslateX(20 * i);
r.setTranslateY(10 * i);
r.setOpacity(1 - 0.05 * i);
root.getChildren().add(r);
Rectangle r2 = new Rectangle(10, 10, 50, 50);
r2.setStroke(Color.RED);
r2.setFill(Color.TRANSPARENT);
r2.setTranslateX(20 * i);
r2.setTranslateY(10 * i);
root.getChildren().add(r2);
}
}
When you run it, rectangles are displayed in a row. Only the outline is red, and the inside gradually becomes transparent.
Here, a shape made transparent as a whole with setOpacity is overlaid with a shape whose inside is transparent with setFill(Color.TRANSPARENT). This expresses a shape where the outline remains visible while only the inside gradually becomes transparent.
Blur Effects
Shapes also include features for visual effects. A typical visual effect is blur.
Visual effects are set with the setEffect method included in shapes, which are subclasses of Node.
"Node".setEffect("Effect");
The argument is an instance of the Effect class, or one of its subclasses, that represents the visual effect. Many visual effects are provided, and all of them can be used as subclasses of Effect.
Blur-related visual effect classes include the following. The constructor arguments are the settings needed to express the effect.
Gaussian Blur
new GaussianBlur(radius)
Gaussian Blur creates a blur effect using a Gaussian curve. It is used to apply smooth blur over a wide area. The argument is a real number that becomes the blur radius.
Motion Blur
new MotionBlur(angle, radius)
Motion Blur creates a blur effect like a photo of something moving at high speed. The arguments are a real number for the blur direction angle and a real number for the blur strength radius.
Box Blur
new BoxBlur(width, height, iterations)
Box Blur creates a blur effect based on the average value of neighboring pixels. The arguments are the box width, height, and the number of effect iterations. Width and height are double values, and iterations is an int.
A simple example is shown below.
public void createShape(Pane root){
for(int i = 0;i < 10;i++){
Rectangle r = new Rectangle(20, 20, 50, 50);
r.setTranslateX(25 * i);
r.setTranslateY(15 * i);
r.setFill(Color.BLUE);
r.setStroke(Color.RED);
r.setStrokeWidth(5);
r.setEffect(new GaussianBlur(2.0 * i));
root.getChildren().add(r);
}
}
When you run the source code, rectangles are drawn with gradually stronger Gaussian Blur.
Shadow Effects and Reflection
A visual effect often used together with blur is a shadow. There are several kinds of shadows. Here is a brief summary.
Drop Shadow
new DropShadow(radius, horizontal offset, vertical offset, color);
An effect where the shadow of a shape falls below it is called a drop shadow. It is provided by the DropShadow class. There are several constructors, but the commonly used one specifies the shadow radius, horizontal and vertical offset, and shadow color (Color instance).
Inner Shadow
new InnerShadow(radius, horizontal offset, vertical offset, color);
This draws a shadow inside a shape, making it look recessed. As with DropShadow, specify the radius, horizontal and vertical offsets, and shadow color.
Reflection
new Reflection(top offset, fraction, top opacity, bottom opacity);
This is a light effect rather than a shadow. Reflection displays an inverted image below a shape, as if the shape were on ice or water. The arguments specify the distance between the original shape and the reflected shape, the fraction of the reflected shape to draw, and transparency settings for the top and bottom of the reflected shape.
An actual usage example is shown below.
public void createShape(Pane root){
Rectangle r = new Rectangle(20, 20, 100, 50);
r.setFill(Color.BLUE);
r.setStroke(Color.RED);
r.setStrokeWidth(5);
r.setEffect(new DropShadow(20.0, 10.0, 5.0, Color.BLACK));
root.getChildren().add(r);
Ellipse e = new Ellipse(220, 50, 70, 30);
e.setFill(Color.YELLOW);
e.setStroke(Color.GREEN);
e.setStrokeWidth(5);
e.setEffect(new Reflection(5.0, 2.0, 0.5, 0));
root.getChildren().add(e);
Text t = new Text(50, 250, "Hello!");
t.setFont(new Font(80));
t.setFill(Color.YELLOW);
t.setStroke(Color.GREEN);
t.setStrokeWidth(1);
t.setEffect(new InnerShadow(2.0, 2.0, 1.0, Color.BLACK));
root.getChildren().add(t);
}
DropShadow and InnerShadow are not very difficult. Reflection can configure the displayed width of the reflected shape and how the top and bottom fade, so once you understand the role of each argument, you can create interesting effects.
Applying Multiple Visual Effects with an Effect Chain
We have introduced several visual effects, but all of them were set with setEffect on a Node. In other words, multiple effects cannot be set directly at the same time.
However, there are cases where you want to use several visual effects together. What should you do then?
You need to change how you think about it. Only one Effect can be set with setEffect; that itself does not change. What you should focus on is not the Node being applied to, but the Effect class that becomes the visual effect.
The Effect class applies an effect to an input image and outputs a result. In other words, it transforms an input image and produces an output image. Therefore, if the output of one visual effect can be passed as the input of another visual effect, multiple effects can be used.
That is, apply effects in sequence, such as “visual effect A” -> “visual effect B” -> “visual effect C”, and set the final result with setEffect. This is called an effect chain. It is configured with the setInput method.
"Effect".setInput("Effect");
setInput is a method of the Effect class. Pass another Effect instance as the argument. The effect set as the argument is used as the input for the next visual effect.
The following is an example.
public void createShape(Pane root){
InnerShadow is = new InnerShadow(10.0, 2.0, 2.0, Color.rgb(0, 100, 100));
DropShadow ds = new DropShadow(20.0, 10.0, 5.0, Color.BLACK);
ds.setInput(is);
Reflection rf = new Reflection(0.0, 2.0, 0.5, 0);
rf.setInput(ds);
Rectangle r = new Rectangle(20, 20, 100, 50);
r.setFill(Color.CYAN);
r.setEffect(rf);
root.getChildren().add(r);
}
Here, three effects, InnerShadow, DropShadow, and Reflection, are connected with setInput to create a visual effect. Once you know how to use effect chains, you can combine visual effects in many ways.