Blending
Blending is the process of combining two pixels that would occupy the same space to produce a third value that is actually placed at that space. Blending can be used to determine what should be seen in a region where two nodes overlap or where two effects are applied to a node. You can use blending either as an effect or as a mode that controls the drawing of overlapping nodes in a group or container.
The Blend Effect
The Blend effect combines two inputs and produces a result that depends on the selected blend mode. The variables of the Blend class are listed in Table 20-17.
Table 20-17. Variables of the Blend Class
Variable |
Type |
Access |
Default |
Description |
mode |
BlendMode |
RW |
SRC_OVER |
The mode that determines how pixels from the two inputs are combined to produce the resulting pixel. |
topInput |
Effect |
RW |
null |
The top input to this effect. If this is null, the node to which the effect is applied is used. |
bottomInput |
Effect |
RW |
null |
The bottom input to this effect. If this is null, the node to which the effect is applied is used. |
opacity |
Number |
RW |
1.0 |
The opacity applied to the top input before blending. |
Here's an example that demonstrates how to construct a Blend effect. This code is extracted from the file javafxeffects/BlendEffect1.fx, which you can run to try out all the available blend modes:
var image1 = Image { url: "{__DIR__}image1.jpg" }; var image2 = Image { url: "{__DIR__}image2.jpg" }; ImageView { x: 30 y: 30 image: image1 effect: Blend { mode: BlendMode.ADD topInput: Identity { x: 150 y: 150 source: image2 } }
Here, the bottom input is the ImageView itself (because the bottomInput variable is null, so the node itself becomes the input), while the top input is the output of an Identify effect applied to an Image. The second image is placed 150 pixels below and to the right of the ImageView, giving the result shown in Figure 20-29.
Figure 20-29 Using the Blend effect
As you can see, the result of this effect is the union of the two images. There is a significant area of overlap between the two images, and in this region, their pixels are combined according to the unique set of rules that apply to the selected blend mode. There are 19 different modes, all defined as constants in the BlendMode class. You will find the details of each mode in the documentation for the BlendMode class. In Figure 20-29, BlendMode.ADD has been used. This adds all the color and alpha components from the two pixels to produce the result pixel. For example, if the RGBA values for two pixels were (0.6, 0.2, 0.3, 0.4) and (0.5, 0.6, 0.1, 0.5), the value of the resulting pixel would be (1.0, 0.8, 0.4, 0.9). Notice that the value of each channel is limited to 1.0, which is why the result of combining the red channels in this example is 1.0 rather than 1.1.
By selecting different values from the combo box at the top of the scene, you can see how each mode operates. Of particular interest are the SRC_ATOP, SRC_IN, SRC_OUT and SRC_OVER modes. In these modes, the "source" is the top input. You can see the results of applying SRC_ATOP mode on the left of Figure 20-30 and SRC_IN mode on the right.
Figure 20-30 The SRC_ATOP and SRC_IN blend modes
The SRC_ATOP mode keeps all the bottom input plus that part of the top input that overlaps it. In the overlap area, only the top input is painted. By contrast, SRC_IN keeps only that part of the top input that overlaps with the bottom input, and everything else (including all the bottom input) is lost.
The Group Blend Mode
A blend mode can be applied to a group (or a container, because Container is a subclass of Group) by setting its blendMode variable to one of the constants defined by the BlendMode class. The blend mode determines how the pixels in the areas in which there are overlapping nodes are constructed from those of the nodes themselves. By default, and in all the examples that you have seen so far, the blendMode variable has the value BlendMode.SRC_OVER, which causes the node in front to be drawn over those that are behind it.
The following code, from the file javafxeffects/BlendGroup1.fx, allows you to see how each of the possible blend modes operates when applied to the nodes of a group:
1 var image1 = Image { url: "{__DIR__}image1.jpg" }; 2 var image2 = Image { url: "{__DIR__}image2.jpg" }; 3 var scene: Scene; 4 Stage { 5 title: "Blend Group" 6 scene: scene = Scene { 7 var modeCombo: SwingComboBox; 8 var mode = bind modeCombo.selectedItem.value 9 as BlendMode; 10 width: 500 11 height: 400 12 fill: Color.BLACK 13 content: [ 14 modeCombo = SwingComboBox { 15 translateX: bind (scene.width 16 - modeCombo.layoutBounds.width) / 2 17 editable: false 18 items: [ 19 SwingComboBoxItem { 20 value: BlendMode.ADD 21 text: "ADD" 22 } 23 // Further items not shown here 24 25 ] 26 selectedIndex: 0 27 } 28 Circle { 29 centerX: 100 30 centerY: 100 31 radius: 80 32 fill: Color.YELLOW 33 } 34 Group { 35 blendMode: bind if (mode != null) mode 36 else BlendMode.ADD 37 content: [ 38 ImageView { 39 x: 30 40 y: 30 41 image: image1 42 } 43 ImageView { 44 x: 150 45 y: 150 46 image: image2 47 } 48 ] 49 } 50 ] 51 } 52 }
This code creates a scene containing a combo box that allows a BlendMode to be selected, a circle, and a group containing two overlapping two ImageViews. On the left of Figure 20-31, you can see the result of applying the default mode, which is SRC_OVER. On the right of the figure, the MULTIPLY mode is used.
Figure 20-31 Using blend modes in a group
As you can see, these two modes have different effects on the pixels in the area of overlap between the two images. Note, however, that the blend mode has no effect on the region in which the upper-left ImageView overlaps the circle, because the circle is not in the group and therefore is not subject to the blend mode.