如何使用Three.js/React在3D对象中添加视频
在GLB模型中嵌入视频的解决方案
要实现类似目标网站的3D模型+视频纹理效果,核心是将视频作为纹理贴到GLB模型的指定表面上,以下是几种可行方案:
方案1:网页端用Three.js实现(最常用)
这是网页场景下的首选方案,直接在前端加载GLB模型并替换纹理为视频:
- 加载GLB模型:借助Three.js的
GLTFLoader加载你的模型文件 - 准备视频纹理:
- 创建HTML5
<video>元素,配置视频源、静音、循环播放等属性(注意浏览器自动播放限制,需要用户交互触发播放,比如点击页面) - 用Three.js的
VideoTexture将视频转为可用于3D模型的纹理
- 创建HTML5
- 替换模型材质:找到模型上需要贴视频的网格(可通过模型对象的
name属性精准定位),把该网格材质的map属性替换为视频纹理,记得设置material.needsUpdate = true让Three.js识别材质变更 - 启动渲染循环:完成场景、相机、渲染器的初始化后,启动动画循环持续渲染
示例代码片段:
import * as THREE from 'three'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; // 基础场景初始化 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 创建视频元素 const video = document.createElement('video'); video.src = 'your-video.mp4'; video.muted = true; video.loop = true; // 绑定点击事件触发播放,规避浏览器自动播放限制 document.body.addEventListener('click', () => video.play()); // 生成视频纹理 const videoTexture = new THREE.VideoTexture(video); videoTexture.wrapS = THREE.ClampToEdgeWrapping; videoTexture.wrapT = THREE.ClampToEdgeWrapping; // 加载并处理GLB模型 const loader = new GLTFLoader(); loader.load('your-model.glb', (gltf) => { // 替换指定网格的纹理,这里假设目标网格名为"video-face" const targetMesh = gltf.scene.getObjectByName('video-face'); if (targetMesh) { targetMesh.material.map = videoTexture; targetMesh.material.needsUpdate = true; } scene.add(gltf.scene); }); // 渲染循环 function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate();
方案2:用Blender预处理模型
如果希望模型本身携带视频材质,可以用Blender先配置好再导出GLB:
- 打开Blender,导入你的GLB模型
- 在着色器编辑器中,添加
Movie Clip节点并导入视频文件,将其颜色输出连接到材质的Base Color输入,调整纹理坐标让视频贴合模型表面 - 导出GLB时注意勾选相关媒体嵌入选项,但网页端使用时仍需配合Three.js等框架加载(浏览器原生不支持直接播放GLB中的视频纹理),这个方案更适合本地渲染场景
方案3:用Babylon.js实现
和Three.js思路类似,借助Babylon.js的视频纹理能力快速实现:
const canvas = document.getElementById('renderCanvas'); const engine = new BABYLON.Engine(canvas, true); const scene = new BABYLON.Scene(engine); // 创建视频纹理 const videoTexture = new BABYLON.VideoTexture("video", "your-video.mp4", scene, true, false); videoTexture.video.muted = true; videoTexture.video.loop = true; document.body.addEventListener('click', () => videoTexture.video.play()); // 加载GLB模型并替换纹理 BABYLON.SceneLoader.LoadAssetContainer("", "your-model.glb", scene, (container) => { const targetMesh = container.meshes.find(mesh => mesh.name === "video-face"); if (targetMesh) { targetMesh.material.albedoTexture = videoTexture; } container.addAllToScene(); }); // 启动渲染 engine.runRenderLoop(() => { scene.render(); });
内容的提问来源于stack exchange,提问作者mathan iyappan




