如何在Forge Viewer中实现绑定模型的闪烁标记?
解决模型查看器中标记随相机视角偏移的问题
当前实现的核心问题是:闪烁标记作为独立2D DOM元素存在,未与模型的3D空间位置绑定。相机视角变化时,模型的屏幕投影坐标更新,但标记位置未同步,导致偏移。要解决这个问题,必须让标记跟随模型上的目标3D点,同步其屏幕投影位置。
方案一:使用模型查看器内置标注功能(推荐)
如果使用Google的<model-viewer>组件,它内置的标注系统可以自动将标记绑定到模型3D坐标,无需手动处理视角同步。
实现步骤
- 在
<model-viewer>内部添加<annotation>元素,通过position属性指定模型上目标点的3D坐标(格式为X Y Z)。 - 将原有的SVG闪烁标记作为
<annotation>的内容,保留动画逻辑。
代码示例
<!-- 基础模型查看器结构 --> <model-viewer id="myModelViewer" src="your-model.glb" camera-controls></model-viewer> <script> const randomId = "your-unique-id"; // 创建标注元素 const annotation = document.createElement('annotation'); annotation.setAttribute('position', '0 1.5 0'); // 替换为模型目标点的3D坐标 annotation.setAttribute('id', `mymk${randomId}`); // 创建SVG容器 const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute('id', `mysvg${randomId}`); svg.style.width = '50px'; annotation.appendChild(svg); // 复用原有的Snap.svg动画逻辑 const size = 300; const s = Snap(svg); s.attr({viewBox: `0 0 ${size} ${size}`}); const userPath = s.path("M500,10C229.4,10,10,229.4,10,500c0,270.6,219.4,490,490,490c270.6,0,490-219.4,490-490S770.6,10,500,10z M496.2,255c70,0,126.7,56.7,126.7,126.7s-56.7,126.7-126.7,126.7s-126.7-56.7-126.7-126.7C369.5,311.7,426.3,255,496.2,255z M629.1,745h-266c-25.8,0-78.2-21.1-78.2-46.8v0c0-85.8,70.4-156,156.4-156h109.5c86,0,156.4,70.2,156.4,156C707.4,723.9,654.9,745,629.1,745z") .attr({fill: "#029e02"}); const userBox = userPath.getBBox(); const circleBg = s.circle(userBox.cx, userBox.cy, userBox.width / 2) .attr({fill: "#029e02", stroke: "#029e02", strokeWidth: 800}); const user = s.group(circleBg, userPath); const userScaleFactor = 0.09; const userMtx = new Snap.Matrix(); userMtx.translate(size/2 - userBox.width*userScaleFactor / 2, size/2 - userBox.height*userScaleFactor/2); userMtx.scale(userScaleFactor); user.attr({transform: userMtx, cursor: "pointer"}); const smallUserMtx = userMtx.clone().scale(0.9, 0.9, userBox.cx, userBox.cy); setInterval(blink, 3000); function blink(){ user.animate({transform: smallUserMtx}, 200, mina.easein, () => user.animate({transform: userMtx}, 200)); const newCircle = s.circle(size/2, size/2, 40); user.before(newCircle); newCircle.attr({fill: "rgb(244, 203, 217)", strokeWidth: "20", stroke: "#015401"}); newCircle.animate({r: size/2, opacity: 0}, 2000, mina.easeout, () => newCircle.remove()); }; user.attr({ pointerEvents: "auto", cursor: "pointer" }); // 将标注添加到模型查看器 document.getElementById('myModelViewer').appendChild(annotation); </script>
方案二:手动跟踪3D点投影(自定义模型查看器)
如果使用自定义模型查看器(如基于Three.js的实现),需要手动将模型3D坐标转换为屏幕坐标,并实时更新标记位置。
实现步骤
- 获取模型目标点的局部3D坐标(可通过Blender等编辑器导出顶点坐标)。
- 监听相机视角变化事件,在回调中完成3D坐标到屏幕坐标的转换。
- 更新SVG标记的位置,使其与目标点的屏幕坐标对齐。
代码示例(基于Three.js)
// 假设已初始化scene、camera、model对象 const targetPoint = new THREE.Vector3(0, 0, 0); // 模型目标点的局部坐标 const svgElement = $(`#mysvg${randomId}`); function updateMarkerPosition() { // 将局部坐标转换为世界坐标 const worldPoint = targetPoint.clone().applyMatrix4(model.matrixWorld); // 将世界坐标转换为屏幕坐标 const screenPoint = worldPoint.clone().project(camera); // 转换为DOM像素坐标 const x = (screenPoint.x + 1) * window.innerWidth / 2; const y = (-screenPoint.y + 1) * window.innerHeight / 2; // 调整偏移量,让SVG中心对准目标点 svgElement.css({ position: 'absolute', left: `${x - 25}px`, // SVG宽度50px,减去一半实现中心对齐 top: `${y - 25}px` }); } // 绑定相机变化事件 document.getElementById('your-model-viewer').addEventListener('camera-change', updateMarkerPosition); // 或在渲染循环中持续更新 function renderLoop() { requestAnimationFrame(renderLoop); updateMarkerPosition(); // 其他渲染逻辑 } renderLoop();
内容的提问来源于stack exchange,提问作者sercanduyar
相关产品推荐
相关产品推荐

