如何在JavaFX渐变中插值颜色?

问题描述

我试图弄清楚当涉及透明度时如何复制JavaFX渐变的插值/混合方式。如果我尝试使用内置的Color#interpolate方法在颜色之间进行内插的简单方法,则会得到完全不同的结果。如您所见:

enter image description here

两个渐变都是简单的[红色@ 0%,rgba(0,0,255,0)@ 50%,绿色@ 100%],但是在JavaFX渐变中根本看不到蓝色(顶部)并且在幼稚的方法中非常明显(底部)。怎样在渐变中插值颜色的实际公式是什么?在哪里可以找到颜色(即什么类的方法)?


这是一个显示半透明性的示例(从rgba(255,0,0,1)到rgba(0,0,255,0.5)):

enter image description here

该图显示了所得颜色的采样分量(白色表示不透明度)。注意颜色通道是如何非线性插值的。我正在寻找可以调整曲线的方程式。

解决方法

此答案的信用额为@fabian

渲染渐变时,Prism uses pre-multiplied colors

要获得相同的结果,您可以像这样手动进行预乘:

public Color interpolatePreMultiplied(double ratio,Color origin,Color target) {
    var opacity = lerp(ratio,origin.getOpacity(),target.getOpacity());
    return opacity == 0.0 ? Color.TRANSPARENT : Color.color(
        lerp(ratio,origin.getRed() * origin.getOpacity(),target.getRed() * target.getOpacity()) / opacity,lerp(ratio,origin.getBlue() * origin.getOpacity(),target.getBlue() * target.getOpacity()) / opacity,opacity
    );
}

public double lerp(double ratio,double origin,double target) {
    return origin + (target - origin) * ratio;
}

或者您可以使用一些实用程序转换:

public Color interpolatePreMultiplied(double ratio,Color target) {
    var po = toPreMutliplied(origin);
    var pt = toPreMultiplied(target);
    return toStraightAlpha(po.interpolate(pt,ratio));
}

public Color toPreMultiplied(Color color) {
    return Color.color(
        color.getRed() * color.getOpacity(),color.getGreen() * color.getOpacity(),color.getBlue() * color.getOpacity(),color.getOpacity()
    );
}

public Color toStraightAlpha(Color color) {
    return color.getOpacity() == 0.0 ? Color.TRANSPARENT : Color.color(
        color.getRed() / color.getOpacity(),color.getGreen() / color.getOpacity(),color.getBlue() / color.getOpacity(),color.getOpacity()
    );
}