3

我需要逐步插入或更改一系列颜色,因此它从 colorA 到 colorB 再到 colorC 再到 colorD 并返回到 colorA,这需要基于以毫秒为单位的时间,任何帮助将不胜感激(算法,伪代码会很棒)。

请注意,我正在使用 RGB,它可能是 0-255 或 0.0-1.0 范围。

这就是我到目前为止所拥有的,我需要在每个“timePeriod”上更改颜色,我计算经过的时间百分比并更改颜色,这段代码的问题是当它从 A 到B 到 B 到 C 等等

int millisNow = ofGetElapsedTimeMillis();
int millisSinceLastCheck = millisNow - lastTimeCheck;
if ( millisSinceLastCheck > timePeriod ) {
    lastTimeCheck = millisNow;
    millisSinceLastCheck = 0;
    colorsIndex++;
    if ( colorsIndex == colors.size()-1 ) colorsIndex = 0;
    cout << "color indes: " << colorsIndex << endl;
    cout << "color indes: " << colorsIndex + 1 << endl;
}
timeFraction = (float)(millisSinceLastCheck) / (float)(timePeriod);
float p = timeFraction;
colorT.r = colors[colorsIndex].r * p + ( colors[colorsIndex+1].r * ( 1.0 - p ) );
colorT.g = colors[colorsIndex].g * p + ( colors[colorsIndex+1].g * ( 1.0 - p ) );
colorT.b = colors[colorsIndex].b * p + ( colors[colorsIndex+1].b * ( 1.0 - p ) );
colorT.normalize();

提前致谢

4

6 回答 6

11

您的代码大部分是正确的,但是您正在反向进行插值:即您正在插值 B->A,然后是 C->B,然后是 D->C,等等。这会导致切换颜色时的不连续性。

你应该替换这个:

colorT.r = colors[colorsIndex].r * p + ( colors[colorsIndex+1].r * ( 1.0 - p ) );

和:

colorT.r = colors[colorsIndex].r * (1.0 - p) + ( colors[colorsIndex+1].r * p );

其他行也是如此。

此外,正如其他人所说,使用与 RGB 不同的色彩空间可以提供更好的外观效果。

于 2011-05-02T17:25:47.817 回答
9

有两种方法可以处理插值颜色。一个快速简单(你在做什么),另一个稍微慢一些,但在某些情况下看起来更好。

第一个是显而易见的、简单的方法(x * s) + (y * (1-s)),它是纯线性插值,顾名思义。但是,在某些颜色对(例如绿色和橙色)上,中间会出现一些令人讨厌的颜色(脏棕色)。那是因为您正在使用每个组件(R、G 和 B),并且有些地方的组合令人不快。如果您只需要最基本的lerp,那么这就是您想要的方法,并且您的代码是正确的。

如果您想要更好看但稍慢的效果,您需要在 HSL 颜色空间中进行插值。由于色调、饱和度和亮度都是插值的,因此您可以在它们之间获得您期望的颜色,并且可以避免大多数丑陋的颜色。由于颜色通常是在某种轮子中绘制的,因此该方法意识到了这一点(基本 RGB lerp 的行为就像它使用 3 条离散线一样)。

要使用 HSL lerp,您需要转换 RGB 值,在结果之间进行 lerp,然后再转换回来。这个页面有一些可能有用的公式,这个页面有PHP 代码来处理它。

于 2011-05-02T17:22:13.583 回答
1

对 R、G 和 B 分量进行插值将产生工作代码。一个缺点是您生成的步骤不一定看起来相同,即使它们在数学上是相等的。

如果这让您感到困扰,您可以将值从 RGB 转换为 L*a*b* (旨在更接近于人类感知),对这些值进行插值,然后将每个插值转换回 RGB展示。

于 2011-05-02T17:21:33.740 回答
1

你已经得到的东西看起来非常好,但我会稍微简化一下数学:

int millisNow = ofGetElapsedTimeMillis();
int millisSinceLastCheck = millisNow % timerPeriod;
int colorsIndex = (millisNow / timerPerod) % (colors.size() - 1);


float p = (float)(millisSinceLastCheck) / (float)(timePeriod);
colorT.r = colors[colorsIndex+1].r * p + ( colors[colorsIndex].r * ( 1.0 - p ) );
colorT.g = colors[colorsIndex+1].g * p + ( colors[colorsIndex].g * ( 1.0 - p ) );
colorT.b = colors[colorsIndex+1].b * p + ( colors[colorsIndex].b * ( 1.0 - p ) );
colorT.normalize();
于 2011-05-02T17:28:51.030 回答
0

我们正在为我目前正在进行的一个项目做这件事。我们只是独立处理 R、G、B 值,并根据中间有多少“步骤”从 color1 过渡到 color2。我们有离散值,所以我们有一个查找表的方法,但是你可以用浮点做同样的事情,只是动态地计算 RGB 值。

如果您仍有疑问,我可以发布一些 Java 代码。

于 2011-05-02T17:14:43.023 回答
-1

使用经典插值算法分离三个分量 (RBG) 并分别插值。

于 2011-05-02T17:14:23.843 回答