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 颜色会产生黑色的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL颜色混合原理

渲染管道像素阶段“Alpha混合”

渲染管道像素阶段“Alpha混合”

在 Alpha 混合图像上设置背景颜色

Alpha 混合和 UIView 背景颜色

Unity Shader---Alpha Blending的意义