aframe-extras
Version:
Add-ons and examples for A-Frame VR.
2 lines • 14.6 kB
JavaScript
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("THREE"));else if("function"==typeof define&&define.amd)define(["THREE"],e);else{var s="object"==typeof exports?e(require("THREE")):e(t.THREE);for(var n in s)("object"==typeof exports?exports:t)[n]=s[n]}}(self,(t=>(()=>{var e={570:(t,e,s)=>{"use strict";s.r(e),s.d(e,{Pathfinding:()=>a,PathfindingHelper:()=>h});var n=s(612);class r{static roundNumber(t,e){const s=Math.pow(10,e);return Math.round(t*s)/s}static sample(t){return t[Math.floor(Math.random()*t.length)]}static distanceToSquared(t,e){var s=t.x-e.x,n=t.y-e.y,r=t.z-e.z;return s*s+n*n+r*r}static isPointInPoly(t,e){for(var s=!1,n=-1,r=t.length,o=r-1;++n<r;o=n)(t[n].z<=e.z&&e.z<t[o].z||t[o].z<=e.z&&e.z<t[n].z)&&e.x<(t[o].x-t[n].x)*(e.z-t[n].z)/(t[o].z-t[n].z)+t[n].x&&(s=!s);return s}static isVectorInPolygon(t,e,s){var n=1e5,r=-1e5,o=[];return e.vertexIds.forEach((t=>{n=Math.min(s[t].y,n),r=Math.max(s[t].y,r),o.push(s[t])})),!!(t.y<r+.5&&t.y>n-.5&&this.isPointInPoly(o,t))}static triarea2(t,e,s){return(s.x-t.x)*(e.z-t.z)-(e.x-t.x)*(s.z-t.z)}static vequal(t,e){return this.distanceToSquared(t,e)<1e-5}static mergeVertices(t,e=1e-4){e=Math.max(e,Number.EPSILON);for(var s={},r=t.getIndex(),o=t.getAttribute("position"),i=r?r.count:o.count,a=0,h=[],c=[],u=Math.log10(1/e),l=Math.pow(10,u),d=0;d<i;d++){var p=r?r.getX(d):d,g="";g+=~~(o.getX(p)*l)+",",g+=~~(o.getY(p)*l)+",",(g+=~~(o.getZ(p)*l)+",")in s?h.push(s[g]):(c.push(o.getX(p)),c.push(o.getY(p)),c.push(o.getZ(p)),s[g]=a,h.push(a),a++)}const f=new n.BufferAttribute(new Float32Array(c),o.itemSize,o.normalized),v=new n.BufferGeometry;return v.setAttribute("position",f),v.setIndex(h),v}}class o{constructor(t){this.content=[],this.scoreFunction=t}push(t){this.content.push(t),this.sinkDown(this.content.length-1)}pop(){const t=this.content[0],e=this.content.pop();return this.content.length>0&&(this.content[0]=e,this.bubbleUp(0)),t}remove(t){const e=this.content.indexOf(t),s=this.content.pop();e!==this.content.length-1&&(this.content[e]=s,this.scoreFunction(s)<this.scoreFunction(t)?this.sinkDown(e):this.bubbleUp(e))}size(){return this.content.length}rescoreElement(t){this.sinkDown(this.content.indexOf(t))}sinkDown(t){const e=this.content[t];for(;t>0;){const s=(t+1>>1)-1,n=this.content[s];if(!(this.scoreFunction(e)<this.scoreFunction(n)))break;this.content[s]=e,this.content[t]=n,t=s}}bubbleUp(t){const e=this.content.length,s=this.content[t],n=this.scoreFunction(s);for(;;){const r=t+1<<1,o=r-1;let i,a=null;if(o<e&&(i=this.scoreFunction(this.content[o]),i<n&&(a=o)),r<e&&this.scoreFunction(this.content[r])<(null===a?n:i)&&(a=r),null===a)break;this.content[t]=this.content[a],this.content[a]=s,t=a}}}class i{constructor(){this.portals=[]}push(t,e){void 0===e&&(e=t),this.portals.push({left:t,right:e})}stringPull(){const t=this.portals,e=[];let s,n,o,i=0,a=0,h=0;s=t[0].left,n=t[0].left,o=t[0].right,e.push(s);for(let c=1;c<t.length;c++){const u=t[c].left,l=t[c].right;if(r.triarea2(s,o,l)<=0){if(!(r.vequal(s,o)||r.triarea2(s,n,l)>0)){e.push(n),s=n,i=a,n=s,o=s,a=i,h=i,c=i;continue}o=l,h=c}if(r.triarea2(s,n,u)>=0){if(!(r.vequal(s,n)||r.triarea2(s,o,u)<0)){e.push(o),s=o,i=h,n=s,o=s,a=i,h=i,c=i;continue}n=u,a=c}}return 0!==e.length&&r.vequal(e[e.length-1],t[t.length-1].left)||e.push(t[t.length-1].left),this.path=e,e}}class a{constructor(){this.zones={}}static createZone(t,e=1e-4){return class{static buildZone(t,e){const s=this._buildNavigationMesh(t,e),o={};s.vertices.forEach((t=>{t.x=r.roundNumber(t.x,2),t.y=r.roundNumber(t.y,2),t.z=r.roundNumber(t.z,2)})),o.vertices=s.vertices;const i=this._buildPolygonGroups(s);return o.groups=new Array(i.length),i.forEach(((t,e)=>{const s=new Map;t.forEach(((t,e)=>{s.set(t,e)}));const i=new Array(t.length);t.forEach(((t,e)=>{const a=[];t.neighbours.forEach((t=>a.push(s.get(t))));const h=[];t.neighbours.forEach((e=>h.push(this._getSharedVerticesInOrder(t,e))));const c=new n.Vector3(0,0,0);c.add(o.vertices[t.vertexIds[0]]),c.add(o.vertices[t.vertexIds[1]]),c.add(o.vertices[t.vertexIds[2]]),c.divideScalar(3),c.x=r.roundNumber(c.x,2),c.y=r.roundNumber(c.y,2),c.z=r.roundNumber(c.z,2),i[e]={id:e,neighbours:a,vertexIds:t.vertexIds,centroid:c,portals:h}})),o.groups[e]=i})),o}static _buildNavigationMesh(t,e){return t=r.mergeVertices(t,e),this._buildPolygonsFromGeometry(t)}static _spreadGroupId(t){let e=new Set([t]);for(;e.size>0;){const s=e;e=new Set,s.forEach((s=>{s.group=t.group,s.neighbours.forEach((t=>{void 0===t.group&&e.add(t)}))}))}}static _buildPolygonGroups(t){const e=[];return t.polygons.forEach((t=>{void 0!==t.group?e[t.group].push(t):(t.group=e.length,this._spreadGroupId(t),e.push([t]))})),e}static _buildPolygonNeighbours(t,e){const s=new Set,n=e[t.vertexIds[1]],r=e[t.vertexIds[2]];return e[t.vertexIds[0]].forEach((e=>{e!==t&&(n.includes(e)||r.includes(e))&&s.add(e)})),n.forEach((e=>{e!==t&&r.includes(e)&&s.add(e)})),s}static _buildPolygonsFromGeometry(t){const e=[],s=[],r=t.attributes.position,o=t.index,i=[];for(let t=0;t<r.count;t++)s.push((new n.Vector3).fromBufferAttribute(r,t)),i[t]=[];for(let s=0;s<t.index.count;s+=3){const t=o.getX(s),n=o.getX(s+1),r=o.getX(s+2),a={vertexIds:[t,n,r],neighbours:null};e.push(a),i[t].push(a),i[n].push(a),i[r].push(a)}return e.forEach((t=>{t.neighbours=this._buildPolygonNeighbours(t,i)})),{polygons:e,vertices:s}}static _getSharedVerticesInOrder(t,e){const s=t.vertexIds,n=s[0],r=s[1],o=s[2],i=e.vertexIds,a=i.includes(n),h=i.includes(r),c=i.includes(o);return a&&h&&c?Array.from(s):a&&h?[n,r]:h&&c?[r,o]:a&&c?[o,n]:(console.warn("Error processing navigation mesh neighbors; neighbors with <2 shared vertices found."),[])}}.buildZone(t,e)}setZoneData(t,e){this.zones[t]=e}getRandomNode(t,e,s,o){if(!this.zones[t])return new n.Vector3;s=s||null,o=o||0;const i=[];return this.zones[t].groups[e].forEach((t=>{s&&o?r.distanceToSquared(s,t.centroid)<o*o&&i.push(t.centroid):i.push(t.centroid)})),r.sample(i)||new n.Vector3}getClosestNode(t,e,s,n=!1){const o=this.zones[e].vertices;let i=null,a=1/0;return this.zones[e].groups[s].forEach((e=>{const s=r.distanceToSquared(e.centroid,t);s<a&&(!n||r.isVectorInPolygon(t,e,o))&&(i=e,a=s)})),i}findPath(t,e,s,a){const h=this.zones[s].groups[a],c=this.zones[s].vertices,u=this.getClosestNode(t,s,a,!0),l=this.getClosestNode(e,s,a,!0);if(!u||!l)return null;const d=class{static init(t){for(let e=0;e<t.length;e++){const s=t[e];s.f=0,s.g=0,s.h=0,s.cost=1,s.visited=!1,s.closed=!1,s.parent=null}}static cleanUp(t){for(let e=0;e<t.length;e++){const s=t[e];delete s.f,delete s.g,delete s.h,delete s.cost,delete s.visited,delete s.closed,delete s.parent}}static heap(){return new o((function(t){return t.f}))}static search(t,e,s){this.init(t);const n=this.heap();for(n.push(e);n.size()>0;){const e=n.pop();if(e===s){let t=e;const s=[];for(;t.parent;)s.push(t),t=t.parent;return this.cleanUp(s),s.reverse()}e.closed=!0;const r=this.neighbours(t,e);for(let t=0,o=r.length;t<o;t++){const o=r[t];if(o.closed)continue;const i=e.g+o.cost,a=o.visited;if(!a||i<o.g){if(o.visited=!0,o.parent=e,!o.centroid||!s.centroid)throw new Error("Unexpected state");o.h=o.h||this.heuristic(o.centroid,s.centroid),o.g=i,o.f=o.g+o.h,a?n.rescoreElement(o):n.push(o)}}}return[]}static heuristic(t,e){return r.distanceToSquared(t,e)}static neighbours(t,e){const s=[];for(let n=0;n<e.neighbours.length;n++)s.push(t[e.neighbours[n]]);return s}}.search(h,u,l),p=function(t,e){for(var s=0;s<t.neighbours.length;s++)if(t.neighbours[s]===e.id)return t.portals[s]},g=new i;g.push(t);for(let t=0;t<d.length;t++){const e=d[t],s=d[t+1];if(s){const t=p(e,s);g.push(c[t[0]],c[t[1]])}}g.push(e),g.stringPull();const f=g.path.map((t=>new n.Vector3(t.x,t.y,t.z)));return f.shift(),f}}a.prototype.getGroup=function(){const t=new n.Plane;return function(e,s,n=!1){if(!this.zones[e])return null;let o=null,i=Math.pow(50,2);const a=this.zones[e];for(let e=0;e<a.groups.length;e++){const h=a.groups[e];for(const c of h){if(n&&(t.setFromCoplanarPoints(a.vertices[c.vertexIds[0]],a.vertices[c.vertexIds[1]],a.vertices[c.vertexIds[2]]),Math.abs(t.distanceToPoint(s))<.01)&&r.isPointInPoly([a.vertices[c.vertexIds[0]],a.vertices[c.vertexIds[1]],a.vertices[c.vertexIds[2]]],s))return e;const h=r.distanceToSquared(c.centroid,s);h<i&&(o=e,i=h)}}return o}}(),a.prototype.clampStep=function(){const t=new n.Vector3,e=new n.Plane,s=new n.Triangle,r=new n.Vector3;let o,i,a=new n.Vector3;return function(n,h,c,u,l,d){const p=this.zones[u].vertices,g=this.zones[u].groups[l],f=[c],v={};v[c.id]=0,o=void 0,a.set(0,0,0),i=1/0,e.setFromCoplanarPoints(p[c.vertexIds[0]],p[c.vertexIds[1]],p[c.vertexIds[2]]),e.projectPoint(h,t),r.copy(t);for(let e=f.pop();e;e=f.pop()){s.set(p[e.vertexIds[0]],p[e.vertexIds[1]],p[e.vertexIds[2]]),s.closestPointToPoint(r,t),t.distanceToSquared(r)<i&&(o=e,a.copy(t),i=t.distanceToSquared(r));const n=v[e.id];if(!(n>2))for(let t=0;t<e.neighbours.length;t++){const s=g[e.neighbours[t]];s.id in v||(f.push(s),v[s.id]=n+1)}}return d.copy(a),o}}();class h extends n.Object3D{constructor(){super(),this._playerMarker=new n.Mesh(new n.SphereGeometry(.25,32,32),new n.MeshBasicMaterial({color:15631215})),this._targetMarker=new n.Mesh(new n.BoxGeometry(.3,.3,.3),new n.MeshBasicMaterial({color:14469912})),this._nodeMarker=new n.Mesh(new n.BoxGeometry(.1,.8,.1),new n.MeshBasicMaterial({color:4417387})),this._stepMarker=new n.Mesh(new n.BoxGeometry(.1,1,.1),new n.MeshBasicMaterial({color:14472114})),this._pathMarker=new n.Object3D,this._pathLineMaterial=new n.LineBasicMaterial({color:41903,linewidth:2}),this._pathPointMaterial=new n.MeshBasicMaterial({color:41903}),this._pathPointGeometry=new n.SphereGeometry(.08),this._markers=[this._playerMarker,this._targetMarker,this._nodeMarker,this._stepMarker,this._pathMarker],this._markers.forEach((t=>{t.visible=!1,this.add(t)}))}setPath(t){for(;this._pathMarker.children.length;)this._pathMarker.children[0].visible=!1,this._pathMarker.remove(this._pathMarker.children[0]);t=[this._playerMarker.position].concat(t);const e=new n.BufferGeometry;e.setAttribute("position",new n.BufferAttribute(new Float32Array(3*t.length),3));for(let s=0;s<t.length;s++)e.attributes.position.setXYZ(s,t[s].x,t[s].y+.2,t[s].z);this._pathMarker.add(new n.Line(e,this._pathLineMaterial));for(let e=0;e<t.length-1;e++){const s=new n.Mesh(this._pathPointGeometry,this._pathPointMaterial);s.position.copy(t[e]),s.position.y+=.2,this._pathMarker.add(s)}return this._pathMarker.visible=!0,this}setPlayerPosition(t){return this._playerMarker.position.copy(t),this._playerMarker.visible=!0,this}setTargetPosition(t){return this._targetMarker.position.copy(t),this._targetMarker.visible=!0,this}setNodePosition(t){return this._nodeMarker.position.copy(t),this._nodeMarker.visible=!0,this}setStepPosition(t){return this._stepMarker.position.copy(t),this._stepMarker.visible=!0,this}reset(){for(;this._pathMarker.children.length;)this._pathMarker.children[0].visible=!1,this._pathMarker.remove(this._pathMarker.children[0]);return this._markers.forEach((t=>{t.visible=!1})),this}}},982:t=>{t.exports=AFRAME.registerComponent("nav-agent",{schema:{destination:{type:"vec3"},active:{default:!1},speed:{default:2}},init:function(){this.system=this.el.sceneEl.systems.nav,this.system.addAgent(this),this.group=null,this.path=[],this.raycaster=new THREE.Raycaster},remove:function(){this.system.removeAgent(this)},update:function(){this.path.length=0},updateNavLocation:function(){this.group=null,this.path=[]},tick:function(){const t=new THREE.Vector3,e=new THREE.Vector3,s=new THREE.Vector3;return function(n,r){const o=this.el,i=this.data,a=this.raycaster,h=i.speed*r/1e3;if(!i.active)return;if(!this.path.length){const e=this.el.object3D.position;this.group=this.group||this.system.getGroup(e),this.path=this.system.getPath(e,t.copy(i.destination),this.group)||[],o.emit("navigation-start")}if(!this.path.length)return console.warn("[nav] Unable to find path to %o.",i.destination),this.el.setAttribute("nav-agent",{active:!1}),void o.emit("navigation-end");const c=o.object3D.position,u=this.path[0];let l;if(e.subVectors(u,c),e.length()<h){if(this.path.shift(),!this.path.length)return this.el.setAttribute("nav-agent",{active:!1}),void o.emit("navigation-end");s.copy(c),l=this.path[0]}else s.copy(e.setLength(h)).add(c),l=u;l.y=c.y,o.object3D.lookAt(l),a.ray.origin.copy(s),a.ray.origin.y+=1.5,a.ray.direction={x:0,y:-1,z:0};const d=a.intersectObject(this.system.getNavMesh());d.length?(e.subVectors(d[0].point,c),c.add(e.setLength(h))):c.copy(s)}}()})},866:t=>{t.exports=AFRAME.registerComponent("nav-mesh",{schema:{nodeName:{type:"string"}},init:function(){this.system=this.el.sceneEl.systems.nav,this.hasLoadedNavMesh=!1,this.nodeName=this.data.nodeName,this.el.addEventListener("object3dset",this.loadNavMesh.bind(this))},play:function(){this.hasLoadedNavMesh||this.loadNavMesh()},loadNavMesh:function(){var t=this;const e=this.el.getObject3D("mesh");if(this.el.sceneEl.object3D,!e)return;let s;if(e.traverse((e=>{!e.isMesh||t.nodeName&&e.name!==t.nodeName||(s=e)})),!s)return;const n=s.geometry.clone();s.updateWorldMatrix(!0,!1),n.applyMatrix4(s.matrixWorld),this.system.setNavMeshGeometry(n),this.hasLoadedNavMesh=!0}})},214:(t,e,s)=>{const{Pathfinding:n}=s(570),r=new n,o="level";t.exports=AFRAME.registerSystem("nav",{init:function(){this.navMesh=null,this.agents=new Set},setNavMeshGeometry:function(t){this.navMesh=new THREE.Mesh(t),r.setZoneData(o,n.createZone(t)),Array.from(this.agents).forEach((t=>t.updateNavLocation()))},getNavMesh:function(){return this.navMesh},addAgent:function(t){this.agents.add(t)},removeAgent:function(t){this.agents.delete(t)},getPath:function(t,e,s){return this.navMesh?r.findPath(t,e,o,s):null},getGroup:function(t){return this.navMesh?r.getGroup(o,t):null},getNode:function(t,e){return this.navMesh?r.getClosestNode(t,o,e,!0):null},clampStep:function(t,e,s,n,i){return this.navMesh?n?r.clampStep(t,e,n,o,s,i):(i.copy(e),this.getNode(e,s)):(i.copy(e),null)}})},612:e=>{"use strict";e.exports=t}},s={};function n(t){var r=s[t];if(void 0!==r)return r.exports;var o=s[t]={exports:{}};return e[t](o,o.exports,n),o.exports}return n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var s in e)n.o(e,s)&&!n.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:e[s]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n(866),n(982),n(214),{}})()));
//# sourceMappingURL=aframe-extras.pathfinding.min.js.map