如何插入颜色序列?

时间:2011-05-02 17:10:02

标签: c++ colors sequence interpolation openframeworks

我需要逐渐插入或改变一系列颜色,因此它从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();

提前致谢

6 个答案:

答案 0 :(得分:10)

你的代码大多是正确的,但是你正在向后插值:即你正在插值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不同的色彩空间可以提供更好看的效果。

答案 1 :(得分:8)

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

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

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

要使用HSL lerp,您需要转换RGB值,在结果之间转换,然后转换回来。 This page有一些可能对此有用的公式,this one有PHP代码来处理它。

答案 2 :(得分:1)

插入R,G和B组件将生成工作代码。唯一的缺点是你产生的步骤不一定会显得相同,即使它们在数学上是相等的。

如果这困扰你,你可以将RGB的值转换为L * a * b *(设计为更接近人类感知),对这些值进行插值,然后将每个插值转换回来到RGB显示。

答案 3 :(得分: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();

答案 4 :(得分:0)

分离三个组件(RBG)并插入每个组件 分别使用经典插值算法。

答案 5 :(得分:0)

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

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