当前位置: 首页 > news >正文

透明度叠加算法:如何计算半透明像素叠加到另一个像素上的实际可见像素值(附 WPF 和 HLSL 的实现)

本文介绍透明度叠加算法(Alpha Blending Algorithm),并用 C#/WPF 的代码,以及像素着色器的代码 HLSL 来实现它。


本文内容

    • 算法
    • 在 C# 代码中实现
    • 在像素着色器中实现

算法

对于算法,我只是搬运工,可以随意搜索到。算法详情请查看:Alpha compositing - Wikipedia。

对于完全不透明的背景和带有透明度的前景,合并算法为:

float r = (foreground.r * alpha) + (background.r * (1.0 - alpha));

这是红色。然后绿色 g 和蓝色 b 通道进行一样的计算。最终合成图像的透明通道始终设置为 1。

在 C# 代码中实现

多数 UI 框架对于颜色值的处理都是用一个 byte 赛表单个通道的一个像素。于是计算会采用 0xff 即 255。

for (int i = 0; i + 4 < length; i = i + 4)
{
    var backB = background[i];
    var backG = background[i + 1];
    var backR = background[i + 2];
    var foreB = foreground[i];
    var foreG = foreground[i + 1];
    var foreR = foreground[i + 2];
    double alpha = foreground[i + 3];

    blue = 0;

    output[i] = (foreB * alpha) + (backB * (1.0 - alpha));
    output[i + 1] = (foreG * alpha) + (backG * (1.0 - alpha));
    output[i + 2] = (foreR * alpha) + (backR * (1.0 - alpha));
    output[i + 3] = 1.0;
}

这段代码当然是跑不起来的,因为是下面两篇博客的魔改代码。你需要阅读以下两篇博客了解如何在 WPF 中按像素修改图像,然后应用上面的透明度叠加代码。

  • WPF 修改图片颜色
  • WPF 通过位处理合并图片

话说,一般 UI 框架都自带有透明度叠加,为什么还要自己写一份呢?

当然是因为某些场景下我们无法使用到 UI 框架的透明度叠加特性的时候。例如使用 HLSL 编写像素着色器的一个实现。

下面使用像素着色器的实现是我曾经写过的一个特效的一个小部分,我把透明度叠加的部分单独摘取出来。

在像素着色器中实现

以下是 HLSL 代码的实现。Background 是从采样寄存器 0 取到的颜色采样,Foreground 是从采样寄存器 1 取到的颜色采样。

这里的计算中,背景是不带透明度的,而前景是带有透明度的。

/// <description>透明度叠加效果。</description>

sampler2D Background : register(s0);
sampler2D Foreground : register(s1);

float4 main(float2 uv : TEXCOORD) : COlOR
{
    float4 background = tex2D(Background, uv);
    float4 foreground = tex2D(Foreground, uv);
    float alpha = foreground.a;

    float r = (foreground.r * alpha) + (background.r * (1.0 - alpha));
    float g = (foreground.g * alpha) + (background.g * (1.0 - alpha));
    float b = (foreground.b * alpha) + (background.b * (1.0 - alpha));
    float a = 1.0;
    
    return float4(r, g, b, a);
}

叠加了一个带有透明度的图片

如果要测试的图片都是不带透明度的,那么可以通过自己设一个透明度来模拟,传入透明度值 Alpha。

/// <description>透明度叠加效果。</description>

/// <type>Double</type>
/// <summary>采样 2 的叠加透明度。</summary>
/// <minValue>0.0</minValue>
/// <maxValue>1.0</maxValue>
/// <defaultValue>0.75</defaultValue>
float Alpha : register(C0);

sampler2D Background : register(s0);
sampler2D Foreground : register(s1);

float4 main(float2 uv : TEXCOORD) : COlOR
{
    float4 background = tex2D(Background, uv);
    float4 foreground = tex2D(Foreground, uv);
    float alpha = Alpha;

    float r = (foreground.r * alpha) + (background.r * (1.0 - alpha));
    float g = (foreground.g * alpha) + (background.g * (1.0 - alpha));
    float b = (foreground.b * alpha) + (background.b * (1.0 - alpha));
    float a = 1.0;
    
    return float4(r, g, b, a);
}

为第二张采样设定透明度


参考资料

  • Alpha compositing - Wikipedia
  • algorithm - Manually alpha blending an RGBA pixel with an RGB pixel - Stack Overflow

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • C#/.NET 调试的时候显示自定义的调试信息(DebuggerDisplay 和 DebuggerTypeProxy)
  • 详解 .NET 反射中的 BindingFlags 以及常用的 BindingFlags 使用方式
  • 在 csproj 文件中使用系统环境变量的值(示例将 dll 生成到 AppData 目录下)
  • git subtree 的使用
  • 让你的 VSCode 具备调试 C# 语言 .NET Core 程序的能力
  • 手工编辑 tasks.json 和 launch.json,让你的 VSCode 具备调试 .NET Core 程序的能力
  • C#/.NET 如何结束掉一个进程
  • C#/.NET 移动或重命名一个文件夹(如果存在,则合并而不是出现异常报错)
  • 如何创建应用程序清单文件 App.Manifest,如何创建不带清单的应用程序
  • 应用程序清单 Manifest 中各种 UAC 权限级别的含义和效果
  • 启用 Windows 审核模式(Audit Mode),以 Administrator 账户来设置电脑的开箱体验
  • Windows 中的 UAC 用户账户控制
  • Windows 下使用 runas 命令以指定的权限启动一个进程(非管理员、管理员)
  • Windows 的 UAC 设置中的通知等级实际上只有两个档而已
  • Windows 系统上使用任务管理器查看进程的各项属性(命令行、DPI、管理员权限等)
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 【391天】每日项目总结系列128(2018.03.03)
  • 2019年如何成为全栈工程师?
  • android图片蒙层
  • Angularjs之国际化
  • jquery cookie
  • Less 日常用法
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • 编写高质量JavaScript代码之并发
  • 警报:线上事故之CountDownLatch的威力
  • 坑!为什么View.startAnimation不起作用?
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 前端
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 使用 @font-face
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 小程序button引导用户授权
  • 一文看透浏览器架构
  • 说说我为什么看好Spring Cloud Alibaba
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • #QT(TCP网络编程-服务端)
  • $().each和$.each的区别
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (六)软件测试分工
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (四)库存超卖案例实战——优化redis分布式锁
  • (循环依赖问题)学习spring的第九天
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (转)使用VMware vSphere标准交换机设置网络连接
  • (转载)Linux 多线程条件变量同步
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .net MVC中使用angularJs刷新页面数据列表