searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

webgl 实现透明视频动画

2024-06-07 09:49:58
14
0

目前动画效果越来越酷炫,动画的绘制难度也逐渐增大,本文描述透明视频,动画的另一种方案,本文通过 webgl 来实现透明动画视频。

需求是啥?

比如我们出要实现一个动画效果,要怎么实现呢?

这里我们的核心目标是动画的背景可替换,比如说,这里的视频可以有背景色,像以下的图。

目前是不是想到了各种 lottie 动画库,或直接用一个 gif 动画来代替?

接下来我们先对方案进行对比。

这里我们的直接目的是实现一个透明背景的动画,目前有几种方案,包括 gif、png 或者对视频进行转换来实现

方案对比

gif

  • 优势:工作量小

  • 劣势:体积大

css 属性 mix-blend-mode: screen;

  • 优势:工作量小、体积小

  • 劣势:只适用于黑色背景视频

webm 透明视频

  • 优势:原生支持

  • 劣势:兼容性差

canvas 绘制视频

  • 优势:动画效果好

  • 劣势:CPU 占用高

webgl 绘制视频

  • 优势:动画效果好,CPU 占用小

  • 劣势:学习成本

选用 webgl 的话,目前已经有很多很成熟且大型的库可供使用比如 pixijs lottie,这些库动画效果酷炫,体积偏大,比如 pixijs 的 cdn 版本有 80k,lottie 中的 lottie-web 文件就更大了,gzip 压缩之后还有 92k。

方案落实

我们想下这里用 webgl 如何进行绘制,怎么能从一个视频中抠出其中的非背景色部分?难道要使用到抠图技术了吗?目前感觉有点难度,并且细节之处还担心有可能有残留阴影。那么,怎么办呢?

我们把问题一步一步转化。

接下来,我们的问题就是如何把图片的背景变成透明

问题再次拆分

  • 如何确认哪块属于背景

  • 如何设置背景透明度

首先我们解答第一个问题,左边是遮罩,这样我们就能知道哪块区域是背景区域,

其次,设置背景透明度,即叠加两者颜色后,对 rgba 中的 alpha 进行处理即可。

我们核心的 webgl 算法已经实现

 // 片元着色器, gl_FragColor 即为每像素的颜色
const vShader = `
precison lowp float;
varying vec2 v_texcoord;
uniform sample2D u_sample;
void main(void) {
gl_FragColor = vec4(texture2D(u_sampler, v_texcoord).rgb, texture2D(u_sampler, v_texcoord+vec(-0.5, 0)).r);
}
`;

回归问题,目前来看,我们的问题 如何将图片的背景设置为透明 已经解决了,那么,如何将视频的背景设置为透明呢?抽象来看,视频就是一帧一帧的图片,因此,通过 requestFrame 把一帧一帧的带有遮罩和真实图片进行混合处理,就可以达到我们想要的效果了。

按着这个思路,我们就可以开始进行处理了

我们看看 效果 (如果没反应,点一下屏幕)

我们看一下,这里会出现图像模糊的效果,我们开始思考,这个是不是 webgl 的问题?是不是 webgl 绘制才有这种问题?其他的绘制方式会不会有同样的问题?

我们首先需要确认是不是只有 webgl 才有这个问题,与 webgl 相对的是 canvas。

因此,我们写一个 canvas 来看看。发现 canvas 有同样的问题。

因此,排除 webgl 本身的问题。

绘制方面出现问题的话,我们可以考虑到,是不是分辨率和设备像素比导致的问题,在网上搜了一下,果然是这个原因 解决 canvas 在高清屏中绘制模糊的问题,不过文中的提到 backingStorePixelRatio 这个属性我在 webgl 和 canvas 上下文中都试了几下,都没有获取到值,因此把这个当作是 1 来进行处理。

到此,我们通过设置 webgl 绘制的设备像素比,进行缩放行为,看看能否消除该不良效果

 ...
this.radio = window.devicePixelRatio;
...
...
gl.viewport(
0,
0,
this.options.width * this.radio,
this.options.height * this.radio
);
...

0条评论
作者已关闭评论
裘****熙
1文章数
0粉丝数
裘****熙
1 文章 | 0 粉丝
裘****熙
1文章数
0粉丝数
裘****熙
1 文章 | 0 粉丝
原创

