近期項目需求做一個透明背景的視頻疊加攝像頭的交互,於是去了解了一下透明背景視頻的實現方法。
1、webm視頻格式
首先想到的當然是先跟動畫大哥交流能否製作出透明背景的視頻,給出的答案是webm格式的視頻是可以背景透明的,OK,拿到視頻,放到項目中,chorme打開,完美播放,這也太簡單了吧,但移動端是不會同意讓你這麼輕易就播放視頻的,Safari,微信,都不支持,沒辦法,只能繼續尋找方案。
2、CSS 樣式去掉背景
利用css樣式 mix-blend-mode 混合模式,有一個屬性 screen 就是黑色和其它元素進行混合的時候表現爲透明。但這種方法有一種情況沒法解決,就是如果視頻中有元素是半透明的就無法成功了。
有關這種方法詳細描述可以參考鏈接:如何讓MP4 video視頻背景色變成透明?
3、webgl 渲染帶透明通道的視頻
首先,你需要一個這樣的視頻
或者一個這樣的視頻
儘量使得視頻尺寸寬高比爲1:2或者2:1,這樣渲染出來的視頻就是1:1大小了。然後用webgl將視頻渲染在畫布上,渲染的同時將視頻上下,或者左右進行疊加計算。
webgl渲染可以用three.js,上下疊加的代碼如下:
let videoWidth=1080; //視頻實際的寬度
//定義渲染器
var renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(new THREE.Color("lightgrey"), 0);
renderer.setSize(videoWidth, videoWidth);
//居中顯示
renderer.domElement.style.position = "absolute";
renderer.domElement.style.top = (window.innerHeight - videoWidth) / 2 + "px";
renderer.domElement.style.left = (window.innerWidth - videoWidth) / 2 + "px";
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.Camera();
scene.add(camera);
//播放視頻
var video = document.getElementById("video");
video.play();
//獲取視頻紋理
var texture = new THREE.VideoTexture(video);
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
//定義幾何體
var geometry = new THREE.PlaneBufferGeometry(1, 1);
//處理視頻紋理
var uniforms = {
time: { type: "f", value: 1.0 },
texture: { type: "sampler2D", value: texture }
};
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader:
`varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader:
`#ifdef GL_ES
precision highp float;
#endif
uniform float time;
uniform sampler2D texture;
varying vec2 vUv;
void main( void ) {
gl_FragColor = vec4(
texture2D(texture, vec2(vUv.x, 0.5 + vUv.y/2.)).rgb,
texture2D(texture, vec2(vUv.x, vUv.y/2.)).r
);
}`,
transparent: true
});
var mesh = new THREE.Mesh(geometry, material)
scene.add(mesh);
var animate = function() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
requestAnimationFrame(animate);
如果是左右,只需要改一下疊加的方向就行,代碼中的 fragmentShader 屬性改爲如下:
fragmentShader:
`#ifdef GL_ES
precision highp float;
#endif
uniform float time;
uniform sampler2D texture;
varying vec2 vUv;
void main( void ) {
gl_FragColor = vec4(
texture2D(texture, vec2(vUv.x/2., vUv.y)).rgb,
texture2D(texture, vec2(vUv.x/2., vUv.y)).r
);
}`,
以上,完美解決視頻背景透明問題。
本文結。