diff --git a/src/components/auto-box-collider.js b/src/components/auto-box-collider.js index 139bb57fa94838ab79345aa387f13c07a305a837..2d3d2f53bbbd4cbe18a3f9fd1f19603badd8f907 100644 --- a/src/components/auto-box-collider.js +++ b/src/components/auto-box-collider.js @@ -11,8 +11,8 @@ AFRAME.registerComponent("auto-box-collider", { onLoaded() { this.el.removeEventListener("model-loaded", this.onLoaded); - const rotation = this.el.getAttribute("rotation"); - this.el.setAttribute("rotation", { x: 0, y: 0, z: 0 }); + const rotation = this.el.object3D.rotation.clone(); + this.el.object3D.rotation.set(0, 0, 0); const { min, max } = new THREE.Box3().setFromObject(this.el.object3DMap.mesh); const halfExtents = new THREE.Vector3() .addVectors(min.clone().negate(), max) @@ -25,7 +25,7 @@ AFRAME.registerComponent("auto-box-collider", { if (this.data.resize) { this.resize(min, max); } - this.el.setAttribute("rotation", rotation); + this.el.object3D.rotation.copy(rotation); this.el.removeAttribute("auto-box-collider"); }, diff --git a/src/components/auto-scale-cannon-physics-body.js b/src/components/auto-scale-cannon-physics-body.js index f5ae24b5bb906f623eb1ba52111583884d64ff87..e3ab60400e00f253e670736c2f94c44e301f4658 100644 --- a/src/components/auto-scale-cannon-physics-body.js +++ b/src/components/auto-scale-cannon-physics-body.js @@ -1,39 +1,27 @@ -function almostEquals(u, v, epsilon) { +function almostEquals(epsilon, u, v) { return Math.abs(u.x - v.x) < epsilon && Math.abs(u.y - v.y) < epsilon && Math.abs(u.z - v.z) < epsilon; } -function debounce(fn, delay) { - let timer = null; - return function() { - const args = arguments; - clearTimeout(timer); - timer = setTimeout(() => { - fn.apply(this, args); - }, delay); - }; -} - -const autoScaleCannonPhysicsBody = { +AFRAME.registerComponent("auto-scale-cannon-physics-body", { dependencies: ["body"], init() { this.body = this.el.components["body"]; this.prevScale = this.el.object3D.scale.clone(); - this.updateCannonScale = debounce(this.updateCannonScale.bind(this), 100); + this.nextUpdateTime = -1; }, - tick() { + tick(t) { const scale = this.el.object3D.scale; // Note: This only checks if the LOCAL scale of the object3D changes. - if (!almostEquals(scale, this.prevScale, 0.001)) { - this.updateCannonScale(); + if (!almostEquals(0.001, scale, this.prevScale)) { this.prevScale.copy(scale); + this.nextUpdateTime = t + 100; } - }, - updateCannonScale() { - this.body.updateCannonScale(); + if (this.nextUpdateTime > 0 && t > this.nextUpdateTime) { + this.nextUpdateTime = -1; + this.body.updateCannonScale(); + } } -}; - -AFRAME.registerComponent("auto-scale-cannon-physics-body", autoScaleCannonPhysicsBody); +}); diff --git a/src/components/offset-relative-to.js b/src/components/offset-relative-to.js index 3cd45b942ed4573ee9b588a467de456af801f62f..82a90717ba22137ac38e045a893804f60a183d3b 100644 --- a/src/components/offset-relative-to.js +++ b/src/components/offset-relative-to.js @@ -12,16 +12,38 @@ AFRAME.registerComponent("offset-relative-to", { }, on: { type: "string" + }, + selfDestruct: { + default: false } }, init() { - this.updateOffset(); - this.el.sceneEl.addEventListener(this.data.on, this.updateOffset.bind(this)); + this.updateOffset = this.updateOffset.bind(this); + if (this.data.on) { + this.el.sceneEl.addEventListener(this.data.on, this.updateOffset); + } else { + this.updateOffset(); + } }, - updateOffset() { - const offsetVector = new THREE.Vector3().copy(this.data.offset); - this.data.target.object3D.localToWorld(offsetVector); - this.el.setAttribute("position", offsetVector); - this.data.target.object3D.getWorldQuaternion(this.el.object3D.quaternion); - } + + updateOffset: (function() { + const offsetVector = new THREE.Vector3(); + return function() { + const obj = this.el.object3D; + const target = this.data.target.object3D; + offsetVector.copy(this.data.offset); + target.localToWorld(offsetVector); + if (obj.parent) { + obj.parent.worldToLocal(offsetVector); + } + obj.position.copy(offsetVector); + target.getWorldQuaternion(obj.quaternion); + if (this.data.selfDestruct) { + if (this.data.on) { + this.el.sceneEl.removeEventListener(this.data.on, this.updateOffset); + } + this.el.removeAttribute("offset-relative-to"); + } + }; + })() }); diff --git a/src/components/position-at-box-border.js b/src/components/position-at-box-border.js deleted file mode 100644 index 273bd1379b35c86edf64571058cc5fd7ec5c5cc2..0000000000000000000000000000000000000000 --- a/src/components/position-at-box-border.js +++ /dev/null @@ -1,64 +0,0 @@ -const PI = Math.PI; -const PI_HALF = PI / 2; -const THREE_PI_HALF = 3 * PI / 2; -const right = new THREE.Vector3(1, 0, 0); -const forward = new THREE.Vector3(0, 0, 1); -const left = new THREE.Vector3(-1, 0, 0); -const back = new THREE.Vector3(0, 0, -1); -const dirs = [left, right, forward, back]; -const rotations = [THREE_PI_HALF, PI_HALF, 0, PI]; - -AFRAME.registerComponent("position-at-box-border", { - schema: { - target: { type: "string" } - }, - - init() { - this.position = new THREE.Vector3(); - this.prevScale = new THREE.Vector3(-1, -1, -1); - this.cam = document.querySelector("[camera]").object3D; - this.camWorldPos = new THREE.Vector3(); - }, - - tick() { - if (!this.shape) { - this.shape = this.el.components["shape"]; - if (!this.shape) return; - } - if (!this.target) { - this.target = this.el.querySelector(this.data.target).object3D; - if (!this.target) return; - } - const halfExtents = this.shape.data.halfExtents; - const halfExtentDirs = [halfExtents.x, halfExtents.x, halfExtents.z, halfExtents.z]; - this.cam.getWorldPosition(this.camWorldPos); - - let minSquareDistance = Infinity; - const targetInfo = { - dir: dirs[0], - halfExtent: halfExtentDirs[0], - rotation: rotations[0] - }; - - for (let i = 0; i < dirs.length; i++) { - const dir = dirs[i]; - const pointOnBoxFace = dir.clone().multiplyScalar(halfExtentDirs[i]); - this.el.object3D.localToWorld(pointOnBoxFace); - const squareDistance = pointOnBoxFace.distanceToSquared(this.camWorldPos); - if (squareDistance < minSquareDistance) { - minSquareDistance = squareDistance; - targetInfo.dir = dir; - targetInfo.halfExtent = halfExtentDirs[i]; - targetInfo.rotation = rotations[i]; - } - } - - this.target.position.copy( - targetInfo.dir - .clone() - .multiplyScalar(targetInfo.halfExtent) - .add(this.shape.data.offset) - ); - this.target.rotation.set(0, targetInfo.rotation, 0); - } -}); diff --git a/src/components/position-at-box-shape-border.js b/src/components/position-at-box-shape-border.js new file mode 100644 index 0000000000000000000000000000000000000000..f85d744a9f532290dccc0dfc799e0959831e4d6c --- /dev/null +++ b/src/components/position-at-box-shape-border.js @@ -0,0 +1,65 @@ +const PI = Math.PI; +const HALF_PI = PI / 2; +const THREE_HALF_PI = 3 * PI / 2; +const rotations = [THREE_HALF_PI, HALF_PI, 0, PI]; +const right = new THREE.Vector3(1, 0, 0); +const forward = new THREE.Vector3(0, 0, 1); +const left = new THREE.Vector3(-1, 0, 0); +const back = new THREE.Vector3(0, 0, -1); +const dirs = [left, right, forward, back]; + +AFRAME.registerComponent("position-at-box-shape-border", { + schema: { + target: { type: "string" } + }, + + init() { + this.cam = this.el.sceneEl.camera.el.object3D; + }, + + tick: (function() { + const camWorldPos = new THREE.Vector3(); + const targetPosition = new THREE.Vector3(); + const pointOnBoxFace = new THREE.Vector3(); + return function() { + if (!this.shape) { + this.shape = this.el.components["shape"]; + if (!this.shape) return; + } + if (!this.target) { + this.target = this.el.querySelector(this.data.target).object3D; + if (!this.target) return; + } + const halfExtents = this.shape.data.halfExtents; + const halfExtentDirs = ["x", "x", "z", "z"]; + this.cam.getWorldPosition(camWorldPos); + + let minSquareDistance = Infinity; + let targetDir = dirs[0]; + let targetHalfExtent = halfExtents[halfExtentDirs[0]]; + let targetRotation = rotations[0]; + + for (let i = 0; i < dirs.length; i++) { + const dir = dirs[i]; + const halfExtent = halfExtents[halfExtentDirs[i]]; + pointOnBoxFace.copy(dir).multiplyScalar(halfExtent); + this.el.object3D.localToWorld(pointOnBoxFace); + const squareDistance = pointOnBoxFace.distanceToSquared(camWorldPos); + if (squareDistance < minSquareDistance) { + minSquareDistance = squareDistance; + targetDir = dir; + targetHalfExtent = halfExtent; + targetRotation = rotations[i]; + } + } + + this.target.position.copy( + targetPosition + .copy(targetDir) + .multiplyScalar(targetHalfExtent) + .add(this.shape.data.offset) + ); + this.target.rotation.set(0, targetRotation, 0); + }; + })() +}); diff --git a/src/components/reposition-relative-to-target.js b/src/components/reposition-relative-to-target.js deleted file mode 100644 index 760c48cac4d591827049d6c11a0d4bcd410b9ed0..0000000000000000000000000000000000000000 --- a/src/components/reposition-relative-to-target.js +++ /dev/null @@ -1,28 +0,0 @@ -AFRAME.registerComponent("reposition-relative-to-target", { - schema: { - on: { type: "string" }, - target: { type: "selector" }, - offset: { type: "vec3" } - }, - - init() { - this.reposition = this.reposition.bind(this); - if (this.data.on) { - this.el.addEventListener(this.data.on, this.reposition); - } else { - this.reposition(); - } - }, - - reposition() { - const obj = this.el.object3D; - const target = this.data.target.object3D; - const position = new THREE.Vector3().copy(this.data.offset); - target.localToWorld(position); - obj.position.copy(position); - target.getWorldQuaternion(obj.quaternion); - - this.el.removeEventListener(this.data.on, this.reposition); - this.el.removeAttribute("reposition-relative-to-target"); - } -}); diff --git a/src/hub.html b/src/hub.html index 4f49ab735d4b3f2ab6ef92450a3a994ab8cbd767..3d1eb594544eefa98ad90dbb0ce6b2a4566b1664 100644 --- a/src/hub.html +++ b/src/hub.html @@ -182,7 +182,7 @@ hoverable sticky-object="autoLockOnRelease: true; autoLockOnLoad: true;" auto-box-collider - position-at-box-border="target:.delete-button" + position-at-box-shape-border="target:.delete-button" auto-scale-cannon-physics-body > <a-entity class="delete-button" visible-while-frozen scale="0.08 0.08 0.08"> diff --git a/src/hub.js b/src/hub.js index 9f48626062c6047b6f187dcb31b1fb42ff53c8d8..5ff26a9e99466432ba9267c84a9d2631fa6e2ade 100644 --- a/src/hub.js +++ b/src/hub.js @@ -65,14 +65,13 @@ import "./components/scene-shadow"; import "./components/avatar-replay"; import "./components/image-plus"; import "./components/auto-box-collider"; -import "./components/reposition-relative-to-target"; import "./components/pinch-to-move"; import "./components/look-on-mobile"; import "./components/pitch-yaw-rotator"; import "./components/input-configurator"; import "./components/sticky-object"; import "./components/auto-scale-cannon-physics-body"; -import "./components/position-at-box-border"; +import "./components/position-at-box-shape-border"; import ReactDOM from "react-dom"; import React from "react"; @@ -308,10 +307,11 @@ const onReady = async () => { if (url.endsWith(".gltf") || url.endsWith(".glb")) { const model = document.createElement("a-entity"); model.id = "interactable-model-" + Date.now(); - model.setAttribute("reposition-relative-to-target", { + model.setAttribute("offset-relative-to", { on: "model-loaded", target: "#player-camera", - offset: offset + offset: offset, + selfDestruct: true }); model.setAttribute("gltf-model-plus", "src", url); model.setAttribute("auto-box-collider", { resize: true }); diff --git a/src/vendor/GLTFLoader.js b/src/vendor/GLTFLoader.js index 152ce341db5d3a52ef6cbd756eb4552bab7e982a..1df68673f4d773200f36899bba60be7b7c308a21 100644 --- a/src/vendor/GLTFLoader.js +++ b/src/vendor/GLTFLoader.js @@ -16,9 +16,7 @@ async function toFarsparkURL(url){ "Content-Type": "application/json" }, body: JSON.stringify({ - media: { - url: url - } + media: {url} }) }).then(r => r.json()); return mediaJson.images.raw; @@ -1817,11 +1815,12 @@ THREE.GLTFLoader = ( function () { var sourceURI = source.uri; var isObjectURL = false; - if ( source.bufferView !== undefined ) { + var hasBufferView = source.bufferView !== undefined; + if ( hasBufferView ) { // Load binary image data from bufferView, if provided. - sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) { + sourceURI = await parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) { isObjectURL = true; var blob = new Blob( [ bufferView ], { type: source.mimeType } ); @@ -1832,7 +1831,10 @@ THREE.GLTFLoader = ( function () { } - var farsparkURL = await toFarsparkURL(resolveURL(sourceURI, options.path)); + var urlToLoad = resolveURL(sourceURI, options.path); + if (!hasBufferView){ + urlToLoad = await toFarsparkURL(urlToLoad); + } return Promise.resolve( sourceURI ).then( function ( sourceURI ) { @@ -1842,7 +1844,7 @@ THREE.GLTFLoader = ( function () { return new Promise( function ( resolve, reject ) { - loader.load( farsparkURL, resolve, undefined, reject ); + loader.load( urlToLoad, resolve, undefined, reject ); } );