当我减少已经等于零的颜色通道时,为什么Unity3D颜色会发生变化?

时间:2016-10-10 23:03:35

标签: c# unity3d colors material

这是个热点案例。从某种意义上说,即使在建议中它也没有任何解释。

所以

我有场景中的立方体。

在循环中我为每个立方体启动协同程序,这个协程会做下一件事:

它将立方体的颜色从黑色(0,0,0)更改为红色(1,0,0),然后执行反转操作。在我的代码中,部分地,我将颜色从红色返回到黑色,我减少了G和B字段的值。我为什么要这么做?我会这样做,如果我在copypast之后修改这些行,我将颜色从黑色变为红色,当它不是红色时,以及当我改变R和G和B时。

private IEnumerator CororRoutine(Material cubeMaterial)
{
    float coff = 1f;

    while (cubeMaterial.color.r < 1.0f)
    {
        cubeMaterial.color = new Color(
            cubeMaterial.color.r + coff * Time.deltaTime,
            0.0f,
            0.0f);

        yield return new WaitForEndOfFrame();
    }

    while (cubeMaterial.color.r > 0.0f)
    {
        cubeMaterial.color = new Color(
            cubeMaterial.color.r - coff * Time.deltaTime,
            cubeMaterial.color.g - coff * Time.deltaTime,
            cubeMaterial.color.b - coff * Time.deltaTime);

        yield return new WaitForEndOfFrame();
    }
}

所以,有一件非常奇怪的事情发生了...... 截图: enter image description here

正如您所看到的,已经双向改变的立方体有一点红色。但。材料中反照率颜色的值完全为(0,0,0)。 在屏幕截图中,您可以看到材料上的红色阴影。

如果你知道某些事情,那可以让我对这里发生的事情有所了解,这将非常有帮助。

Edit_1:

问题是:当我减少已经为0的颜色通道时,为什么颜色会发生变化?这对任何人都知道吗? 我知道我不应该减少已经等于0的通道的值。 但是当我这样做的时候,当材料的颜色发生变化时,这似乎很奇怪。

3 个答案:

答案 0 :(得分:1)

  

当我减少已经为0的颜色通道时,为什么颜色会发生变化?   这对任何人都知道吗?我知道我不应该减少值   已经等于0的频道。但是,这似乎很奇怪   当我这样做时,材料的颜色会发生变化。

ChristFLe len已经回答了您的问题。请阅读它们。阅读他们谈到的负面价值。这就是问题所在。

我回答这个问题的唯一原因是因为我认为你做错了,而且这两个答案都没有提供一种改变颜色的正确方法

Debug.Log("R: " + cubeMaterial.color.r);
Debug.Log("G: " + cubeMaterial.color.g);
Debug.Log("B: " + cubeMaterial.color.b);

在第二个while循环中。您会注意到RGB值正在变为负值。我得到了以下值:

R: -0.0210881
G: -1.026095
B: -1.026095

color.rcolor.gcolor.bcolor.a属性允许从0.0f1.0f的值。您不能使用小于0f的值或大于1f的值。如果这样做,您将得到未定义的行为,因为没有人知道Unity如何处理超出此范围的值。不要问为什么,因为这是由Unity设定的规则。它是如此简单。

来自Unity Doc的直接引用:

  

这种结构在整个Unity中用于传递颜色。每   color component是一个浮点值,范围从0到1.

请注意,您当前的while循环无法阻止值低于0或高于1

<强>解

您有两种选择。

1 。您可以使用Mathf.ClampMathf.Clamp01来解决此问题。这会将您的价值限制在01之间。

替换

cubeMaterial.color = new Color(
cubeMaterial.color.r - coff * Time.deltaTime,
cubeMaterial.color.g - coff * Time.deltaTime,
cubeMaterial.color.b - coff * Time.deltaTime);

cubeMaterial.color = new Color(
Mathf.Clamp(cubeMaterial.color.r - coff * Time.deltaTime, 0, 1),
Mathf.Clamp(cubeMaterial.color.g - coff * Time.deltaTime, 0, 1),
Mathf.Clamp(cubeMaterial.color.b - coff * Time.deltaTime, 0, 1));

2 。这是正确的方式。您不应该首先增加颜色值。这个答案中的第一个解决方案只是一个黑客攻击。真正的解决方案是使用Color.Lerp。这将在两种颜色之间变化。我强烈推荐这个解决方案。

private IEnumerator CororRoutine(Material cubeMaterial)
{
    float counter = 0f;
    float changeDuration = 1f;

    Color blackColor = Color.black; //OR new Color(0f,0f,1f);
    Color redColor = Color.red; //OR new Color(1f,0f,0f);

    //Black To Red
    while (counter < changeDuration)
    {
        counter += Time.deltaTime;
        cubeMaterial.color = Color.Lerp(blackColor, redColor, counter / changeDuration);
        yield return new WaitForEndOfFrame();
    }

    counter = 0;

    //Red To Black
    while (counter < changeDuration)
    {
        counter += Time.deltaTime;
        cubeMaterial.color = Color.Lerp(redColor, blackColor, counter / changeDuration);
        yield return new WaitForEndOfFrame();
    }
}

答案 1 :(得分:0)

也许是因为你在说

        cubeMaterial.color.g - coff * Time.deltaTime,
        cubeMaterial.color.b - coff * Time.deltaTime);

虽然已经0

答案 2 :(得分:0)

  

在我的代码中,部分地,我将颜色从红色返回到黑色,我减少了G和B字段的值。我为什么要这么做?我会这样做,如果我在copypast之后修改这些行,我将颜色从黑色变为红色,当它不是红色时,以及当我改变R和G和B时。

当您从其他地方复制代码时,您似乎忘了更改此代码。

如果您确定绿色和蓝色组件没有变化,那么您可以简单地写一下:

while (cubeMaterial.color.r > 0.0f)
{
    cubeMaterial.color = new Color(
        cubeMaterial.color.r - coff * Time.deltaTime,
        0.0f,
        0.0f);

    yield return new WaitForEndOfFrame();
}

如果这些值可能已更改,那么您希望在递减其值之前检查绿色和蓝色成分是否已经为零。

如果coff - Time.deltaTime的值大于当前cubeMaterial.color.r,则可能会出现问题。这将导致&#34;否定&#34;颜色。即使成功创建,我也不知道。

如果没有创建,这将使您的对象保留最后的有效颜色 - 深红色。

如果它确实被创建,那么如果显示代码忽略了这个符号,这将解释对象的非常轻微的红色。

您正在使用float值,虽然这些值非常适合速度,但它们存在准确性问题。当你足够接近时,我会添加一个额外的测试来将值设置为零:

float offset = coff * Time.deltaTime;
while (cubeMaterial.color.r > 0.0f)
{
    cubeMaterial.color = new Color(
        (offset > cubeMaterial.color.r) ? cubeMaterial.color.r - offset : 0.0f,
        0.0f,
        0.0f);

    yield return new WaitForEndOfFrame();
}