зеркало из https://github.com/mozilla/hubs.git
Get image rotation and rotate the resulting object accordingly.
This commit is contained in:
Родитель
55c991ee40
Коммит
5006510a48
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 19 KiB |
|
@ -13,6 +13,9 @@ AFRAME.registerComponent("offset-relative-to", {
|
|||
on: {
|
||||
type: "string"
|
||||
},
|
||||
orientation: {
|
||||
default: 1 // see doc/image_orientations.gif
|
||||
},
|
||||
selfDestruct: {
|
||||
default: false
|
||||
}
|
||||
|
@ -27,6 +30,9 @@ AFRAME.registerComponent("offset-relative-to", {
|
|||
},
|
||||
|
||||
updateOffset: (function() {
|
||||
const y = new THREE.Vector3(0, 1, 0);
|
||||
const z = new THREE.Vector3(0, 0, -1);
|
||||
const QUARTER_CIRCLE = Math.PI / 2;
|
||||
const offsetVector = new THREE.Vector3();
|
||||
return function() {
|
||||
const obj = this.el.object3D;
|
||||
|
@ -40,6 +46,38 @@ AFRAME.registerComponent("offset-relative-to", {
|
|||
this.el.body && this.el.body.position.copy(obj.position);
|
||||
target.getWorldQuaternion(obj.quaternion);
|
||||
this.el.body && this.el.body.quaternion.copy(obj.quaternion);
|
||||
|
||||
// See doc/image_orientations.gif
|
||||
switch (this.data.orientation) {
|
||||
case 8:
|
||||
obj.rotateOnAxis(z, 3 * QUARTER_CIRCLE);
|
||||
break;
|
||||
case 7:
|
||||
obj.rotateOnAxis(z, 3 * QUARTER_CIRCLE);
|
||||
obj.rotateOnAxis(y, 2 * QUARTER_CIRCLE);
|
||||
break;
|
||||
case 6:
|
||||
obj.rotateOnAxis(z, QUARTER_CIRCLE);
|
||||
break;
|
||||
case 5:
|
||||
obj.rotateOnAxis(z, QUARTER_CIRCLE);
|
||||
obj.rotateOnAxis(y, 2 * QUARTER_CIRCLE);
|
||||
break;
|
||||
case 4:
|
||||
obj.rotateOnAxis(z, 2 * QUARTER_CIRCLE);
|
||||
obj.rotateOnAxis(y, 2 * QUARTER_CIRCLE);
|
||||
break;
|
||||
case 3:
|
||||
obj.rotateOnAxis(z, 2 * QUARTER_CIRCLE);
|
||||
break;
|
||||
case 2:
|
||||
obj.rotateOnAxis(y, 2 * QUARTER_CIRCLE);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.data.selfDestruct) {
|
||||
if (this.data.on) {
|
||||
this.el.sceneEl.removeEventListener(this.data.on, this.updateOffset);
|
||||
|
|
|
@ -84,7 +84,7 @@ AFRAME.registerComponent("super-spawner", {
|
|||
const thisGrabId = nextGrabId++;
|
||||
this.heldEntities.set(hand, thisGrabId);
|
||||
|
||||
const entity = addMedia(this.data.src, ObjectContentOrigins.SPAWNER);
|
||||
const entity = addMedia(this.data.src, ObjectContentOrigins.SPAWNER).entity;
|
||||
entity.object3D.position.copy(
|
||||
this.data.useCustomSpawnPosition ? this.data.spawnPosition : this.el.object3D.position
|
||||
);
|
||||
|
|
11
src/hub.js
11
src/hub.js
|
@ -306,11 +306,14 @@ const onReady = async () => {
|
|||
|
||||
const offset = { x: 0, y: 0, z: -1.5 };
|
||||
const spawnMediaInfrontOfPlayer = (src, contentOrigin) => {
|
||||
const entity = addMedia(src, contentOrigin, true);
|
||||
const { entity, orientation } = addMedia(src, contentOrigin, true);
|
||||
|
||||
entity.setAttribute("offset-relative-to", {
|
||||
target: "#player-camera",
|
||||
offset
|
||||
orientation.then(or => {
|
||||
entity.setAttribute("offset-relative-to", {
|
||||
target: "#player-camera",
|
||||
offset,
|
||||
orientation: or
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ const BottomHUD = ({ onCreateObject, showImageOnlyButton, onMediaPicked }) => (
|
|||
|
||||
BottomHUD.propTypes = {
|
||||
onCreateObject: PropTypes.func,
|
||||
showImageOnlyButton: PropTypes.bool,
|
||||
onMediaPicked: PropTypes.func
|
||||
};
|
||||
|
||||
|
|
|
@ -51,6 +51,45 @@ export const upload = file => {
|
|||
}).then(r => r.json());
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/questions/7584794/accessing-jpeg-exif-rotation-data-in-javascript-on-the-client-side/32490603#32490603
|
||||
function getOrientation(file, callback) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const view = new DataView(e.target.result);
|
||||
if (view.getUint16(0, false) != 0xffd8) {
|
||||
return callback(-2);
|
||||
}
|
||||
const length = view.byteLength;
|
||||
let offset = 2;
|
||||
while (offset < length) {
|
||||
if (view.getUint16(offset + 2, false) <= 8) return callback(-1);
|
||||
const marker = view.getUint16(offset, false);
|
||||
offset += 2;
|
||||
if (marker == 0xffe1) {
|
||||
if (view.getUint32((offset += 2), false) != 0x45786966) {
|
||||
return callback(-1);
|
||||
}
|
||||
|
||||
const little = view.getUint16((offset += 6), false) == 0x4949;
|
||||
offset += view.getUint32(offset + 4, little);
|
||||
const tags = view.getUint16(offset, little);
|
||||
offset += 2;
|
||||
for (let i = 0; i < tags; i++) {
|
||||
if (view.getUint16(offset + i * 12, little) == 0x0112) {
|
||||
return callback(view.getUint16(offset + i * 12 + 8, little));
|
||||
}
|
||||
}
|
||||
} else if ((marker & 0xff00) != 0xff00) {
|
||||
break;
|
||||
} else {
|
||||
offset += view.getUint16(offset, false);
|
||||
}
|
||||
}
|
||||
return callback(-1);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
let interactableId = 0;
|
||||
export const addMedia = (src, contentOrigin, resize = false) => {
|
||||
const scene = AFRAME.scenes[0];
|
||||
|
@ -61,6 +100,15 @@ export const addMedia = (src, contentOrigin, resize = false) => {
|
|||
entity.setAttribute("media-loader", { resize, src: typeof src === "string" ? src : "" });
|
||||
scene.appendChild(entity);
|
||||
|
||||
const orientation = new Promise(function(resolve) {
|
||||
if (src instanceof File) {
|
||||
getOrientation(src, x => {
|
||||
resolve(x);
|
||||
});
|
||||
} else {
|
||||
resolve(1);
|
||||
}
|
||||
});
|
||||
if (src instanceof File) {
|
||||
upload(src)
|
||||
.then(response => {
|
||||
|
@ -78,5 +126,5 @@ export const addMedia = (src, contentOrigin, resize = false) => {
|
|||
scene.emit("object_spawned", { objectType });
|
||||
});
|
||||
|
||||
return entity;
|
||||
return { entity, orientation };
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче