2020-09-22

【UWP】初试 SkiaSharp 中的 Runtime Effect

SkiaSharp 是跨平台图形库 skia 的 .net 封装。在 skia 的 m81 版本中,SkRuntimeEffect 变成了一个公开的 API。而 SkRuntimeEffect 有什么用呢,根据说明,可以使用 Skia 专门的着色器语言来编写着色器。而着色器这个相对来说还是挺好理解的,就是给一个面添加颜色。

目前最新版本的 SkiaSharp 还是基于 m80 版本进行的封装。我们需要用到预览版的 SkiaSharp 才行,打开 VS,更改 nuget 包源:

Snipaste_2020-09-22_10-21-08

 

接下来创建 UWP 项目,添加 SkiaSharp 和 SkiaSharp.Views 引用。注意这里可能会等很久或者失败,建议禾斗学上网,或者手动下载 SkiaSharp 的这个 nuget 包到本地,然后再更改 nuget 包源指向本地文件夹。包下载地址:https://nugetized.blob.core.windows.net/skiasharp-eap/flatcontainer/skiasharp/2.84.0-preview.2/skiasharp.2.84.0-preview.2.nupkg

Snipaste_2020-09-22_10-23-51

版本号中的 84 表明是根据 skia m84 这个版本封装的。

 

接下来修改 xaml,添加 SKSwapChainPanel 并订阅 PaintSurface 事件。

编写 PaintSurface 事件处理函数:

  private void SKSwapChainPanel_PaintSurface(object sender, SKPaintGLSurfaceEventArgs e)  {   var renderTarget = e.BackendRenderTarget;   var surface = e.Surface;   var canvas = surface.Canvas;   canvas.Clear();   const string sksl = @"void main(float2 fragCoord, inout half4 fragColor){ fragColor = half4(1.0,0.0,0.0,1.0);}";   using (var effect = SKRuntimeEffect.Create(sksl, out var errors))   {    using (var paint = new SKPaint())    {     var shader = effect.ToShader(false);     paint.Shader = shader;     canvas.DrawRect(0, 0, renderTarget.Width, renderTarget.Height, paint);    }   }  }

接下来我们一行行说明一下每行代码的作用。

var renderTarget = e.BackendRenderTaget;

从事件对象中获取渲染的目标,从这里我们可以获取到渲染目标的大小。

var surface = e.Surface;var canvas = surface.Canvas;

获取绘制画布。

canvas.Clear();

清空画布,因为 PaintSurface 事件是有可能不断触发的(例如改变控件大小),如果不清空的话,内容就会不断叠加上去。

const string sksl = @"void main(float2 fragCoord, inout half4 fragColor){ fragColor = half4(1.0,0.0,0.0,1.0);}";

声明 skia 着色器语言(SKSL)。SKSL 的说明可以看这里:https://skia.googlesource.com/skia/+/master/src/sksl/README 或者 Github 镜像地址:https://github.com/google/skia/blob/master/src/sksl/README

而 shader 语言中需要像 c 语言一样声明一个 main 函数。SKSL 类似于 GLSL,但还是有一点点区别。

在 https://medium.com/cavalry-animation/sksl-in-cavalry-932d503c889e 这篇文章中,我们可以知道 SKSL 的 main 函数的签名:

Snipaste_2020-09-22_10-52-03

也就是:

void main(float2 fragCoord, inout half4 fragColor)

float2 代表包含两个单精度浮点数 float 的结构体,half4 代表包含四个半精度浮点数 half 的结构体。inout 表明这个参数是输入输出,类似 C# 里的 ref。根据参数名,我们知道第一个参数 fragCoord 是某个像素点的坐标,而 fragColor 则是这个点的颜色(rgba)。

接下来我们返回红色,也就是 fragColor = half4(1.0, 0.0, 0.0, 1.0)。至于这里为什么不用 255 来代表全红,而用 1.0,我理解是因为 255 包含的色域还不够多,而用这种百分比的方式则能够显示更多的颜色。

using (var effect = SKRuntimeEffect.Create(sksl, out var errors))

这里就是根据 SKSL 动态编译出一个 effect,如果没有编译错误的话,errors 将会是 null。

using (var paint = new SKPaint())

创建了一个画笔。

var shader = effect.ToShader(false);paint.Shader = shader;

将 effect 转换成 shader,并附着到画笔上。ToShader 的参数名是 isOpaque,翻译过来就是:是否是不透明的。这里我们可能需要 alpha 通道,所以传 false。

canvas.DrawRect(0, 0, renderTarget.Width, renderTarget.Height, paint);

最后就是在画布上画一个和画布一样大小的矩形了,这样相当于填充了整个矩形。

 

运行之后我们可以看到如下效果:

Snipaste_2020-09-22_11-10-46

 

看上去用 Shader 比直接设置画笔颜色画矩形复杂多了。这里我再举一个小例子:

const string sksl = @"void main(float2 fragCoord, inout half4 fragColor){ float scale = 10; float x = fragCoord.x / scale; float y = fragCoord.y / scale; if (int(mod(x, 2.0)) == 0 ^^ int(mod(y, 2.0)) == 0) {  fragColor = half4(1.0,0.0,0.0,1.0); } else {  fragColor = half4(0.0,1.0,0.0,1.0); }}";

出来的效果是这样的:

Snipaste_2020-09-22_12-11-11

这个虽然效果用传统的设置像素的方式也能做,但性能就会相差很多了。更别说其它高级的效果了。


原文转载:http://www.shaoqun.com/a/477515.html

zen cart:https://www.ikjzd.com/w/1282
parenthood:https://www.ikjzd.com/w/2497
如何安全高效管理多个Facebook、Google、亚马逊账号?:https://www.ikjzd.com/home/126575
做跨境电商,市场分析你会吗?:https://www.ikjzd.com/home/95820
亚马逊工具性价比之王(一)运营专家overgrowth:https://www.ikjzd.com/home/2785

SkiaSharp是跨平台图形库skia的.net封装。在skia的m81版本中,SkRuntimeEffect变成了一个公开的API。而SkRuntimeEffect有什么用呢,根据说明,可以使用Skia专门的着色器语言来编写着色器。而着色器这个相对来说还是挺好理解的,就是给一个面添加颜色。目前最新版本的SkiaSharp还是基于m80版本进行的封装。我们需要用到预览版的SkiaSharp才行,
欧舒丹:https://www.ikjzd.com/w/1756
张洁:https://www.ikjzd.com/w/1663
运营干货:速卖通直播怎么推广引流?做好这三点很重要!:https://www.ikjzd.com/home/15958
别瞎折腾!旺季海外仓运营与风控干货一键get!:https://www.ikjzd.com/home/109546
跨境电商如何规避侵权?你可以这样做:https://www.ikjzd.com/home/20119

No comments:

Post a Comment