在Javafx中为剪裁图像添加光照效果

时间:2014-06-03 09:08:02

标签: javafx blend emboss

我尝试将浮雕效果(也称为凹凸贴图)添加到复杂的剪切图像中。 (Namly是一个拼图。) 这可以通过每像素操作来完成,但是它非常昂贵:剪辑的确切形式是运行时确定的,因此即使是凹凸贴图也必须在运行时生成。

JavaFX的灯光效果提供了类似的开箱即用效果:

// Create clipping
pieceClip = createPiece(topEdge, leftEdge, bottomEdge, rightEdge);
pieceClip.setFill(Color.WHITE);
pieceClip.setStroke(null);

// Create clipped image view
imageView.setImage(image);
imageView.setClip(pieceClip);

// Create ambient light
Light.Distant light = new Light.Distant();
light.setAzimuth(-135.0);

// Create lighting effect
Lighting lighting = new Lighting();
lighting.setLight(light);
lighting.setSurfaceScale(4.0);

// Create shape to apply lighting on (the shape is the same as the clipping)
Shape pieceStroke1 = createPiece(topEdge, leftEdge, bottomEdge, rightEdge);
pieceStroke1.setFill(new Color(1, 1, 1, 0.4));
pieceStroke1.setStroke(null);

// Apply lighting
pieceStroke1.setEffect(lighting);

// Add clipped image and lighting overlay to the shape
getChildren().addAll(imageView, pieceStroke1);

这很好用,照明效果:

然而,它有一个副作用:由于叠加是白色而且只是半透明,它会使图像变暗(使其变得模糊不清,不那么生动)。

我尝试使用Blend(COLOR_BURN,DARKEN等)来恢复图像颜色,但是因为没有这些效果,我失败了。

我如何保留图像颜色饱和度,但应用浮雕效果?

我有几个想法如何做,但我不知道哪一个会起作用:

  1. 直接将照明应用于图像。 它失败了,因为照明应用于未剪辑的图像。
  2. 通过在图像或照明叠加层上应用混合效果来纠正色彩饱和度降低 由于我在这些影响中的无能,它失败了。
  3. 剪切叠加层形状以仅覆盖受光照影响的区域 它需要偏移Bezier弯曲,这样做很难且很昂贵。
  4. 更改叠加形状alpha以遵循灯光效果强度。
  5. 任何想法都会受到高度赞赏。

1 个答案:

答案 0 :(得分:3)

<强>解决方案

对效果链中的ColorAdjust效果应用Lighting效果。

无论你做什么,照明效果都会在一定程度上改变图像的外观和颜色(因为这就是照明所做的),但通过应用额外的颜色调整,你可以得到一个可识别的图像非常接近原始着色。

如果您需要调整图像的形状,请对剪切的图像进行快照,并将效果应用于快照(如果这是您想要的),如以下答案中所述:Border-Radius and Shadow on ImageView

示例

// increase brightness and contrast.
ColorAdjust brightLight = new ColorAdjust(0, 0, .25, 0.25); 

// chain in your lighting effect.
brightLight.setInput(lighting);

// apply the chained effect to your image.
ImageView litAdjusted = new ImageView(image);
litAdjusted.setEffect(brightLight);

可执行样本

herebedragons

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

// Java 8 code
public class HereBeDragons extends Application {

    @Override public void start(final Stage stage) {
        Image image     = new Image(imageLoc);
        Image clipImage = new Image(CLIP_IMAGE_LOC);

        ImageView plain = new ImageView(image);

        ImageView lit = new ImageView(image);
        Lighting lighting = createLighting();
        lit.setEffect(lighting);

        ImageView litAdjusted = new ImageView(image);
        ColorAdjust brightLight = new ColorAdjust(0, 0, .25, 0.25);
        brightLight.setInput(lighting);
        litAdjusted.setEffect(brightLight);

        plain.setClip(new ImageView(clipImage));
        SnapshotParameters params = new SnapshotParameters();
        params.setFill(Color.TRANSPARENT);
        WritableImage clippedImage = plain.snapshot(params, null);
        ImageView litAdjustedClip = new ImageView(clippedImage);
        litAdjustedClip.setEffect(brightLight);
        plain.setClip(null);

        HBox layout = new HBox(
                10,
                new CaptionedImage(plain,       "Plain"),
                new CaptionedImage(lit,         "Lit"),
                new CaptionedImage(litAdjusted, "Lit and Adjusted"),
                new CaptionedImage(litAdjustedClip, "Clipped,\nLit and Adjusted")
        );
        layout.setPadding(new Insets(20));
        layout.setStyle("-fx-background-color: lightblue;");

        stage.setTitle("Here be Dragons");
        stage.setScene(new Scene(layout, Color.LIGHTBLUE));
        stage.setResizable(false);
        stage.show();
    }

    private Lighting createLighting() {
        // Create ambient light
        Light.Distant light = new Light.Distant();
        light.setAzimuth(-135.0);

        // Create lighting effect
        Lighting lighting = new Lighting();
        lighting.setLight(light);
        lighting.setSurfaceScale(4.0);

        return lighting;
    }

    private class CaptionedImage extends Label {
        public CaptionedImage(ImageView imageView, String caption) {
            setText(caption);
            setGraphic(imageView);
            setContentDisplay(ContentDisplay.TOP);
            setTextAlignment(TextAlignment.CENTER);

            setStyle(
                    "-fx-text-fill: midnightblue; " +
                    "-fx-font-size: 16px; " +
                    "-fx-font-family: palatino; " +
                    "-fx-font-style: italic;"
            );
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

    private static final String imageLoc =
        "http://icons.iconarchive.com/icons/custom-icon-design/round-world-flags/128/Wales-icon.png";    
    // icon license: Free for non-commercial use. 
    // Buy commercial license here: 
    // http://www.customicondesign.com/free-icons/flag-icon-set/flat-round-world-flag-icon-set

    private static final String CLIP_IMAGE_LOC =
            "http://icons.iconarchive.com/icons/gpritiranjan/simple-christmas/128/star-icon.png";
    // star icon license: freeware, commercial usage allowed.
}