Commit 48a8afca authored by Alfakhori's avatar Alfakhori
Browse files

Update public/2-Hit.html, public/1-Cube.html, public/page2.html

Deleted public/build/aframe-ar-location-only.js, public/build/aframe-ar-new-location-only.js, public/build/aframe-ar-nft.js, public/build/aframe-ar.js, public/build/ar-threex-location-only.js, public/app.js
parent c4777486
Pipeline #7416 passed with stage
in 9 seconds
/*
* Copyright 2017 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Query for WebXR support. If there's no support for the `immersive-ar` mode,
* show an error.
*/
(async function() {
const isArSessionSupported = navigator.xr && navigator.xr.isSessionSupported && await navigator.xr.isSessionSupported("immersive-ar");
if (isArSessionSupported) {
document.getElementById("enter-ar").addEventListener("click", window.app.activateXR)
} else {
onNoXRDevice();
}
})();
/**
* Container class to manage connecting to the WebXR Device API
* and handle rendering on every frame.
*/
class App {
/**
* Run when the Start AR button is pressed.
*/
activateXR = async () => {
try {
// Initialize a WebXR session using "immersive-ar".
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
requiredFeatures: ['hit-test', 'dom-overlay'],
domOverlay: { root: document.body }
});
// Create the canvas that will contain our camera's background and our virtual scene.
this.createXRCanvas();
// With everything set up, start the app.
await this.onSessionStarted();
} catch(e) {
console.log(e);
onNoXRDevice();
}
}
/**
* Add a canvas element and initialize a WebGL context that is compatible with WebXR.
*/
createXRCanvas() {
this.canvas = document.createElement("canvas");
document.body.appendChild(this.canvas);
this.gl = this.canvas.getContext("webgl", {xrCompatible: true});
this.xrSession.updateRenderState({
baseLayer: new XRWebGLLayer(this.xrSession, this.gl)
});
}
/**
* Called when the XRSession has begun. Here we set up our three.js
* renderer, scene, and camera and attach our XRWebGLLayer to the
* XRSession and kick off the render loop.
*/
onSessionStarted = async () => {
// Add the `ar` class to our body, which will hide our 2D components
document.body.classList.add('ar');
// To help with working with 3D on the web, we'll use three.js.
this.setupThreeJs();
// Setup an XRReferenceSpace using the "local" coordinate system.
this.localReferenceSpace = await this.xrSession.requestReferenceSpace('local');
// Create another XRReferenceSpace that has the viewer as the origin.
this.viewerSpace = await this.xrSession.requestReferenceSpace('viewer');
// Perform hit testing using the viewer as origin.
this.hitTestSource = await this.xrSession.requestHitTestSource({ space: this.viewerSpace });
// Start a rendering loop using this.onXRFrame.
this.xrSession.requestAnimationFrame(this.onXRFrame);
this.xrSession.addEventListener("select", this.onSelect);
}
/** Place a sunflower when the screen is tapped. */
onSelect = () => {
if (window.sunflower) {
const clone = window.sunflower.clone();
clone.position.copy(this.reticle.position);
this.scene.add(clone)
const shadowMesh = this.scene.children.find(c => c.name === 'shadowMesh');
shadowMesh.position.y = clone.position.y;
}
}
/**
* Called on the XRSession's requestAnimationFrame.
* Called with the time and XRPresentationFrame.
*/
onXRFrame = (time, frame) => {
// Queue up the next draw request.
this.xrSession.requestAnimationFrame(this.onXRFrame);
// Bind the graphics framebuffer to the baseLayer's framebuffer.
const framebuffer = this.xrSession.renderState.baseLayer.framebuffer
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer)
this.renderer.setFramebuffer(framebuffer);
// Retrieve the pose of the device.
// XRFrame.getViewerPose can return null while the session attempts to establish tracking.
const pose = frame.getViewerPose(this.localReferenceSpace);
if (pose) {
// In mobile AR, we only have one view.
const view = pose.views[0];
const viewport = this.xrSession.renderState.baseLayer.getViewport(view);
this.renderer.setSize(viewport.width, viewport.height)
// Use the view's transform matrix and projection matrix to configure the THREE.camera.
this.camera.matrix.fromArray(view.transform.matrix)
this.camera.projectionMatrix.fromArray(view.projectionMatrix);
this.camera.updateMatrixWorld(true);
// Conduct hit test.
const hitTestResults = frame.getHitTestResults(this.hitTestSource);
// If we have results, consider the environment stabilized.
if (!this.stabilized && hitTestResults.length > 0) {
this.stabilized = true;
document.body.classList.add('stabilized');
}
if (hitTestResults.length > 0) {
const hitPose = hitTestResults[0].getPose(this.localReferenceSpace);
// Update the reticle position
this.reticle.visible = true;
this.reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
this.reticle.updateMatrixWorld(true);
}
// Render the scene with THREE.WebGLRenderer.
this.renderer.render(this.scene, this.camera)
}
}
/**
* Initialize three.js specific rendering code, including a WebGLRenderer,
* a demo scene, and a camera for viewing the 3D content.
*/
setupThreeJs() {
// To help with working with 3D on the web, we'll use three.js.
// Set up the WebGLRenderer, which handles rendering to our session's base layer.
this.renderer = new THREE.WebGLRenderer({
alpha: true,
preserveDrawingBuffer: true,
canvas: this.canvas,
context: this.gl
});
this.renderer.autoClear = false;
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Initialize our demo scene.
this.scene = DemoUtils.createLitScene();
this.reticle = new Reticle();
this.scene.add(this.reticle);
// We'll update the camera matrices directly from API, so
// disable matrix auto updates so three.js doesn't attempt
// to handle the matrices independently.
this.camera = new THREE.PerspectiveCamera();
this.camera.matrixAutoUpdate = false;
}
};
window.app = new App();
This diff is collapsed.
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("aframe"),require("three")):"function"==typeof define&&define.amd?define(["aframe","three"],e):"object"==typeof exports?exports.ARjs=e(require("aframe"),require("three")):t.ARjs=e(t.AFRAME,t.THREE)}(this,((t,e)=>(()=>{var i={254:function(t,e,i){var o;o=t=>(()=>{"use strict";var e={381:e=>{e.exports=t}},i={};function o(t){var n=i[t];if(void 0!==n)return n.exports;var s=i[t]={exports:{}};return e[t](s,s.exports,o),s.exports}o.d=(t,e)=>{for(var i in e)o.o(e,i)&&!o.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var n={};return(()=>{o.r(n),o.d(n,{DeviceOrientationControls:()=>l,LocationBased:()=>i,WebcamRenderer:()=>s});class t{constructor(){this.EARTH=40075016.68,this.HALF_EARTH=20037508.34}project(t,e){return[this.lonToSphMerc(t),this.latToSphMerc(e)]}unproject(t){return[this.sphMercToLon(t[0]),this.sphMercToLat(t[1])]}lonToSphMerc(t){return t/180*this.HALF_EARTH}latToSphMerc(t){return Math.log(Math.tan((90+t)*Math.PI/360))/(Math.PI/180)*this.HALF_EARTH/180}sphMercToLon(t){return t/this.HALF_EARTH*180}sphMercToLat(t){var e=t/this.HALF_EARTH*180;return 180/Math.PI*(2*Math.atan(Math.exp(e*Math.PI/180))-Math.PI/2)}getID(){return"epsg:3857"}}var e=o(381);class i{constructor(e,i,o={}){this._scene=e,this._camera=i,this._proj=new t,this._eventHandlers={},this._lastCoords=null,this._gpsMinDistance=0,this._gpsMinAccuracy=100,this._maximumAge=0,this._watchPositionId=null,this.setGpsOptions(o),this.initialPosition=null,this.initialPositionAsOrigin=o.initialPositionAsOrigin||!1}setProjection(t){this._proj=t}setGpsOptions(t={}){void 0!==t.gpsMinDistance&&(this._gpsMinDistance=t.gpsMinDistance),void 0!==t.gpsMinAccuracy&&(this._gpsMinAccuracy=t.gpsMinAccuracy),void 0!==t.maximumAge&&(this._maximumAge=t.maximumAge)}startGps(t=0){return null===this._watchPositionId&&(this._watchPositionId=navigator.geolocation.watchPosition((t=>{this._gpsReceived(t)}),(t=>{this._eventHandlers.gpserror?this._eventHandlers.gpserror(t.code):alert(`GPS error: code ${t.code}`)}),{enableHighAccuracy:!0,maximumAge:0!=t?t:this._maximumAge}),!0)}stopGps(){return null!==this._watchPositionId&&(navigator.geolocation.clearWatch(this._watchPositionId),this._watchPositionId=null,!0)}fakeGps(t,e,i=null,o=0){null!==i&&this.setElevation(i),this._gpsReceived({coords:{longitude:t,latitude:e,accuracy:o}})}lonLatToWorldCoords(t,e){const i=this._proj.project(t,e);if(this.initialPositionAsOrigin){if(!this.initialPosition)throw"Trying to use 'initial position as origin' mode with no initial position determined";i[0]-=this.initialPosition[0],i[1]-=this.initialPosition[1]}return[i[0],-i[1]]}add(t,e,i,o){this.setWorldPosition(t,e,i,o),this._scene.add(t)}setWorldPosition(t,e,i,o){const n=this.lonLatToWorldCoords(e,i);void 0!==o&&(t.position.y=o),[t.position.x,t.position.z]=n}setElevation(t){this._camera.position.y=t}on(t,e){this._eventHandlers[t]=e}setWorldOrigin(t,e){this.initialPosition=this._proj.project(t,e)}_gpsReceived(t){let e=Number.MAX_VALUE;t.coords.accuracy<=this._gpsMinAccuracy&&(null===this._lastCoords?this._lastCoords={latitude:t.coords.latitude,longitude:t.coords.longitude}:e=this._haversineDist(this._lastCoords,t.coords),e>=this._gpsMinDistance&&(this._lastCoords.longitude=t.coords.longitude,this._lastCoords.latitude=t.coords.latitude,this.initialPositionAsOrigin&&!this.initialPosition&&this.setWorldOrigin(t.coords.longitude,t.coords.latitude),this.setWorldPosition(this._camera,t.coords.longitude,t.coords.latitude),this._eventHandlers.gpsupdate&&this._eventHandlers.gpsupdate(t,e)))}_haversineDist(t,i){const o=e.MathUtils.degToRad(i.longitude-t.longitude),n=e.MathUtils.degToRad(i.latitude-t.latitude),s=Math.sin(n/2)*Math.sin(n/2)+Math.cos(e.MathUtils.degToRad(t.latitude))*Math.cos(e.MathUtils.degToRad(i.latitude))*(Math.sin(o/2)*Math.sin(o/2));return 2*Math.atan2(Math.sqrt(s),Math.sqrt(1-s))*6371e3}}class s{constructor(t,i){let o;this.renderer=t,this.renderer.autoClear=!1,this.sceneWebcam=new e.Scene,void 0===i?(o=document.createElement("video"),o.setAttribute("autoplay",!0),o.setAttribute("playsinline",!0),o.style.display="none",document.body.appendChild(o)):o=document.querySelector(i),this.geom=new e.PlaneBufferGeometry,this.texture=new e.VideoTexture(o),this.material=new e.MeshBasicMaterial({map:this.texture});const n=new e.Mesh(this.geom,this.material);if(this.sceneWebcam.add(n),this.cameraWebcam=new e.OrthographicCamera(-.5,.5,.5,-.5,0,10),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const t={video:{width:1280,height:720,facingMode:"environment"}};navigator.mediaDevices.getUserMedia(t).then((t=>{console.log("using the webcam successfully..."),o.srcObject=t,o.play()})).catch((t=>{setTimeout((()=>{this.createErrorPopup("Webcam Error\nName: "+t.name+"\nMessage: "+t.message)}),1e3)}))}else setTimeout((()=>{this.createErrorPopup("sorry - media devices API not supported")}),1e3)}update(){this.renderer.clear(),this.renderer.render(this.sceneWebcam,this.cameraWebcam),this.renderer.clearDepth()}dispose(){this.material.dispose(),this.texture.dispose(),this.geom.dispose()}createErrorPopup(t){if(!document.getElementById("error-popup")){var e=document.createElement("div");e.innerHTML=t,e.setAttribute("id","error-popup"),document.body.appendChild(e)}}}const a=new e.Vector3(0,0,1),r=new e.Euler,c=new e.Quaternion,d=new e.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5)),h={type:"change"};class l extends e.EventDispatcher{constructor(t){super(),!1===window.isSecureContext&&console.error("THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)");const i=this,o=new e.Quaternion;this.object=t,this.object.rotation.reorder("YXZ"),this.enabled=!0,this.deviceOrientation={},this.screenOrientation=0,this.alphaOffset=0,this.TWO_PI=2*Math.PI,this.HALF_PI=.5*Math.PI,this.orientationChangeEventName="ondeviceorientationabsolute"in window?"deviceorientationabsolute":"deviceorientation",this.smoothingFactor=1;const n=function(t){i.deviceOrientation=t},s=function(){i.screenOrientation=window.orientation||0};this.connect=function(){s(),void 0!==window.DeviceOrientationEvent&&"function"==typeof window.DeviceOrientationEvent.requestPermission?window.DeviceOrientationEvent.requestPermission().then((t=>{"granted"===t&&(window.addEventListener("orientationchange",s),window.addEventListener(i.orientationChangeEventName,n))})).catch((function(t){console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",t)})):(window.addEventListener("orientationchange",s),window.addEventListener(i.orientationChangeEventName,n)),i.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",s),window.removeEventListener(i.orientationChangeEventName,n),i.enabled=!1},this.update=function(){if(!1===i.enabled)return;const t=i.deviceOrientation;if(t){let n=t.alpha?e.MathUtils.degToRad(t.alpha)+i.alphaOffset:0,s=t.beta?e.MathUtils.degToRad(t.beta):0,l=t.gamma?e.MathUtils.degToRad(t.gamma):0;const u=i.screenOrientation?e.MathUtils.degToRad(i.screenOrientation):0;if(this.smoothingFactor<1){if(this.lastOrientation){const t=this.smoothingFactor;n=this._getSmoothedAngle(n,this.lastOrientation.alpha,t),s=this._getSmoothedAngle(s+Math.PI,this.lastOrientation.beta,t),l=this._getSmoothedAngle(l+this.HALF_PI,this.lastOrientation.gamma,t,Math.PI)}else s+=Math.PI,l+=this.HALF_PI;this.lastOrientation={alpha:n,beta:s,gamma:l}}!function(t,e,i,o,n){r.set(i,e,-o,"YXZ"),t.setFromEuler(r),t.multiply(d),t.multiply(c.setFromAxisAngle(a,-n))}(i.object.quaternion,n,this.smoothingFactor<1?s-Math.PI:s,this.smoothingFactor<1?l-this.HALF_PI:l,u),8*(1-o.dot(i.object.quaternion))>1e-6&&(o.copy(i.object.quaternion),i.dispatchEvent(h))}},this._orderAngle=function(t,e,i=this.TWO_PI){return e>t&&Math.abs(e-t)<i/2||t>e&&Math.abs(e-t)>i/2?{left:t,right:e}:{left:e,right:t}},this._getSmoothedAngle=function(t,e,i,o=this.TWO_PI){const n=this._orderAngle(t,e,o),s=n.left,a=n.right;n.left=0,n.right-=s,n.right<0&&(n.right+=o);let r=a==e?(1-i)*n.right+i*n.left:i*n.right+(1-i)*n.left;return r+=s,r>=o&&(r-=o),r},this.dispose=function(){i.disconnect()},this.connect()}}})(),n})(),t.exports=o(i(381))},223:e=>{"use strict";e.exports=t},381:t=>{"use strict";t.exports=e}},o={};function n(t){var e=o[t];if(void 0!==e)return e.exports;var s=o[t]={exports:{}};return i[t].call(s.exports,s,s.exports,n),s.exports}n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var s={};return(()=>{"use strict";n.r(s);var t=n(223),e=n(381);t.registerComponent("arjs-webcam-texture",{init:function(){this.scene=this.el.sceneEl,this.texCamera=new e.OrthographicCamera(-.5,.5,.5,-.5,0,10),this.texScene=new e.Scene,this.scene.renderer.autoClear=!1,this.video=document.createElement("video"),this.video.setAttribute("autoplay",!0),this.video.setAttribute("playsinline",!0),this.video.setAttribute("display","none"),document.body.appendChild(this.video),this.geom=new e.PlaneBufferGeometry,this.texture=new e.VideoTexture(this.video),this.material=new e.MeshBasicMaterial({map:this.texture});const t=new e.Mesh(this.geom,this.material);this.texScene.add(t)},play:function(){if(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const t={video:{facingMode:"environment"}};navigator.mediaDevices.getUserMedia(t).then((t=>{this.video.srcObject=t,this.video.play()})).catch((t=>{this.el.sceneEl.systems.arjs._displayErrorPopup(`Webcam error: ${t}`)}))}else this.el.sceneEl.systems.arjs._displayErrorPopup("sorry - media devices API not supported")},tick:function(){this.scene.renderer.clear(),this.scene.renderer.render(this.texScene,this.texCamera),this.scene.renderer.clearDepth()},pause:function(){this.video.srcObject.getTracks().forEach((t=>{t.stop()}))},remove:function(){this.material.dispose(),this.texture.dispose(),this.geom.dispose()}});var i=n(254);t.registerComponent("gps-new-camera",{schema:{simulateLatitude:{type:"number",default:0},simulateLongitude:{type:"number",default:0},simulateAltitude:{type:"number",default:-Number.MAX_VALUE},gpsMinDistance:{type:"number",default:0},positionMinAccuracy:{type:"number",default:100},gpsTimeInterval:{type:"number",default:0},initialPositionAsOrigin:{type:"boolean",default:!1}},init:function(){this._testForOrientationControls(),this.threeLoc=new i.LocationBased(this.el.sceneEl.object3D,this.el.object3D,{initialPositionAsOrigin:this.data.initialPositionAsOrigin}),this.threeLoc.on("gpsupdate",(t=>{this._currentPosition={longitude:t.coords.longitude,latitude:t.coords.latitude},this._sendGpsUpdateEvent(t.coords.longitude,t.coords.latitude)})),this.threeLoc.on("gpserror",(t=>{t>=1&&t<=3?this._displayError(["User denied access to GPS.","GPS satellites not available.","Timeout communicating with GPS satellites - try moving to a more open area."][t-1]):this._displayError(`Unknown geolocation error code ${t}.`)}));const t=this._isMobile();this.el.setAttribute("look-controls-enabled",!t),t&&this.el.setAttribute("arjs-device-orientation-controls",!0),navigator.userAgent.match(/Version\/[\d.]+.*Safari/)&&this._setupSafariOrientationPermissions(),this.el.sceneEl.addEventListener("gps-entity-place-added",(t=>{const e=t.detail.component.components["gps-new-entity-place"];this._currentPosition&&e.setDistanceFrom(this._currentPosition)}))},update:function(t){this.threeLoc.setGpsOptions({gpsMinAccuracy:this.data.positionMinAccuracy,gpsMinDistance:this.data.gpsMinDistance,maximumAge:this.data.gpsTimeInterval}),0===this.data.simulateLatitude&&0===this.data.simulateLongitude||this.data.simulateLatitude==t.simulateLatitude&&this.data.simulateLongitude==t.simulateLongitude||(this.threeLoc.stopGps(),this.threeLoc.fakeGps(this.data.simulateLongitude,this.data.simulateLatitude),this.data.simulateLatitude=0,this.data.simulateLongitude=0),this.data.simulateAltitude>-Number.MAX_VALUE&&this.threeLoc.setElevation(this.data.simulateAltitude+1.6)},play:function(){0===this.data.simulateLatitude&&0===this.data.simulateLongitude&&this.threeLoc.startGps()},pause:function(){this.threeLoc.stopGps()},latLonToWorld:function(t,e){return this.threeLoc.lonLatToWorldCoords(e,t)},getInitialPosition:function(){return this.threeLoc.initialPosition},_sendGpsUpdateEvent:function(t,e){this.el.emit("gps-camera-update-position",{position:{longitude:t,latitude:e}})},_testForOrientationControls:function(){this.el.components["arjs-device-orientation-controls"]||this.el.components["look-controls"]||this._displayError("WARNING - No orientation controls component, app will not respond to device rotation.")},_displayError:function(t){const e=this.el.sceneEl.systems.arjs;e?e._displayErrorPopup(t):alert(t)},_setupSafariOrientationPermissions:function(){if("function"==typeof window.DeviceOrientationEvent?.requestPermission){var t=function(){console.log("Requesting device orientation permissions..."),DeviceOrientationEvent.requestPermission(),document.removeEventListener("touchend",t)};document.addEventListener("touchend",(function(){t()}),!1),this.el.sceneEl.systems.arjs._displayErrorPopup("After camera permission prompt, please tap the screen to activate geolocation.")}else{var e=setTimeout((()=>{this.el.sceneEl.systems.arjs._displayErrorPopup("Please enable device orientation in Settings > Safari > Motion & Orientation Access.")}),750);window.addEventListener("deviceorientation",(function(){clearTimeout(e)}),{once:!0})}},_isMobile:function(){return!!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}}),t.registerComponent("gps-new-entity-place",{schema:{longitude:{type:"number",default:0},latitude:{type:"number",default:0}},init:function(){const t=document.querySelector("[gps-new-camera]");t.components["gps-new-camera"]?(this._cameraGps=t.components["gps-new-camera"],t.addEventListener("gps-camera-update-position",(t=>{this.distance=this._haversineDist(t.detail.position,this.data)})),this.el.sceneEl.emit("gps-entity-place-added",{component:this.el})):console.error("gps-new-camera not initialised")},update:function(){const t=this._cameraGps.threeLoc.lonLatToWorldCoords(this.data.longitude,this.data.latitude);this.el.object3D.position.set(t[0],this.el.object3D.position.y,t[1])},setDistanceFrom:function(t){this.distance=this._haversineDist(t,this.data)},_haversineDist:function(t,i){const o=e.MathUtils.degToRad(i.longitude-t.longitude),n=e.MathUtils.degToRad(i.latitude-t.latitude),s=Math.sin(n/2)*Math.sin(n/2)+Math.cos(e.MathUtils.degToRad(t.latitude))*Math.cos(e.MathUtils.degToRad(i.latitude))*(Math.sin(o/2)*Math.sin(o/2));return 2*Math.atan2(Math.sqrt(s),Math.sqrt(1-s))*6371e3}}),t.registerComponent("arjs-device-orientation-controls",{schema:{smoothingFactor:{type:"number",default:1}},init:function(){this._orientationControls=new THREEx.DeviceOrientationControls(this.el.object3D)},update:function(){this._orientationControls.smoothingFactor=this.data.smoothingFactor},tick:function(){this._orientationControls.update()}})})(),s})()));
This diff is collapsed.
This diff is collapsed.
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("three")):"function"==typeof define&&define.amd?define(["three"],e):"object"==typeof exports?exports.THREEx=e(require("three")):t.THREEx=e(t.THREE)}(this,(t=>(()=>{"use strict";var e={381:e=>{e.exports=t}},i={};function o(t){var n=i[t];if(void 0!==n)return n.exports;var s=i[t]={exports:{}};return e[t](s,s.exports,o),s.exports}o.d=(t,e)=>{for(var i in e)o.o(e,i)&&!o.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var n={};return(()=>{o.r(n),o.d(n,{DeviceOrientationControls:()=>l,LocationBased:()=>i,WebcamRenderer:()=>s});class t{constructor(){this.EARTH=40075016.68,this.HALF_EARTH=20037508.34}project(t,e){return[this.lonToSphMerc(t),this.latToSphMerc(e)]}unproject(t){return[this.sphMercToLon(t[0]),this.sphMercToLat(t[1])]}lonToSphMerc(t){return t/180*this.HALF_EARTH}latToSphMerc(t){return Math.log(Math.tan((90+t)*Math.PI/360))/(Math.PI/180)*this.HALF_EARTH/180}sphMercToLon(t){return t/this.HALF_EARTH*180}sphMercToLat(t){var e=t/this.HALF_EARTH*180;return 180/Math.PI*(2*Math.atan(Math.exp(e*Math.PI/180))-Math.PI/2)}getID(){return"epsg:3857"}}var e=o(381);class i{constructor(e,i,o={}){this._scene=e,this._camera=i,this._proj=new t,this._eventHandlers={},this._lastCoords=null,this._gpsMinDistance=0,this._gpsMinAccuracy=100,this._maximumAge=0,this._watchPositionId=null,this.setGpsOptions(o),this.initialPosition=null,this.initialPositionAsOrigin=o.initialPositionAsOrigin||!1}setProjection(t){this._proj=t}setGpsOptions(t={}){void 0!==t.gpsMinDistance&&(this._gpsMinDistance=t.gpsMinDistance),void 0!==t.gpsMinAccuracy&&(this._gpsMinAccuracy=t.gpsMinAccuracy),void 0!==t.maximumAge&&(this._maximumAge=t.maximumAge)}startGps(t=0){return null===this._watchPositionId&&(this._watchPositionId=navigator.geolocation.watchPosition((t=>{this._gpsReceived(t)}),(t=>{this._eventHandlers.gpserror?this._eventHandlers.gpserror(t.code):alert(`GPS error: code ${t.code}`)}),{enableHighAccuracy:!0,maximumAge:0!=t?t:this._maximumAge}),!0)}stopGps(){return null!==this._watchPositionId&&(navigator.geolocation.clearWatch(this._watchPositionId),this._watchPositionId=null,!0)}fakeGps(t,e,i=null,o=0){null!==i&&this.setElevation(i),this._gpsReceived({coords:{longitude:t,latitude:e,accuracy:o}})}lonLatToWorldCoords(t,e){const i=this._proj.project(t,e);if(this.initialPositionAsOrigin){if(!this.initialPosition)throw"Trying to use 'initial position as origin' mode with no initial position determined";i[0]-=this.initialPosition[0],i[1]-=this.initialPosition[1]}return[i[0],-i[1]]}add(t,e,i,o){this.setWorldPosition(t,e,i,o),this._scene.add(t)}setWorldPosition(t,e,i,o){const n=this.lonLatToWorldCoords(e,i);void 0!==o&&(t.position.y=o),[t.position.x,t.position.z]=n}setElevation(t){this._camera.position.y=t}on(t,e){this._eventHandlers[t]=e}setWorldOrigin(t,e){this.initialPosition=this._proj.project(t,e)}_gpsReceived(t){let e=Number.MAX_VALUE;t.coords.accuracy<=this._gpsMinAccuracy&&(null===this._lastCoords?this._lastCoords={latitude:t.coords.latitude,longitude:t.coords.longitude}:e=this._haversineDist(this._lastCoords,t.coords),e>=this._gpsMinDistance&&(this._lastCoords.longitude=t.coords.longitude,this._lastCoords.latitude=t.coords.latitude,this.initialPositionAsOrigin&&!this.initialPosition&&this.setWorldOrigin(t.coords.longitude,t.coords.latitude),this.setWorldPosition(this._camera,t.coords.longitude,t.coords.latitude),this._eventHandlers.gpsupdate&&this._eventHandlers.gpsupdate(t,e)))}_haversineDist(t,i){const o=e.MathUtils.degToRad(i.longitude-t.longitude),n=e.MathUtils.degToRad(i.latitude-t.latitude),s=Math.sin(n/2)*Math.sin(n/2)+Math.cos(e.MathUtils.degToRad(t.latitude))*Math.cos(e.MathUtils.degToRad(i.latitude))*(Math.sin(o/2)*Math.sin(o/2));return 2*Math.atan2(Math.sqrt(s),Math.sqrt(1-s))*6371e3}}class s{constructor(t,i){let o;this.renderer=t,this.renderer.autoClear=!1,this.sceneWebcam=new e.Scene,void 0===i?(o=document.createElement("video"),o.setAttribute("autoplay",!0),o.setAttribute("playsinline",!0),o.style.display="none",document.body.appendChild(o)):o=document.querySelector(i),this.geom=new e.PlaneBufferGeometry,this.texture=new e.VideoTexture(o),this.material=new e.MeshBasicMaterial({map:this.texture});const n=new e.Mesh(this.geom,this.material);if(this.sceneWebcam.add(n),this.cameraWebcam=new e.OrthographicCamera(-.5,.5,.5,-.5,0,10),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const t={video:{width:1280,height:720,facingMode:"environment"}};navigator.mediaDevices.getUserMedia(t).then((t=>{console.log("using the webcam successfully..."),o.srcObject=t,o.play()})).catch((t=>{setTimeout((()=>{this.createErrorPopup("Webcam Error\nName: "+t.name+"\nMessage: "+t.message)}),1e3)}))}else setTimeout((()=>{this.createErrorPopup("sorry - media devices API not supported")}),1e3)}update(){this.renderer.clear(),this.renderer.render(this.sceneWebcam,this.cameraWebcam),this.renderer.clearDepth()}dispose(){this.material.dispose(),this.texture.dispose(),this.geom.dispose()}createErrorPopup(t){if(!document.getElementById("error-popup")){var e=document.createElement("div");e.innerHTML=t,e.setAttribute("id","error-popup"),document.body.appendChild(e)}}}const r=new e.Vector3(0,0,1),a=new e.Euler,h=new e.Quaternion,c=new e.Quaternion(-Math.sqrt(.5),0,0,Math.sqrt(.5)),d={type:"change"};class l extends e.EventDispatcher{constructor(t){super(),!1===window.isSecureContext&&console.error("THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)");const i=this,o=new e.Quaternion;this.object=t,this.object.rotation.reorder("YXZ"),this.enabled=!0,this.deviceOrientation={},this.screenOrientation=0,this.alphaOffset=0,this.TWO_PI=2*Math.PI,this.HALF_PI=.5*Math.PI,this.orientationChangeEventName="ondeviceorientationabsolute"in window?"deviceorientationabsolute":"deviceorientation",this.smoothingFactor=1;const n=function(t){i.deviceOrientation=t},s=function(){i.screenOrientation=window.orientation||0};this.connect=function(){s(),void 0!==window.DeviceOrientationEvent&&"function"==typeof window.DeviceOrientationEvent.requestPermission?window.DeviceOrientationEvent.requestPermission().then((t=>{"granted"===t&&(window.addEventListener("orientationchange",s),window.addEventListener(i.orientationChangeEventName,n))})).catch((function(t){console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:",t)})):(window.addEventListener("orientationchange",s),window.addEventListener(i.orientationChangeEventName,n)),i.enabled=!0},this.disconnect=function(){window.removeEventListener("orientationchange",s),window.removeEventListener(i.orientationChangeEventName,n),i.enabled=!1},this.update=function(){if(!1===i.enabled)return;const t=i.deviceOrientation;if(t){let n=t.alpha?e.MathUtils.degToRad(t.alpha)+i.alphaOffset:0,s=t.beta?e.MathUtils.degToRad(t.beta):0,l=t.gamma?e.MathUtils.degToRad(t.gamma):0;const u=i.screenOrientation?e.MathUtils.degToRad(i.screenOrientation):0;if(this.smoothingFactor<1){if(this.lastOrientation){const t=this.smoothingFactor;n=this._getSmoothedAngle(n,this.lastOrientation.alpha,t),s=this._getSmoothedAngle(s+Math.PI,this.lastOrientation.beta,t),l=this._getSmoothedAngle(l+this.HALF_PI,this.lastOrientation.gamma,t,Math.PI)}else s+=Math.PI,l+=this.HALF_PI;this.lastOrientation={alpha:n,beta:s,gamma:l}}!function(t,e,i,o,n){a.set(i,e,-o,"YXZ"),t.setFromEuler(a),t.multiply(c),t.multiply(h.setFromAxisAngle(r,-n))}(i.object.quaternion,n,this.smoothingFactor<1?s-Math.PI:s,this.smoothingFactor<1?l-this.HALF_PI:l,u),8*(1-o.dot(i.object.quaternion))>1e-6&&(o.copy(i.object.quaternion),i.dispatchEvent(d))}},this._orderAngle=function(t,e,i=this.TWO_PI){return e>t&&Math.abs(e-t)<i/2||t>e&&Math.abs(e-t)>i/2?{left:t,right:e}:{left:e,right:t}},this._getSmoothedAngle=function(t,e,i,o=this.TWO_PI){const n=this._orderAngle(t,e,o),s=n.left,r=n.right;n.left=0,n.right-=s,n.right<0&&(n.right+=o);let a=r==e?(1-i)*n.right+i*n.left:i*n.right+(1-i)*n.left;return a+=s,a>=o&&(a-=o),a},this.dispose=function(){i.disconnect()},this.connect()}}})(),n})()));
<!doctype html>
<!--
/*
* Copyright 2017 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Building an augmented reality application with the WebXR Device API</title>
<link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css">
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Hit Tree 1.0</title>
<!-- three.js -->
<script src="https://unpkg.com/three@0.126.0/build/three.js"></script>
<script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script>
</head>
<body>
<!-- Starting an immersive WebXR session requires user interaction.
We start this one with a simple button. -->
<button onclick="activateXR()">Start Hello WebXR</button>
<script>
async function activateXR() {
// Add a canvas element and initialize a WebGL context that is compatible with WebXR.
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const gl = canvas.getContext("webgl", {xrCompatible: true});
const scene = new THREE.Scene();
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
directionalLight.position.set(10, 15, 10);
scene.add(directionalLight);
// Set up the WebGLRenderer, which handles rendering to the session's base layer.
const renderer = new THREE.WebGLRenderer({
alpha: true,
preserveDrawingBuffer: true,
canvas: canvas,
context: gl
});
renderer.autoClear = false;
// The API directly updates the camera matrices.
// Disable matrix auto updates so three.js doesn't attempt
// to handle the matrices independently.
const camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;
// Initialize a WebXR session using "immersive-ar".
const session = await navigator.xr.requestSession("immersive-ar", {requiredFeatures: ['hit-test']});
session.updateRenderState({
baseLayer: new XRWebGLLayer(session, gl)
});
// A 'local' reference space has a native origin that is located
// near the viewer's position at the time the session was created.
const referenceSpace = await session.requestReferenceSpace('local');
// Create another XRReferenceSpace that has the viewer as the origin.
const viewerSpace = await session.requestReferenceSpace('viewer');
// Perform hit testing using the viewer as origin.
const hitTestSource = await session.requestHitTestSource({ space: viewerSpace });
const loader = new THREE.GLTFLoader();
let reticle;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", function(gltf) {
reticle = gltf.scene;
reticle.visible = false;
scene.add(reticle);
})
let flower;
loader.load("/assets/tree/scene.gltf", function(gltf) {
flower = gltf.scene;
});
session.addEventListener("select", (event) => {
if (flower) {
const clone = flower.clone();
clone.position.copy(reticle.position);
scene.add(clone);
}
});
// Create a render loop that allows us to draw on the AR view.
const onXRFrame = (time, frame) => {
// Queue up the next draw request.
session.requestAnimationFrame(onXRFrame);
// Bind the graphics framebuffer to the baseLayer's framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer)
// Retrieve the pose of the device.
// XRFrame.getViewerPose can return null while the session attempts to establish tracking.
const pose = frame.getViewerPose(referenceSpace);
if (pose) {
// In mobile AR, we only have one view.
const view = pose.views[0];
const viewport = session.renderState.baseLayer.getViewport(view);
renderer.setSize(viewport.width, viewport.height)
// Use the view's transform matrix and projection matrix to configure the THREE.camera.
camera.matrix.fromArray(view.transform.matrix)
camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true);
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0 && reticle) {
const hitPose = hitTestResults[0].getPose(referenceSpace);
reticle.visible = true;
reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
reticle.updateMatrixWorld(true);
}
// Render the scene with THREE.WebGLRenderer.
renderer.render(scene, camera)
}
}
session.requestAnimationFrame(onXRFrame);
<link rel="stylesheet" type="text/css" href="../shared/app.css" />
<script src="../shared/utils.js"></script>
</head>
<body>
<div id="enter-ar-info" class="mdc-card demo-card">
<h2>Augmented Reality with the WebXR Device API</h2>
<p>
This is an experiment using augmented reality features with the WebXR Device API.
Upon entering AR, you will be surrounded by a world of cubes.
Learn more about these features from the <a href="https://codelabs.developers.google.com/codelabs/ar-with-webxr">Building an augmented reality application with the WebXR Device API</a> Code Lab.
</p>
<!-- Starting an immersive WebXR session requires user interaction. Start the WebXR experience with a simple button. -->
<a id="enter-ar" class="mdc-button mdc-button--raised mdc-button--accent">
Start augmented reality
</a>
</div>
<div id="unsupported-info" class="mdc-card demo-card">
<h2>Unsupported Browser</h2>
<p>
Your browser does not support AR features with WebXR. Learn more about these features from the
<a href="https://codelabs.developers.google.com/codelabs/ar-with-webxr">Building an augmented reality application with the WebXR Device API</a> Code Lab.
</p>
</div>
<script src="app.js"></script>
<div id="stabilization"></div>
</body>
}
</script>
</body>
</html>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment