生成随机颜色并排除旧颜色的最佳方法

时间:2017-12-03 09:49:36

标签: c# unity3d random colors

不完全确定如何标记标题但我想在对象上每秒生成一个随机颜色。我也希望这种颜色与对象已有的旧颜色不相似。如果当前随机颜色与对象已有的颜色相同,则再次重新生成随机颜色。该对象只是一个Text组件。

这是我用来生成颜色的函数:

public Color genRandomColor()
{
    float r, g, b;
    r = UnityEngine.Random.Range(0f, 1f);
    g = UnityEngine.Random.Range(0f, 1f);
    b = UnityEngine.Random.Range(0f, 1f);

    return new Color(r, g, b);
}

为了比较颜色是否相似,我移植并使用this中的函数回答C#。

public double ColourDistance(Color32 c1, Color32 c2)
{
    double rmean = (c1.r + c2.r) / 2;
    int r = c1.r - c2.r;
    int g = c1.g - c2.g;
    int b = c1.b - c2.b;
    double weightR = 2 + rmean / 256;
    double weightG = 4.0;
    double weightB = 2 + (255 - rmean) / 256;
    return Math.Sqrt(weightR * r * r + weightG * g * g + weightB * b * b);
}

我将随机颜色生成器放在一个协程函数内的while循环中,一遍又一遍地运行,直到生成的颜色不相似为止。每次生成随机颜色时,我都会使用yield return null;等待一帧,这样它就不会冻结程序。

const float threshold = 400f;
bool keepRunning = true;

while (keepRunning)
{
    Text text = obj.GetComponent<Text>();

    //Generate new color but make sure it's not similar to the old one
    Color randColor = genRandomColor();
    while ((ColourDistance(text.color, randColor) <= threshold))
    {
        Debug.Log("Color not original. Generating a new Color next frame");
        randColor = genRandomColor();
        yield return null;
    }

    text.color = randColor;
    yield return new WaitForSeconds(1f);
}

一切似乎都在解决一个小问题。

问题在于,有时需要13秒重新生成与旧版本不相似的颜色。我删除yield return null;以防止它等待每一帧,它现在似乎工作但我冒着冻结整个游戏的风险,因为我现在使用随机函数来控制while循环。我已经注意到了很小的冻结,但这并不好。

在不冻结游戏或等待几秒钟的情况下,生成与对象的新颜色不相似的随机颜色的更好方法是什么?

2 个答案:

答案 0 :(得分:3)

我会采取不同的方法:

  • 在[0;中生成随机整数2]代表红色,绿色,蓝色
  • 将0.5添加到刚刚在第一步中确定的颜色,但如果大于1
  • 则减去-1
  • 在[0;范围内]生成2个独立的随机浮点数。 1]是为剩余的两个颜色成分而采取的

示例:假设我们有C1 =(R1; G1; B1)=(0.71; 0.22; 0.83)

  • 假设步骤1产生索引0,即红色
  • 因此我们采用R1 + 0.5 = 0.71 + 0.5f = 0.21f
  • 我们创建G2和B2作为新的绿色和蓝色组件并得到(0.21f; G2; B2)

即使G2和B2与它们的前辈相同,当R2移位时,新颜色也会明显不同

更新代码

    # set t1 to value 0 or 1, depending on the (x < 10) condition
    slti  $t1, $t0, 10   # t1 = 1 when x < 10 || 0 when 10 <= x
    # now use the 1/0 value to adjust x by left-shifting it
    sllv  $t0, $t0, $t1  # shift left x by t1 bits (doing *= 2 or *= 1)

测试:

public static class RandomColorGenerator
{
    public static Color GetNextPseudoRandomColor(Color current)
    {
        int keep = new System.Random().Next(0, 2);
        float red = UnityEngine.Random.Range(0f, 1f);
        float green = UnityEngine.Random.Range(0f, 1f);
        float blue = UnityEngine.Random.Range(0f, 1f);
        Color c = new Color(red, green, blue);
        float fixedComp = c[keep] + 0.5f;
        c[keep] = fixedComp - Mathf.Floor(fixedComp);
        return c;
    }
}

运行编辑器测试后,在(0; 0; 0)周围生成场景视图 enter image description here

答案 1 :(得分:2)

这是另一个想法:

而不是生成RBG组件,而是生成HSV组合(并转换)。就人眼而言,色调的差异约为15度(在0-1等级上约为0.05)足以被认为是不同的颜色。这是唯一重要的价值。

例如,这里的图像是顶部带红色的图像(&#34; 0度&#34;)。沿着底部有4种颜色:沿着&#34; hue&#34; 7,15,30和60度。滑块。

Color distinction

7度差异可以但看起来太近了。 15度转换绝对是一种不同的颜色(即使我将它和下一个同时称为#34;橙色&#34;它们至少不同的橙色)

您可以选择所需的任何阈值并生成新颜色,直到新颜色超过您的阈值(以度为单位)。对于值和饱和度,您几乎可以生成从0到1的任何值,因为即使值与前一颜色完全相同,最小强制色调差异也会导致颜色大不相同。

然后,converting from HSV to RGB非常简单。

我用两种不同的语言完成了这种事情,其中​​一种用于我特别希望生成两种或三种不同颜色的项目。同时还确保亮度足够高(即我不希望&#34;黑色&#34;可能),因此HSV是唯一明智的解决方案:我可以生成随机色调,设置值和饱和度朝向最大值(例如random range [0.8,1.0])。另一个项目是我将两个图像合并为一个纹理:我想保留第一个图像的相同色调和饱和度,但是根据第二个图像调整。 / p>

您可能还想根据您的目标偏置饱和度和值数字,如果饱和度或值太低(低于0.5),色调将开始模糊并且太相似(颜色将全部变得混乱)。或者,您可以生成0到1之间的单个浮点数,并将饱和度设置为that number,将值设置为one minus that number