javascript播放带透明通道的mp4动画

  • 2020 年 11 月 12 日
  • 笔记

    随着互联网的发展,动画效果也在一直更新,从刚开始的flsh动画,cocos骨骼动画,到YY开源的svga动画。最近1年来,带有透明通道的mp4动画被使用的极为广泛,对于app端。github上有开源的AlphaPlayer可以使用,但是对于web端,相关的资料很少。为了解决这个问题想了很多办法,提出了使用webm格式。但是最终还是要实现播放mp4格式。

    播放mp4格式的透明动画,需要什么呢。首先,对于web前端来说,webgl应该大家都很少介绍到,更不要说着色器了(shader)和OpenGL ES的语法了。放弃了好几次,最后看到一个帖子,可以用THREEJS来进行。先上一个图

    

 

   可以看到素材中左边部分使用RGB通道存储了原透明视频的Alpha值,右边部分使用RGB通道存储了原透明视频的RGB值,然后在端上通过OpenGL重新将每个像素点的Alpha值和RGB值进行组合,重新得到ARGB视频画面,实现透明视频的动画效果。

  在web端,具体实现。

  1.有个video播放器,播放mp4动画

  2.使用threejs和openel把画面重绘到一个容器里。

  

 1 var lastUpdate;
 2 var container;
 3 var camera, scene, renderer;
 4 var uniforms;
 5 
 6 function init() {
 7 
 8   container = document.getElementById('container');
 9   camera = new THREE.Camera();
10   camera.position.z = 1;
11   scene = new THREE.Scene();
12 
13   var video = document.getElementById('video');
14   video.src = "//devimage.91banban.com/topcard.mp4";
15   video.play();
16   video.onended = () => {
17     video.play();
18   }
19   videoTexture = new THREE.VideoTexture(video);
20   videoTexture.minFilter = THREE.LinearFilter;
21   videoTexture.magFilter = THREE.LinearFilter;
22   videoTexture.format = THREE.RGBAFormat;
23 
24   // shader stuff
25   uniforms = {
26     time: { type: "f", value: 1.0 },
27     texture: { type: "sampler2D", value: videoTexture }
28   };
29   var material = new THREE.ShaderMaterial({
30     uniforms: uniforms,
31     vertexShader: `varying vec2 vUv;
32           void main() {
33             vUv = uv;
34             gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
35           }`,
36     fragmentShader: `#ifdef GL_ES
37           precision highp float;
38           #endif
39 
40           uniform float time;
41           uniform sampler2D texture;
42           varying vec2 vUv;
43 
44           void main( void ) {
45             gl_FragColor = vec4(
46             texture2D(texture, vec2(0.5+vUv.x/2., vUv.y)).rgb,
47             texture2D(texture, vec2(vUv.x/2., vUv.y)).r
48             );
49           }`,
50     transparent: true
51   });
52   lastUpdate = new Date().getTime();
53   var geometry = new THREE.PlaneBufferGeometry(2, 2);
54   var mesh = new THREE.Mesh(geometry, material);
55   mesh.scale.setScalar(0.8);
56   scene.add(mesh);
57   renderer = new THREE.WebGLRenderer({ alpha: true });
58   renderer.setPixelRatio(window.devicePixelRatio / 1);
59 
60   container.appendChild(renderer.domElement);
61 
62   document.getElementById('play-button').addEventListener('click', e => { video.play(); });
63   renderer.setSize(1000, 1100);
64   this.animate();
65 }
66 
67 function animate() {
68   var currentTime = new Date().getTime()
69   var timeSinceLastUpdate = currentTime - lastUpdate;
70   lastUpdate = currentTime;
71   requestAnimationFrame(animate);
72   render(timeSinceLastUpdate);
73 
74 }
75 function render(timeDelta) {
76   uniforms.time.value += (timeDelta ? timeDelta / 1000 : 0.05);
77   renderer.render(scene, camera);
78 }
79 
80 init();

最终实现的效果图