webgl 渲染带透明通道的视频(threeJS)

首先,你需要一个这样的视频

 

或者一个这样的视频

尽量使得视频尺寸宽高比为1:2或者2:1,这样渲染出来的视频就是1:1大小了。然后用webgl将视频渲染在画布上,渲染的同时将视频上下,或者左右进行叠加计算。

 webgl渲染可以用three.js,上下叠加的代码如下:

复制代码
import * as THREE from 'three';
    let videoWidth = 540; //视频实际的宽度
    let videoHeight = 540;//原视频实际的高度的一般
    //定义渲染器
    var renderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setClearColor(new THREE.Color("lightgrey"), 0);
    renderer.setSize(videoWidth, videoHeight);

    //居中显示
    // renderer.domElement.style.position = "absolute"; 

    renderer.domElement.style.top = (window.innerHeight - videoWidth) / 2 + "px";
    renderer.domElement.style.left = (window.innerWidth - videoWidth) / 2 + "px";
    // renderer.domElement.style.backgroundColor = "#999";
    // canvas的背景图
    // renderer.domElement.style.backgroundImage = "url('./images/6b4b2ec4_E812211_16ce1ab6.jpg')";

    document.body.appendChild(renderer.domElement);
    var scene = new THREE.Scene();
    var camera = new THREE.Camera();
    scene.add(camera);
    //播放视频
    var video = document.getElementById("video");
    video.onended = () => {
      video.play();

    }
    //获取视频纹理
    var texture = new THREE.VideoTexture(video);
    texture.minFilter = THREE.LinearFilter;
    texture.magFilter = THREE.LinearFilter;
    texture.format = THREE.RGBAFormat;

    //定义几何体
    var geometry = new THREE.PlaneBufferGeometry(2, 2);

    //处理视频纹理
    var uniforms = {
      time: { type: "f", value: 1.0 },
      videoTexture: { 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 videoTexture;
    varying vec2 vUv;
    
    void main( void ) {
      gl_FragColor = vec4(
      texture2D(videoTexture, vec2(vUv.x, 0.5 + vUv.y/2.)).rgb,
      texture2D(videoTexture, vec2(vUv.x, vUv.y/2.)).r
      );
    }`,

      // 通过视频的rgb值,转换成webGl渲染需要的rgba值
      // vec4是取样器获取的是值对应的是(r,g,b,a)
      // texture2D是取样器获取的是视频的rgb值,可以通过.r,.g,.b或者.rg,.rb,.gb,.rgb分别取样
      // vUv传入的是纹理的坐标(浮点数)

      transparent: true
    });
    var mesh = new THREE.Mesh(geometry, material)
    scene.add(mesh);


    var animate = function () {
      requestAnimationFrame(animate);
      renderer.render(scene, camera);
    };

    // document.getElementById('play-button').addEventListener('click', e => {
    //   video.play();
    //   requestAnimationFrame(animate);
    // });
    video.play();
    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
      );
    }`,
复制代码

以上解决视频背景透明问题 

参考原文:前端如何制作出透明背景视频

posted @   webHYT  阅读(1188)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示