参考AR.js 结合vue three.js 实现基于位置的一个模型加载AR
本次demo运用的three.js 的版本为0.126.1
主要思路
- 获取手机的媒体视频流
- 将视频流作为场景的背景
- 运用透视相机结合手机定位定位相机位置
- 运用three.js 的设备控制器控制相机的移动
实现
获取手机媒体视频
getVideo() {function getUserMedia(constraints, success, error) { if (navigator.mediaDevices.getUserMedia) { //最新的标准API navigator.mediaDevices .getUserMedia(constraints) .then(success) .catch(error); } else if (navigator.webkitGetUserMedia) { //webkit核心浏览器 navigator.webkitGetUserMedia(constraints, success, error); } else if (navigator.mozGetUserMedia) { //firfox浏览器 navigator.mozGetUserMedia(constraints, success, error); } else if (navigator.getUserMedia) { //旧版API navigator.getUserMedia(constraints, success, error); } }
function success(stream) { //兼容webkit核心浏览器 // let CompatibleURL = window.URL || window.webkitURL; //将视频流设置为video元素的源 console.log(stream); //video.src = CompatibleURL.createObjectURL(stream); video.srcObject = stream; video.play(); } function error(error) { console.log(`访问用户媒体设备失败${error.name}, ${error.message}`); } if ( navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ) { //调用用户媒体设备, 访问摄像头 getUserMedia( { video: { // width: window.innerWidth, // height: window.innerHeight, facingMode: { exact: "environment", }, }, }, success, error ); } else { alert("不支持访问用户媒体"); } video.addEventListener( "pause", function () { window.clearInterval(); }, false ); video.addEventListener( "ended", function () { clearInterval(); }, false ); return video;}
加载场景
init(){
let _this = this; let dom = document.getElementById("ARShow"); let width = dom.clientWidth; let height = dom.clientHeight; camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 100); scene = new THREE.Scene(); // 创建场景
// 将获取的视频流作为场景背景
scene.background = new THREE.VideoTexture(_this.getVideo()); / scene.updateMatrixWorld(true); renderer = new THREE.WebGLRenderer({ alpha: true, }); renderer.setSize(width, height); dom.appendChild(renderer.domElement); let material = new THREE.MeshBasicMaterial({ color: 0xff0000, }); let pointLoaction = lglt2xyz(longitude, latitude); // 自定义的经纬度 let pointLoactionS = new THREE.Vector3( pointLoaction.x, 0, pointLoaction.z );
let pointGeometry = new THREE.CylinderGeometry( 0.3, 0.3, 2, 32 ); let pointMesh = new THREE.Mesh(pointGeometry, material); pointMesh.position.set( pointLoactionS.x, pointLoactionS.y, pointLoactionS.z ); scene.add(pointMesh); // 网格模型添加到场景中
controls = new DeviceOrientationControls(camera);
function animate() { window.requestAnimationFrame(animate); camera.lookAt(scene.position); camera.updateProjectionMatrix(); controls.update(); renderer.render(scene, camera); } animate();
}
将经纬度转换为世界坐标
function lglt2xyz(longitude, latitude, radius=6378137) { var lg = THREE.Math.degToRad(longitude); var lt = THREE.Math.degToRad(latitude); var temp = radius * Math.cos(lt); var x = temp * Math.sin(lg); var y = radius * Math.sin(lt); var z = temp * Math.cos(lg); return { x: x, y: y, z: z, } }
获取用户位置信息
var timer = navigator.geolocation.watchPosition( function (position) { // watchPosition var longitude = position.coords.longitude; var latitude = position.coords.latitude; console.log("经度", longitude); console.log("纬度", latitude); let cameraPosition = lglt2xyz(longitude, latitude); let cameraP = new THREE.Vector3( cameraPosition.x, 3, cameraPosition.z ); camera.position.set(cameraP.x, cameraP.y, cameraP.z); // camera.target = new THREE.Vector3( // cameraPosition.x, // cameraPosition.y, // cameraPosition.z // ); }, function (error) { alert(error.code); //清除多次地理位置定位 navigator.geolocation.clearWatch(timer); }, { /*数据收集 : json的形式 enableHighAcuracy : 更精确的查找,默认false timeout :指定获取地理位置的超时时间,默认不限时,单位为毫秒 maximumAge :最长有效期,在重复获取地理位置时,此参数指定多久再次获取位置。 */ enableHighAccuracy: true, maximumAge: 2, } );
手机定位有偏差效果可能会有偏差