UWP/WinUI3 PixelShaderEffect 实现ThresholdEffect 滤镜。

打印 上一主题 下一主题

主题 620|帖子 620|积分 1860

在上一遍文章中已经介绍了PixelShaderEffect 用hlsl(着色器) 可以实现各种自定义滤镜效果了,本文将用 "ThresholdEffect" 来讲解如何编写,编译hlsl,然后使用PixelShaderEffect制作自定义滤镜。
效果图:

 
 
一.hlsl帮助程序介绍
  在写hlsl 代码前需要简单介绍下 “hlsl帮助程序”.通过学习了 hlsl帮助程序 后我们不需要将hlsl的所有知识都掌握了就可以写一写简单的hlsl代码了。hlsl帮助程序分为两部分,宏定义和函数。
  1.宏定义
D2D_INPUT_COUNT N纹理输入个数。必须定义
D2D_INPUTn_SIMPLE 指定第n个纹理的为简单采样,默认为此定义,可选的
D2D_INPUTn_COMPLEX  指定第n个纹理为复杂采样.可选的
D2D_REQUIRES_SCENE_POSITION指示着色器函数调用使用场景位置的值的帮助方法(即使用D2DGetScenePosition函数,必须要有该定义)
D2D_CUSTOM_ENTRY  着色器程序入口
#include "d2d1effecthelpers.hlsli"引入 hlsl帮助程序
  2.函数
D2DGetInput(n)获取第n张纹理的当前位置的像素,返回float4,即是rgba颜色。
D2DSampleInput(n,float2(x,y))(按百分比位置进行采样)获取第n张纹理指定位置(xy按照百分比0~1)的像素颜色,返回float4,即rgba颜色。(需要定义纹理为复杂采样才能使用该函数)
D2DSampleInputAtOffset(n,float2(ox,oy))(按绝对位置进行偏移采样)从输入坐标偏移的偏移量对第n张纹理进行采样(需要定义纹理为复杂采样)。例子:比如需要获取当前像素的左边像素可以使用该函数 D2DSampleInputAtOffset(0,float(-1,0))来获取左边像素的颜色;
D2DSampleInputAtPosition(n,float2(x,y))(按绝对位置进行采样) 例子:比如输入的纹理图像大小的宽和高都为100,现在需要获取该纹理位置 50,50位置的像素可以使用该函数D2DSampleInputAtPosition(0,float2(50,50));(需要定义纹理为复杂采样)
D2DGetInputCoordinate(n)获取当前像素在屏幕上的坐标(相对位置0~1)(需要定义纹理为复杂采样)
D2DGetScenePosition()  获取当前像素在屏幕上的坐标(绝对位置)(需要定义 D2D_REQUIRES_SCENE_POSITION宏)
D2D_PS_ENTRY 函数 一个宏,用于定义具有给定函数名称的像素着色器入口点。
  hlsl帮助程序文档:HLSL 帮助程序 - Win32 apps | Microsoft Docs
  hlsl文档:高级着色器语言 (HLSL) - Win32 apps | Microsoft Docs
二.编写hlsl代码
  在项目程序中右键-》添加新建项-》常规-》文本文件 并将文件名改成ThresholdEffect.hlsl
  在代码中用宏定义了 输入一张纹理,并且将纹理的采样模式定义为简单模式,通过#include 引入hlsl帮助程序。
然后在声明了 三个变量 hreshold,startColor,endColor;
  声明一个 getGray(in float3 color) 函数将颜色的各个分量相加再除以3 并且返回;
  最后定义了一个 D2D_PS_ENTRY 函数,该函数是着色器程序的入口函数,在函数里面调用了 D2DGetInput(0)函数获取第0张纹理的当前像素,然后通过调用getGray 函数将像素的颜色转换成灰度值后跟 threshold 比较再决定返回那个颜色。
注意:函数的声明需要写在调用前,否则编译的时候会找不到函数而报错;
  1. //定义输入纹理数量为 1张
  2. #define D2D_INPUT_COUNT 1
  3. //定义第一张纹理的采样模式为简单模式
  4. #define D2D_INPUT0_SIMPLE
  5. //引入 hlsl帮助程序
  6. #include "d2d1effecthelpers.hlsli"
  7. //定义属性
  8. //阈值
  9. float threshold;
  10. //默认第一个颜色为白色
  11. float4 startColor = float4(1,1,1,1);
  12. //默认第二个颜色为黑色
  13. float4 endColor = float4(0, 0, 0, 1);
  14. //将输入颜色转换成灰度 (r+g+b)/3
  15. float getGray(in float3 color)
  16. {
  17.     float gray = (color.r + color.g + color.b) / 3;
  18.     return gray;
  19. }
  20. //程序入口
  21. D2D_PS_ENTRY(main){
  22.     //获取当前位置的输入纹理像素颜色
  23. float3 color = D2DGetInput(0).rgb;
  24. float gray = getGray(color);
  25.     if(gray<=threshold){
  26.     return endColor;
  27.     }
  28.     return startColor;
  29. }
复制代码
xaml六.后台代码
  1.在 canvas的CreateResource 事件中读取bin文件中的字节数组并创建一个 PixelShaderEffect 对象;
  2.添加选择图片事件用于选择一张输入的源图;
  3.绘制图像,effect 对象通过 Properties 键值对的形式对着色器里面的属性进行赋值。这里需要注意 着色器里面的颜色范围是 0~1 并且是float类型,所以需要将c#里面的颜色的每个分量都除以255,转换成Vector4结构;
  4.监听Slider 和颜色选择器 的更改并重新绘制显示图像;
  1. set INCLUDEPATH="%WindowsSdkDir%\Include\%WindowsSDKVersion%\um"
  2. fxc ThresholdEffect.hlsl /nologo /T lib_4_0_level_9_3_ps_only /D D2D_FUNCTION /D D2D_ENTRY=main /Fl ThresholdEffect.fxlib /I %INCLUDEPATH%
  3. fxc ThresholdEffect.hlsl /nologo /T ps_4_0_level_9_3 /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate ThresholdEffect.fxlib /Fo:ThresholdEffect.bin /I %INCLUDEPATH%
  4. del ThresholdEffect.fxlib
复制代码
ThresholdEffectPage结语:
  现在已经将PixelShaderEffect 的整个使用过程都讲解完了。下一篇讲解 "ReplaceColorEffect";

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表