Skip to content

Commit

Permalink
Fix object menus transforms
Browse files Browse the repository at this point in the history
  • Loading branch information
keianhzo committed Sep 27, 2023
1 parent d2e86ef commit 64ffc11
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 134 deletions.
7 changes: 6 additions & 1 deletion src/bit-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ export const ObjectMenu = defineComponent({
rotateButtonRef: Types.eid,
mirrorButtonRef: Types.eid,
scaleButtonRef: Types.eid,
targetRef: Types.eid
targetRef: Types.eid,
handlingTargetRef: Types.eid,
flags: Types.ui8
});
// TODO: Store this data elsewhere, since only one or two will ever exist.
export const LinkHoverMenu = defineComponent({
Expand Down Expand Up @@ -381,3 +383,6 @@ export const LinearScale = defineComponent({
export const Quack = defineComponent();
export const TrimeshTag = defineComponent();
export const HeightFieldTag = defineComponent();
export const ObjectMenuTransform = defineComponent({
targetObjectRef: Types.eid
});
52 changes: 10 additions & 42 deletions src/bit-systems/link-hover-menu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Not, defineQuery, entityExists } from "bitecs";
import { Matrix4, Vector3 } from "three";
import { Not, addComponent, defineQuery, entityExists, removeComponent } from "bitecs";
import type { HubsWorld } from "../app";
import {
Link,
Expand All @@ -8,15 +7,15 @@ import {
TextTag,
Interacted,
LinkHoverMenuItem,
LinkInitializing
LinkInitializing,
ObjectMenuTransform
} from "../bit-components";
import { findAncestorWithComponent, findChildWithComponent } from "../utils/bit-utils";
import { hubIdFromUrl } from "../utils/media-url-utils";
import { Text as TroikaText } from "troika-three-text";
import { handleExitTo2DInterstitial } from "../utils/vr-interstitial";
import { changeHub } from "../change-hub";
import { EntityID } from "../utils/networking-types";
import { setMatrixWorld } from "../utils/three-utils";
import { LinkType } from "../inflators/link";

const menuQuery = defineQuery([LinkHoverMenu]);
Expand Down Expand Up @@ -89,43 +88,6 @@ async function handleLinkClick(world: HubsWorld, button: EntityID) {
}
}

const _moveTargetPos = new Vector3();
const _lookAtTargetPos = new Vector3();
const _objectPos = new Vector3();
const _mat4 = new Matrix4();

// Move the menu object to target object position but a little bit closer
// to the camera and make the menu object look at the camera.
// TODO: Similar code in object-menu system. Expose as util and reuse?
function moveToTarget(world: HubsWorld, menu: EntityID) {
const menuObj = world.eid2obj.get(menu)!;

const targetObj = world.eid2obj.get(LinkHoverMenu.targetObjectRef[menu])!;
targetObj.updateMatrices();

// TODO: Remove the dependency with AFRAME
const camera = AFRAME.scenes[0].systems["hubs-systems"].cameraSystem.viewingCamera;
camera.updateMatrices();

_moveTargetPos.setFromMatrixPosition(targetObj.matrixWorld);
_lookAtTargetPos.setFromMatrixPosition(camera.matrixWorld);

// Place the menu object a little bit closer to the camera in the scene
_objectPos
.copy(_lookAtTargetPos)
.sub(_moveTargetPos)
.normalize()
// TODO: 0.5 is an arbitrary number. 0.5 might be too small for
// huge target object. Using bounding box may be safer?
// TODO: What if camera is between the menu and the target object?
.multiplyScalar(0.5)
.add(_moveTargetPos);

_mat4.copy(camera.matrixWorld).setPosition(_objectPos);
setMatrixWorld(menuObj, _mat4);
menuObj.lookAt(_lookAtTargetPos);
}

function updateButtonText(world: HubsWorld, menu: EntityID, button: EntityID) {
const text = findChildWithComponent(world, TextTag, button)!;
const textObj = world.eid2obj.get(text)! as TroikaText;
Expand Down Expand Up @@ -157,6 +119,13 @@ function flushToObject3Ds(world: HubsWorld, menu: EntityID, frozen: boolean, for
const target = LinkHoverMenu.targetObjectRef[menu];
const visible = !!target && !frozen;

if (visible) {
addComponent(world, ObjectMenuTransform, menu);
ObjectMenuTransform.targetObjectRef[menu] = target;
} else {
removeComponent(world, ObjectMenuTransform, menu);
}

const obj = world.eid2obj.get(menu)!;
obj.visible = visible;

Expand All @@ -182,7 +151,6 @@ export function linkHoverMenuSystem(world: HubsWorld, sceneIsFrozen: boolean) {
updateLinkMenuTarget(world, menu, sceneIsFrozen);
const currTarget = LinkHoverMenu.targetObjectRef[menu];
if (currTarget) {
moveToTarget(world, menu);
clickedMenuItemQuery(world).forEach(eid => handleLinkClick(world, eid));
}
flushToObject3Ds(world, menu, sceneIsFrozen, prevTarget !== currTarget);
Expand Down
38 changes: 4 additions & 34 deletions src/bit-systems/media-loading.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { addComponent, defineQuery, enterQuery, exitQuery, hasComponent, removeComponent, removeEntity } from "bitecs";
import { Box3, Euler, Vector3 } from "three";
import { Box3, Vector3 } from "three";
import { HubsWorld } from "../app";
import {
GLTFModel,
Expand All @@ -17,7 +17,6 @@ import { ErrorObject } from "../prefabs/error-object";
import { LoadingObject } from "../prefabs/loading-object";
import { animate } from "../utils/animate";
import { setNetworkedDataWithoutRoot } from "../utils/assign-network-ids";
import { computeObjectAABB } from "../utils/auto-box-collider";
import { crClearTimeout, crNextFrame, crTimeout } from "../utils/coroutine";
import { ClearFunction, JobRunner, withRollback } from "../utils/coroutine-utils";
import { easeOutQuadratic } from "../utils/easing";
Expand All @@ -30,37 +29,7 @@ import { loadAudio } from "../utils/load-audio";
import { loadHtml } from "../utils/load-html";
import { MediaType, mediaTypeName, resolveMediaInfo } from "../utils/media-utils";
import { EntityID } from "../utils/networking-types";

const getBox = (() => {
const rotation = new Euler();
return (world: HubsWorld, eid: EntityID, rootEid: EntityID, worldSpace?: boolean) => {
const box = new Box3();
const obj = world.eid2obj.get(eid)!;
const rootObj = world.eid2obj.get(rootEid)!;

rotation.copy(obj.rotation);
obj.rotation.set(0, 0, 0);
obj.updateMatrices(true, true);
rootObj.updateMatrices(true, true);
rootObj.updateMatrixWorld(true);

computeObjectAABB(rootObj, box, false);

if (!box.isEmpty()) {
if (!worldSpace) {
obj.worldToLocal(box.min);
obj.worldToLocal(box.max);
}
obj.rotation.copy(rotation);
obj.matrixNeedsUpdate = true;
}

rootObj.matrixWorldNeedsUpdate = true;
rootObj.updateMatrices();

return box;
};
})();
import { getBox } from "../utils/three-utils";

export function* waitForMediaLoaded(world: HubsWorld, eid: EntityID) {
while (hasComponent(world, MediaLoader, eid)) {
Expand Down Expand Up @@ -234,6 +203,7 @@ function* loadMedia(world: HubsWorld, eid: EntityID) {
}

const tmpVector = new Vector3();
const box = new Box3();
function* loadAndAnimateMedia(world: HubsWorld, eid: EntityID, clearRollbacks: ClearFunction) {
if (MediaLoader.flags[eid] & MEDIA_LOADER_FLAGS.IS_OBJECT_MENU_TARGET) {
addComponent(world, ObjectMenuTarget, eid);
Expand All @@ -251,7 +221,7 @@ function* loadAndAnimateMedia(world: HubsWorld, eid: EntityID, clearRollbacks: C

if (media) {
if (hasComponent(world, MediaLoaded, media)) {
const box = getBox(world, eid, media);
getBox(world, eid, media, box);
addComponent(world, MediaContentBounds, eid);
box.getSize(tmpVector);
MediaContentBounds.bounds[eid].set(tmpVector.toArray());
Expand Down
49 changes: 49 additions & 0 deletions src/bit-systems/object-menu-transform-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { defineQuery } from "bitecs";
import { HubsWorld } from "../app";
import { ObjectMenuTransform } from "../bit-components";
import { EntityID } from "../utils/networking-types";
import { Box3, Matrix4, Quaternion, Sphere, Vector3 } from "three";
import { getBox, setMatrixWorld } from "../utils/three-utils";

const _vec3_1 = new Vector3();
const _vec3_2 = new Vector3();
const _quat = new Quaternion();
const _mat4 = new Matrix4();
const aabb = new Box3();
const sphere = new Sphere();

function moveToTarget(world: HubsWorld, menu: EntityID) {
const targetEid = ObjectMenuTransform.targetObjectRef[menu];
const targetObj = world.eid2obj.get(targetEid);
if (!targetObj) return;

getBox(world, targetEid, targetEid, aabb, true);
aabb.getBoundingSphere(sphere);

// Keeps world scale (1, 1, 1) because
// a menu object is a child of a target object
// and the target object's scale can be changed.
// Another option may be making the menu object
// a sibling of the target object.
_mat4.copy(targetObj.matrixWorld);
_mat4.decompose(_vec3_1, _quat, _vec3_2);
_vec3_2.set(1.0, 1.0, 1.0);
_mat4.compose(sphere.center, _quat, _vec3_2);

const menuObj = world.eid2obj.get(menu)!;
setMatrixWorld(menuObj, _mat4);

// TODO: Remove the dependency with AFRAME
const camera = AFRAME.scenes[0].systems["hubs-systems"].cameraSystem.viewingCamera;
camera.updateMatrices();
menuObj.lookAt(sphere.center.setFromMatrixPosition(camera.matrixWorld));
menuObj.translateZ(sphere.radius);
}

const menuQuery = defineQuery([ObjectMenuTransform]);

export function objectMenuTransformSystem(world: HubsWorld) {
menuQuery(world).forEach(menu => {
moveToTarget(world, menu);
});
}
Loading

0 comments on commit 64ffc11

Please sign in to comment.