视频本质上就是一帧帧图片流构成,把视频作为 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)
首先在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>实例化 THREE.VideoTexture() 获得贴图对象
// 获取video对象
const video = document.getElementById('video');
// 设置视频播放
video.play();
// 获取视频贴图对象
const texture = new THREE.VideoTexture(video);设置材质的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)注意设置更新动画
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>
如果需要有声音播放,可以设置个用户交互。