如何插入颜色序列?

发布于 2024-11-04 09:47:45 字数 1075 浏览 5 评论 0原文

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

提前致谢

I need to interpolate or change gradually a sequence of colors, so it goes from colorA to colorB to colorC to colorD and them back to colorA, this need to be based on time elapsed in milliseconds, any help will be much appreciated (algorithms, pseudo code will be great).

Note that I am working with RGB, it could be 0-255 or 0.0-1.0 range.

This is what I have so far, I need to change the colors on every "timePeriod", them I calculate the percentage of time elapsed and change the colors, the problem with this code is that there is a jump when it goes from A to B to B to C and so on

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();

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

北风几吹夏 2024-11-11 09:47:47

您的代码大部分是正确的,但是您正在向后进行插值:即您正在插值 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 不同的色彩空间可以提供更好的外观结果。

Your code is mostly correct, but you are doing the interpolation backwards: i.e. you are interpolating B->A, then C->B, then D->C, etc. This causes the discontinuity when switching colors.

You should replace this:

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

with:

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

and the same for the other lines.

Also, as others have said, using a different color space than RGB can provide better looking results.

风轻花落早 2024-11-11 09:47:47

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

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

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

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

There are two ways to handle interpolating colors. One is fast and easy (what you're doing), the other is slightly slower but can look better in some circumstances.

The first is the obvious, simple method of (x * s) + (y * (1-s)), which is pure linear interpolation and does what the name suggests. However, on certain color pairs (say green and orange), you get some nasty colors in the middle (a dirty brown). That's because you're lerping each component (R, G and B) and there are points where the combination is unpleasant. If you just need the most basic lerp, then this is the method you want, and your code is about right.

If you want a better-looking but slightly slower effect, you'll want to interpolate in HSL colorspace. Since the hue, saturation and lum are each interpolated, you get what color you would expect between them and can avoid a majority of the ugly ones. Since colors are typically drawn in some sort of wheel, this method is aware of that (where as basic RGB lerp acts like it's working with 3 discrete lines).

To use an HSL lerp, you need to convert the RGB values, lerp between the results, and convert back. This page has some formulas that may be useful for that, and this one has PHP code to handle it.

浅语花开 2024-11-11 09:47:47

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

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

Interpolating the R, G, and B components will produce working code. The one shortcoming is that the steps you produce won't necessarily appear the same, even though they're mathematically equal.

If that bothers you, you could convert values from RGB to something like L*a*b* (which is designed to correspond more closely to human perception), do your interpolation on those values, and then convert each interpolated value back to RGB for display.

你又不是我 2024-11-11 09:47:47

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

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();

What you've got already looks very good, but I'd simplify the math a little bit:

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();
请你别敷衍 2024-11-11 09:47:47

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

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

We're doing this on a project I'm currently working on. We just treat the R, G, B values independently and transition from color1 to color2 based on how many "steps" there are in between. We have discrete values so we have a look-up table approach, but you could do the same thing with floating point and just calculate the RGB values dynamically.

If you still have questions, I could post some Java code.

风月客 2024-11-11 09:47:47

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

Separate the three components (RBG) and interpolate each
separately, using the classical interpolation algorithm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文