A-Frame:如何让动态生成实体响应用户位置(移动端)
实现AR文本实体的位置响应交互
需求说明
在iPhone Chrome浏览器中,基于现有AR.js + A-Frame代码,实现以下功能:
- 动态生成的文本实体绑定指定经纬度位置
- 用户走近文本时,文本自动放大;远离时缩小
- 用户可通过相机控制绕文本移动
实现方案与修改代码
核心修改点
- 新增经纬度输入面板,支持手动设置文本实体的GPS位置
- 添加实时距离计算逻辑,根据用户与文本的距离动态调整缩放比例
- 启用相机
look-controls,支持用户绕文本旋转视角 - 开启文本
look-at属性,让文本始终面向用户
完整代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script> <script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script> <script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script> <script src="https://unpkg.com/aframe-text-geometry-component@^0.5.0/dist/aframe-text-geometry-component.min.js"></script> <style> body { margin: 0; padding: 0; } a-scene { width: 100vw; height: 100vh; } .lat-lng-input { position: fixed; top: 20px; left: 20px; z-index: 999; display: flex; gap: 10px; } .lat-lng-input input { padding: 8px; border: 1px solid #ccc; border-radius: 4px; } .lat-lng-input button { padding: 8px 16px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } </style> </head> <body style="margin: 0; overflow: hidden;"> <!-- 经纬度输入面板 --> <div class="lat-lng-input"> <input type="text" id="latitude" placeholder="输入纬度" /> <input type="text" id="longitude" placeholder="输入经度" /> <button onclick="setEntityLocation()">设置位置</button> </div> <a-scene vr-mode-ui="enabled: false" embedded arjs="sourceType: webcam; debugUIEnabled: false;" > <a-assets> <img src="WMNH2OF.jpeg" id="chrome" crossorigin="anonymous" /> <a-asset-item id="helvetikerBoldFont" src="https://rawgit.com/mrdoob/three.js/dev/examples/fonts/helvetiker_bold.typeface.json" ></a-asset-item> </a-assets> <!-- 启用视角控制 + GPS位置追踪 --> <a-camera gps-camera rotation-reader look-controls position="0 1.6 0"></a-camera> </a-scene> <script> let delay = 0; let lyrics = [ "Go shorty", "Go shorty", "Go shorty", "Go shorty", "Go shorty", "Go shorty" ]; // 存储所有生成的文本实体 const textEntities = []; // 默认经纬度 let targetLat = 0; let targetLng = 0; function randomRGB() { let r = Math.floor(Math.random() * 256); let g = Math.floor(Math.random() * 256); let b = Math.floor(Math.random() * 256); return `rgb(${r},${g},${b})`; } function createEntity(transcript) { let sceneEl = document.querySelector("a-scene"); let entityEl2 = document.createElement("a-entity"); // 绑定GPS位置 entityEl2.setAttribute("gps-entity-place", `latitude: ${targetLat}; longitude: ${targetLng}`); entityEl2.setAttribute("scale", "1 1 1"); entityEl2.setAttribute( "text-geometry", `value: ${transcript}; font: #helvetikerBoldFont; bevelEnabled: true; bevelSize: 0.03; bevelThickness: 0.03; curveSegments: 15;` ); entityEl2.setAttribute( "material", `metalness:0.9; roughness: 0.05; sphericalEnvMap: #chrome; color: ${randomRGB()}` ); // 文本始终面向相机 entityEl2.setAttribute("look-at", "[gps-camera]"); // 循环颜色动画 entityEl2.setAttribute( "animation__color", `property: material.color; to: ${randomRGB()}; dur: 2000; easing: linear; loop: true` ); sceneEl.appendChild(entityEl2); textEntities.push(entityEl2); } // 实时更新文本缩放 function updateTextScale() { const cameraEl = document.querySelector("[gps-camera]"); if (!cameraEl.object3D) return; textEntities.forEach(entity => { if (!entity.object3D) return; // 计算相机与文本的距离 const distance = cameraEl.object3D.position.distanceTo(entity.object3D.position); // 距离越近缩放越大(可调整比例) const scaleFactor = Math.min(5, 10 / distance); entity.setAttribute("scale", `${scaleFactor} ${scaleFactor} ${scaleFactor}`); }); requestAnimationFrame(updateTextScale); } // 设置实体经纬度 function setEntityLocation() { const latInput = document.getElementById("latitude"); const lngInput = document.getElementById("longitude"); targetLat = parseFloat(latInput.value) || 0; targetLng = parseFloat(lngInput.value) || 0; // 更新现有实体位置 textEntities.forEach(entity => { entity.setAttribute("gps-entity-place", `latitude: ${targetLat}; longitude: ${targetLng}`); }); } function rap() { for (let i = 0; i < lyrics.length; i++) { setTimeout(function () { createEntity(lyrics[i]); }, (delay += 2000)); } // 启动距离监听 setTimeout(() => updateTextScale(), 3000); } rap(); </script> </body> </html>
功能说明
- 经纬度设置:页面顶部的输入面板支持手动输入目标经纬度,点击按钮后所有文本实体将绑定到该GPS位置
- 距离响应缩放:通过
requestAnimationFrame实时计算用户与文本的距离,动态调整文本大小,距离越近文本越大 - 视角控制:启用
look-controls后,用户可拖动屏幕绕文本实体旋转视角,实现环绕查看 - 文本朝向:
look-at组件确保文本始终面向用户,提升AR交互的直观性
内容的提问来源于stack exchange,提问作者hayden
相关产品推荐
相关产品推荐

