如何在AR.js中为基于位置放置的两个物体绘制连线?
解决方案:在AR.js中连接两个位置放置的物体
AR.js基于Three.js(通常搭配A-Frame框架),因此可以直接利用Three.js的线条渲染API实现两个AR物体间的连线,核心思路是实时获取两个物体的世界坐标,更新线条的顶点位置。
核心实现步骤
- 获取两个AR物体对应的Three.js
Object3D实例(A-Frame中每个实体的object3D属性就是对应的Three.js对象) - 创建线条几何体,以两个物体的世界坐标作为顶点
- 配置线条材质(颜色、宽度、样式等)
- 将线条添加到AR场景中,并实时更新顶点位置以跟随物体移动
方式1:原生Three.js + A-Frame 直接实现
假设你有两个标记物(marker)对应的物体:
<a-scene arjs> <a-marker preset="hiro" id="marker1"> <a-box position="0 0.5 0" color="#4CC3D9"></a-box> </a-marker> <a-marker preset="kanji" id="marker2"> <a-sphere position="0 0.5 0" color="#EF2D5E"></a-sphere> </a-marker> </a-scene>
添加JavaScript代码实现连线:
// 获取两个AR物体的Object3D const object1 = document.querySelector('#marker1').object3D; const object2 = document.querySelector('#marker2').object3D; // 创建线条几何体(初始顶点为原点,后续实时更新) const lineGeometry = new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(), new THREE.Vector3() ]); // 创建线条材质(可自定义颜色、线宽等) const lineMaterial = new THREE.LineBasicMaterial({ color: 0xFFFF00, linewidth: 2, transparent: true, opacity: 0.8 }); // 创建线条对象并添加到场景 const line = new THREE.Line(lineGeometry, lineMaterial); document.querySelector('a-scene').object3D.add(line); // 实时更新线条顶点位置 function updateLine() { // 获取物体的世界坐标并更新线条顶点 object1.getWorldPosition(lineGeometry.attributes.position.array); object2.getWorldPosition(lineGeometry.attributes.position.array.slice(3)); // 标记几何体属性需要更新 lineGeometry.attributes.position.needsUpdate = true; requestAnimationFrame(updateLine); } updateLine();
方式2:封装为A-Frame自定义组件(更优雅)
将连线逻辑封装成可复用的A-Frame组件,方便在场景中直接调用:
AFRAME.registerComponent('connect-objects', { // 定义组件参数:需要连接的两个目标物体选择器 schema: { target1: { type: 'selector' }, target2: { type: 'selector' }, color: { type: 'color', default: '#FF0000' }, linewidth: { type: 'number', default: 2 } }, init() { const { target1, target2, color, linewidth } = this.data; if (!target1 || !target2) return; // 初始化线条几何体和材质 this.lineGeometry = new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(), new THREE.Vector3() ]); this.lineMaterial = new THREE.LineBasicMaterial({ color, linewidth, transparent: true, opacity: 0.7 }); this.line = new THREE.Line(this.lineGeometry, this.lineMaterial); // 将线条添加到当前实体的Object3D中 this.el.object3D.add(this.line); }, // A-Frame的tick函数会在每一帧执行,用于实时更新线条 tick() { const { target1, target2 } = this.data; if (!target1 || !target2) return; // 更新线条顶点为两个物体的世界坐标 target1.object3D.getWorldPosition(this.lineGeometry.attributes.position.array); target2.object3D.getWorldPosition(this.lineGeometry.attributes.position.array.slice(3)); this.lineGeometry.attributes.position.needsUpdate = true; } });
使用组件:
<a-scene arjs> <a-marker preset="hiro" id="marker1"> <a-box position="0 0.5 0" color="#4CC3D9"></a-box> </a-marker> <a-marker preset="kanji" id="marker2"> <a-sphere position="0 0.5 0" color="#EF2D5E"></a-sphere> </a-marker> <!-- 使用自定义组件连接两个物体 --> <a-entity connect-objects="target1: #marker1; target2: #marker2; color: #00FF00; linewidth: 3"></a-entity> </a-scene>
额外优化点
- 如果需要虚线效果,将
LineBasicMaterial替换为LineDashedMaterial,并在初始化后调用lineGeometry.computeLineDistances() - 若物体存在嵌套结构,确保获取的是最外层的
Object3D实例(避免坐标计算错误) - 可以添加条件判断,当其中一个物体不可见时隐藏线条
内容的提问来源于stack exchange,提问作者Sahil V N
相关产品推荐
相关产品推荐