webgl 实现透明视频动画

2024-06-07 09:49:58
14
0

目前动画效果越来越酷炫,动画的绘制难度也逐渐增大,本文描述透明视频,动画的另一种方案,本文通过 webgl 来实现透明动画视频。

需求是啥?

比如我们出要实现一个动画效果,要怎么实现呢?

这里我们的核心目标是动画的背景可替换,比如说,这里的视频可以有背景色,像以下的图。

目前是不是想到了各种 lottie 动画库,或直接用一个 gif 动画来代替?

接下来我们先对方案进行对比。

这里我们的直接目的是实现一个透明背景的动画,目前有几种方案,包括 gif、png 或者对视频进行转换来实现

方案对比

gif

  • 优势:工作量小

  • 劣势:体积大

css 属性 mix-blend-mode: screen;

  • 优势:工作量小、体积小

  • 劣势:只适用于黑色背景视频

webm 透明视频

  • 优势:原生支持

  • 劣势:兼容性差

canvas 绘制视频

  • 优势:动画效果好

  • 劣势:CPU 占用高

webgl 绘制视频

  • 优势:动画效果好,CPU 占用小

  • 劣势:学习成本

选用 webgl 的话,目前已经有很多很成熟且大型的库可供使用比如 pixijs lottie,这些库动画效果酷炫,体积偏大,比如 pixijs 的 cdn 版本有 80k,lottie 中的 lottie-web 文件就更大了,gzip 压缩之后还有 92k。

方案落实

我们想下这里用 webgl 如何进行绘制,怎么能从一个视频中抠出其中的非背景色部分?难道要使用到抠图技术了吗?目前感觉有点难度,并且细节之处还担心有可能有残留阴影。那么,怎么办呢?

我们把问题一步一步转化。

接下来,我们的问题就是如何把图片的背景变成透明

问题再次拆分

  • 如何确认哪块属于背景

  • 如何设置背景透明度

首先我们解答第一个问题,左边是遮罩,这样我们就能知道哪块区域是背景区域,

其次,设置背景透明度,即叠加两者颜色后,对 rgba 中的 alpha 进行处理即可。

我们核心的 webgl 算法已经实现

 // 片元着色器, gl_FragColor 即为每像素的颜色
const vShader = `
precison lowp float;
varying vec2 v_texcoord;
uniform sample2D u_sample;
void main(void) {
gl_FragColor = vec4(texture2D(u_sampler, v_texcoord).rgb, texture2D(u_sampler, v_texcoord+vec(-0.5, 0)).r);
}
`;

回归问题,目前来看,我们的问题 如何将图片的背景设置为透明 已经解决了,那么,如何将视频的背景设置为透明呢?抽象来看,视频就是一帧一帧的图片,因此,通过 requestFrame 把一帧一帧的带有遮罩和真实图片进行混合处理,就可以达到我们想要的效果了。

按着这个思路,我们就可以开始进行处理了

我们看看 效果 (如果没反应,点一下屏幕)

我们看一下,这里会出现图像模糊的效果,我们开始思考,这个是不是 webgl 的问题?是不是 webgl 绘制才有这种问题?其他的绘制方式会不会有同样的问题?

我们首先需要确认是不是只有 webgl 才有这个问题,与 webgl 相对的是 canvas。

因此,我们写一个 canvas 来看看。发现 canvas 有同样的问题。

因此,排除 webgl 本身的问题。

绘制方面出现问题的话,我们可以考虑到,是不是分辨率和设备像素比导致的问题,在网上搜了一下,果然是这个原因 解决 canvas 在高清屏中绘制模糊的问题,不过文中的提到 backingStorePixelRatio 这个属性我在 webgl 和 canvas 上下文中都试了几下,都没有获取到值,因此把这个当作是 1 来进行处理。

到此,我们通过设置 webgl 绘制的设备像素比,进行缩放行为,看看能否消除该不良效果

 ...
this.radio = window.devicePixelRatio;
...
...
gl.viewport(
0,
0,
this.options.width * this.radio,
this.options.height * this.radio
);
...

文章来自个人专栏
前端图像开发
1 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0