threejs将视频作为纹理贴图以及视频纹理贴图无效的问题

视频本质上就是一帧帧图片流构成,把视频作为 Threejs 模型的纹理贴图使用,就是从视频中提取一帧一帧的图片作为模型的纹理贴图,然后不停的更新的纹理贴图就可以产生视频播放的效果。

首先我们需要准备一个视频,比如:https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm

网上很多资料说,可以这样做,不过经我实际测试,它并不能自动播放,只是冻结在第一帧:

//创建video对象(很多资料说,不需要插入到DOM中)
let video = document.createElement('video');
video.src = "./flower.webm"; // 设置视频地址
video.autoplay = "autoplay"; //要设置播放
video.loop = "loop";  //循环播放

//视频当作贴图
var texture = new THREE.VideoTexture(video);  

// 创建立方体
const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshPhongMaterial({
 map: texture // 设置颜色贴图
});

// 使用形状和材质创建一个网格物体
const cube = new THREE.Mesh(geometry, material);
scene.add(cube)


经实际测试,下面这种方式可以:

  1. 首先在DOM中创建一个video标签,设置好各种属性,注意设置静音(chrome在用户没有交互的情况下,不允许有音频播放)。

    <video id="video" loop crossOrigin="anonymous" muted webkit-playsinline style="display:none">
     <source src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm">
    </video>
  2. 实例化 THREE.VideoTexture() 获得贴图对象

    // 获取video对象
    const video = document.getElementById('video');
    // 设置视频播放
    video.play();
    // 获取视频贴图对象
    const texture = new THREE.VideoTexture(video);
  3. 设置材质的map属性

    // 创建立方体
    const geometry = new THREE.BoxGeometry(2, 2, 2);
    const material = new THREE.MeshPhongMaterial({
     map: texture // 设置颜色贴图
    });

    // 使用形状和材质创建一个网格物体
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube)
  4. 注意设置更新动画

    function animate() {
     // 更新视频贴图
     renderer.render(scene, camera);
     requestAnimationFrame(animate);
    }
    animate();


完整点的代码:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
</head>
<body>
   <!-- 1.添加视频 -->
   <video id="video" loop crossOrigin="anonymous" muted webkit-playsinline style="display:none">
       <source src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm">
   </video>
   <script type="importmap">
       {
           "imports": {
               "three": "./three.module.js",
               "three/addons/": "./jsm/"
           }
       }
   </script>
   <script type="module">
       import * as THREE from 'three';
       import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
       // 创建场景
       const scene = new THREE.Scene();
       scene.background = new THREE.Color(0xffffff);

       // 2.1 获取video对象
       const video = document.getElementById('video');
       video.play();
       // 2.2 获取视频贴图对象
       const texture = new THREE.VideoTexture(video);

       // 创建立方体
       const geometry = new THREE.BoxGeometry(2, 2, 2);
       const material = new THREE.MeshPhongMaterial({
           map: texture // 3.设置颜色贴图
       });

       // 使用形状和材质创建一个网格物体
       const cube = new THREE.Mesh(geometry, material);
       scene.add(cube)

       // 创建环境光
       const light1 = new THREE.AmbientLight(0xffffff);
       // 添加到场景中
       scene.add(light1)

       // 创建光
       const light = new THREE.PointLight(0xffffff, 1, 0, 0);
       light.position.set(10, 10, 10)
       scene.add(light)

       // 创建相机
       let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
       camera.position.set(10, 10, 10)
       camera.lookAt(0, 0, 0)

       // 创建 三维坐标轴
       const axesHelper = new THREE.AxesHelper(10);
       // 将坐标轴加入到场景中
       scene.add(axesHelper);


       // 创建渲染对象
       const renderer = new THREE.WebGLRenderer({
           // 开启抗锯齿
           antialias: true
       });
       renderer.setSize(window.innerWidth, window.innerHeight);
       // 执行渲染
       renderer.render(scene, camera);
       document.body.appendChild(renderer.domElement);

       // 创建轨道控制器对象
       const controls = new OrbitControls(camera, renderer.domElement)
       controls.addEventListener('change', function () {
           // 重新执行渲染操作
           renderer.render(scene, camera);
       })

       function animate() {
           // 4. 更新视频贴图
           renderer.render(scene, camera);
           requestAnimationFrame(animate);
       }
       animate();
   </script>
</body>
</html>

如果需要有声音播放,可以设置个用户交互。


微信 遇到疑问可加微信进行反映