微信小程序开发02:原始人也能看懂的着色器与视频处理
往期回顾:
1、背景
还记得01时,3.3.3章节的成果展示吗?
![]()
虽然图片识别成功了,并且视频加载完毕了
但是视频存在大规模的绿色背景,这是业务不期望展示的
期望的效果是抠除绿色背景,仅保留人物主体,如下图:
![]()
今天我们就来尝试对视频图层做调整
2、温故知新
为了快速实现MVP,我们忽略了很多信息,但这些信息对我们基于MVP二次开发时,比较重要
我们需要了解一下当前demo工程的结构:
![]()
清晰的分层架构 :
-
Pages 层 (如 xr-template-water/index.wxml ):
- 负责页面配置和展示
- 定义标题、介绍等元数据
- 处理页面级别的交互
-
Components 层 (如 xr-template-water/index.wxml ):
- 包含实际的 XR 场景逻辑
- 处理 3D 渲染、AR 追踪等核心功能
- 实现具体的业务逻辑
-
共享行为机制 share-behavior.js 的设计 :
- 提供统一的分享功能实现
- 统一处理 AR 追踪状态初始化
- 减少重复代码,提高一致性
- 被所有 template 组件复用
再来看看数据流向:
用户交互
│
▼
Pages 层 (页面配置)
│
▼
xr-demo-viewer (容器组件)
│
├─► 显示 UI (标题、介绍、代码)
│
└─► <slot> (主内容)
│
▼
Components/Template (业务组件)
│
├─► share-behavior (共享功能)
│ │
│ ├─► 分享初始化
│ └─► AR 状态管理
│
└─► xr-scene (XR 场景)
│
├─► 资源加载
├─► 3D 渲染
└─► AR 追踪
像我们在第一期做的改造,得益于此demo工程的优秀设计,当我们想要新增功能时,只要做4步操作:
- 创建 pages/template/xr-template-newFeature
- 创建 components/template/xr-template-newFeature
- 使用 xr-demo-viewer 包裹
- 引入 share-behavior 获得共享功能
3、透明视频
ok,接下来我们进入正题,如何让绿幕视频可以扣除绿幕,实现一些付费AR软件提供的功能?
有两条路:
- 直接导入微信小程序支持的透明视频
- 通过自定义着色器计算每个像素颜色与绿色背景的距离,使用 smoothstep 函数根据距离动态调整透明度,使绿色背景变为透明而其他内容保持不透明。
第一条路需要使用AE等视频处理软件,导出成果,对素材的质量要求较高,也就是对上游有依赖
因此,不想被上游依赖,我们便选择第二条路,自己实现视频扣除纯色背景的功能
况且,XR FRAME本就支持着色器
// XR-Frame 提供的 API
wx.getXrFrameSystem().registerEffect("chroma-key", createChromaKeyEffect);
scene.createEffect({
"name": "chroma-key",
"shaders": [vertexShader, fragmentShader] // 支持 GLSL 着色器
})
ok,写到这里,大家应该还是困惑,着色器和视频有什么关系?
着色器就像一个超级快的修图师,把视频的每一帧图片都检查一遍,把绿色的像素变成透明,然后把处理好的图片贴在3D模型这块"布料"上,纹理材质就是这块布料和修图师的组合
大白话说完,我们来看看处理的过程
我们创建一个新的资源,让它被包裹在xr-assets下,这个新的资源就是我们刚刚提到的“修图师”,它在小程序里的体现就是“材质”,即xr-asset-material
<xr-assets>
<xr-asset-load type="video-texture" asset-id="ayuan-video" src="https:/xxxx.mp4" options="autoPlay:true,loop:true" />
<xr-asset-material asset-id="chroma-key-mat" effect="chroma-key" />
<xr-assets>
asset-id我们很熟悉了,对应于材质的名字,就和视频的asset-id一样
effect是效果,即材质的模板
通过对effect的设置,我们可以调整光照模式,等等
![]()
"chroma-key"是我们通过scene.createEffect方法创造出来的一种自定义效果
部分源码如下:
function createChromaKeyEffect(scene) {
return scene.createEffect({
"name": "chroma-key", // 给这个修图师起个名字叫"绿幕扣除"
// 定义要用的工具:视频图片
"images": [{
"key": "u_baseColorMap", // 视频纹理的代号
"default": "white",
"macro": "WX_USE_BASECOLORMAP"
}],
// 定义修图规则(着色器代码)
"shaders": [
// 第一个着色器:负责把3D模型放到屏幕上
`顶点着色器...`,
// 第二个着色器:负责给每个像素上色(这里是关键!)
`片元着色器...
vec4 color = texture2D(u_baseColorMap, vTextureCoord); // 取出视频的像素颜色
vec3 greenKey = vec3(0.055, 0.816, 0.294); // 绿幕的颜色
float dist = distance(color.rgb, greenKey); // 算一下这个像素离绿色有多远
float threshold = 0.40; // 设定一个距离标准
float alpha = smoothstep(threshold - 0.005, threshold + 0.005, dist);
// 如果离绿色很近,透明度就变成0(看不见)
// 如果离绿色很远,透明度就保持1(看得见)
color.a *= alpha; // 把算好的透明度应用到像素上
`
]
})
}
写完之后,别忘了在系统中注册,这样之后到处都可以使用
// 在组件加载时执行
lifetimes: {
async attached() {
const xrFrameSystem = wx.getXrFrameSystem();
// 把这个修图师注册到系统里,以后可以随时用
xrFrameSystem.registerEffect("chroma-key", createChromaKeyEffect);
}
}
然后我们就要把之前的视频,和我们刚刚创建的材质,组合起来
- 创建一个3D平面模型
- 给这个模型穿上"chroma-key-mat"这件衣服
- 把视频"ayuan-video"贴在衣服上
- 把模型放到场景里
handleARReady: async function ({ detail }) {
// 创建一个3D平面(就像一块板子)
const videoPlane = this.scene.createElement(xr.XRMesh, {
geometry: 'plane', // 形状:平面
material: 'chroma-key-mat', // 材质:用刚才创建的“布料”
uniforms: 'u_baseColorMap: video-ayuan-video', // 把视频贴在布料上
position: '0 0.5 0', // 位置
scale: '0.8 0.45 1', // 大小
});
// 把这个平面添加到场景中
lockItemEle.addChild(videoPlane);
}
一句话总结 :代码先创建了一个"绿幕扣除"的修图方案,然后创建一块用这个方案的布料,最后把视频贴在这块布料上,视频的每一帧都会自动被修图师处理,绿色背景就变透明了!
![]()
附录
架构图
![]()