3D眼镜虚拟试戴:模型定位与面部追踪问题求助
修复实时3D眼镜虚拟试戴的位置与跟踪问题
以下是针对代码问题的具体修复建议:
1. 正确赋值glassesModel全局变量
当前代码中glassesModel未被赋值,导致后续无法修改模型位置。修改loadGlassesModel函数:
function loadGlassesModel() { const loader = new GLTFLoader(); loader.load('/static/models/sport_glasses_b307/scene.gltf', (gltf) => { glassesModel = gltf.scene; // 将加载的模型赋值给全局变量 glassesModel.position.set(0, 2, 2); const scaleFactor = 0.04; glassesModel.scale.set(scaleFactor, 0.05, scaleFactor); scene.add(glassesModel); }); }
2. 移除干扰视角的OrbitControls
OrbitControls允许用户拖拽相机,会破坏虚拟试戴的固定视角,删除相关代码:
// 删除以下OrbitControls初始化代码 // const controls = new OrbitControls(camera, renderer.domElement); // controls.enableDamping = true; // controls.dampingFactor = 0.25; // controls.screenSpacePanning = false; // controls.maxPolarAngle = Math.PI / 2; // 修改animate函数,去掉controls.update()调用 function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); }
3. 修正2D坐标到3D空间的转换逻辑
Webcam的2D像素坐标需要转换为Three.js的3D世界坐标,同时适配视频与画布的比例:
- 先定义全局比例变量:
let videoWidth, videoHeight; let scaleFactorX, scaleFactorY;
- 在
startWebcam中初始化比例参数:
async function startWebcam() { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); webcamElement.srcObject = stream; await new Promise((resolve) => { webcamElement.onloadedmetadata = () => { videoWidth = webcamElement.videoWidth; videoHeight = webcamElement.videoHeight; // 根据相机FOV和距离调整比例,示例值需根据实际场景微调 scaleFactorX = 8 / videoWidth; scaleFactorY = -6 / videoHeight; // 负号修正Y轴翻转问题 resolve(); }; }); isVideo = true; await new Promise(resolve => requestAnimationFrame(resolve)); loadGlassesModel(); }
- 更新
drawLandmarks中的模型位置计算:
if (glassesModel) { // 将双眼中心的2D坐标转换为3D空间坐标,以屏幕中心为原点对齐 const x = (averageEyePosition[0] - videoWidth/2) * scaleFactorX; const y = (averageEyePosition[1] - videoHeight/2) * scaleFactorY; glassesModel.position.set(x, y, -5); glassesModel.visible = eyesDetected; }
4. 修复Mediapipe Landmark识别逻辑
当前通过landmark[5]判断眼睛的方式错误,Mediapipe Face Mesh的关键点是固定索引的,直接使用官方定义的眼睛关键点:
// 替换drawLandmarks中的landmark遍历逻辑 for (const landmarkList of landmarksArray) { // 左眼关键点索引:33, 133;右眼关键点索引:362, 263 const leftEye = landmarkList[33]; const rightEye = landmarkList[362]; // 绘制关键点(可选,用于调试) context.beginPath(); context.arc(leftEye.x * videoWidth, leftEye.y * videoHeight, 2, 0, 2 * Math.PI); context.fill(); context.beginPath(); context.arc(rightEye.x * videoWidth, rightEye.y * videoHeight, 2, 0, 2 * Math.PI); context.fill(); // 计算双眼中心坐标 const averageEyePosition = [ (leftEye.x * videoWidth + rightEye.x * videoWidth) / 2, (leftEye.y * videoHeight + rightEye.y * videoHeight) / 2, ]; // 更新眼镜位置 if (glassesModel) { const x = (averageEyePosition[0] - videoWidth/2) * scaleFactorX; const y = (averageEyePosition[1] - videoHeight/2) * scaleFactorY; glassesModel.position.set(x, y, -5); glassesModel.visible = true; eyesDetected = true; } }
5. 优化相机设置适配试戴视角
调整相机参数,让3D模型更贴合真实面部视角:
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); camera.position.set(0, 0, 5); // 相机贴近屏幕,模拟第一人称视角 camera.lookAt(0, 0, 0);
6. 修复模型可见性控制逻辑
当前代码错误地尝试设置loadGlassesModel.visible(函数对象无此属性),直接使用glassesModel.visible即可:
// 删除错误代码:if (loadGlassesModel) { loadGlassesModel.visible = eyesDetected; } // 替换为: if (glassesModel) { glassesModel.visible = eyesDetected; }
内容的提问来源于stack exchange,提问作者Amal Jallouli
相关产品推荐
相关产品推荐

