Alpha 混合 - 反复混合 RGBA 颜色会产生黑色
Posted
技术标签:
【中文标题】Alpha 混合 - 反复混合 RGBA 颜色会产生黑色【英文标题】:Alpha Blending - Repeatedly mixing RGBA colors results in black 【发布时间】:2014-04-14 14:16:42 【问题描述】:我从另一个问题中实现了this code,效果非常好。
我遇到的问题是反复混合两种颜色会慢慢变成黑色。这是一个效果示例。
我正在使用 C#,并且我有两种颜色的 RGBA(背景和前景),颜色为 Color32 类型 - 1 个字节用于红色、绿色、蓝色和 alpha。目前我正在将 0-255 转换为 0-1,但我认为存在一些浮点转换问题。
有什么方法不会产生这种效果?
编辑:这是我正在使用的代码。 currentColor
是画布(背景),brushColor
是前景。
float bg_r = ((float)currentColor.r) / 255.0f;
float bg_g = ((float)currentColor.g) / 255.0f;
float bg_b = ((float)currentColor.b) / 255.0f;
float bg_a = ((float)currentColor.a) / 255.0f;
float bg_r_a = bg_r * bg_a;
float bg_g_a = bg_g * bg_a;
float bg_b_a = bg_b * bg_a;
float fg_r = ((float)brushColor.r) / 255.0f;
float fg_g = ((float)brushColor.g) / 255.0f;
float fg_b = ((float)brushColor.b) / 255.0f;
float fg_a = (((float)brushColor.a) / 255.0f) * brush.pressure; // 0 - 1
float fg_r_a = fg_r * fg_a;
float fg_g_a = fg_g * fg_a;
float fg_b_a = fg_b * fg_a;
float col_r_a = fg_r_a + bg_r_a * ( 1.0f - fg_a );
float col_g_a = fg_g_a + bg_g_a * ( 1.0f - fg_a );
float col_b_a = fg_b_a + bg_b_a * ( 1.0f - fg_a );
float col_a = fg_a + bg_a * ( 1.0f - fg_a );
float col_r = col_r_a / col_a;
float col_g = col_g_a / col_a;
float col_b = col_b_a / col_a;
byte colR = (byte)Mathf.Clamp( col_r * 255.0f, 0.0f, 255.0f );
byte colG = (byte)Mathf.Clamp( col_g * 255.0f, 0.0f, 255.0f );
byte colB = (byte)Mathf.Clamp( col_b * 255.0f, 0.0f, 255.0f );
byte colA = (byte)Mathf.Clamp( col_a * 255.0f, 0.0f, 255.0f );
Color32 outputColor = new Color32( colR, colG, colB, colA );
链接:http://pastebin.com/hXkKSYLe
【问题讨论】:
我们可以看看你的代码吗? 同意itsme。你是正确舍入还是截断浮点数?如果是后者,这可能是问题所在。除此之外,如果您仍然需要浮点值,我会将其存储为浮点数,然后转换为 int 以显示图像。这样您就不会丢失数据。 我添加了我的代码示例。存储为浮点数可能是要走的路,我稍后会转换并测试。 几年后才意识到这一点,我从未发布过我的结果 - 在内部将数据存储为浮点数,并且仅在设置数据修复问题时转换为字节。 【参考方案1】:问题可能出在以下几行:
byte colR = (byte)Mathf.Clamp( col_r * 255.0f, 0.0f, 255.0f );
具体来说,(byte)
演员表。从浮点类型转换为整数类型将截断小数部分:
Console.WriteLine((byte)1.9f); // Outputs "1"
Console.WriteLine((int)-1.9f); // Outputs "-1"
因此,在每次转换回字节后,您将平均损失 0.5 字节大小的增量,并且在平均 512 次转换后,您的颜色将变为黑色。
尝试添加对Math.Round
的调用以消除偏差。
byte colR = (byte)Math.Round(Mathf.Clamp( col_r * 255.0f, 0.0f, 255.0f ));
【讨论】:
当然,但 not 舍入将概率性地漂移为零。四舍五入将消除这种偏差。 没有人说你必须扔掉颜色通道的小数部分以上是关于Alpha 混合 - 反复混合 RGBA 颜色会产生黑色的主要内容,如果未能解决你的问题,请参考以下文章