Skip to content

Commit

Permalink
Merge pull request #6487 from mozilla/scene-grabbables
Browse files Browse the repository at this point in the history
Scene grabbables support
  • Loading branch information
keianhzo committed May 8, 2024
2 parents 746413d + c23b7d4 commit 4324d10
Show file tree
Hide file tree
Showing 28 changed files with 495 additions and 141 deletions.
10 changes: 8 additions & 2 deletions src/bit-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ export const Owned = defineComponent();
export const EntityStateDirty = defineComponent();
export const NetworkedMediaFrame = defineComponent({
capturedNid: Types.ui32,
scale: [Types.f32, 3]
scale: [Types.f32, 3],
flags: Types.ui8,
mediaType: Types.ui8
});
NetworkedMediaFrame.capturedNid[$isStringType] = true;

Expand Down Expand Up @@ -119,7 +121,11 @@ export const Rigidbody = defineComponent({
activationState: Types.ui8,
collisionFilterGroup: Types.ui32,
collisionFilterMask: Types.ui32,
flags: Types.ui8
flags: Types.ui8,
initialCollisionFilterMask: Types.ui32
});
export const NetworkedRigidBody = defineComponent({
prevType: Types.ui8
});
export const PhysicsShape = defineComponent({
bodyId: Types.ui16,
Expand Down
2 changes: 1 addition & 1 deletion src/bit-systems/camera-tool.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ function rotateWithRightClick(world, camera) {
userinput.get(paths.device.mouse.buttonRight)
) {
const rightCursor = anyEntityWith(world, RemoteRight);
physicsSystem.updateRigidBodyOptions(camera, { type: "kinematic" });
physicsSystem.updateRigidBody(camera, { type: "kinematic" });
transformSystem.startTransform(world.eid2obj.get(camera), world.eid2obj.get(rightCursor), {
mode: "cursor"
});
Expand Down
41 changes: 41 additions & 0 deletions src/bit-systems/interactable-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { addComponent, defineQuery, enterQuery } from "bitecs";
import { HubsWorld } from "../app";
import { Holdable, MediaContentBounds, Networked, Rigidbody } from "../bit-components";
import { getBox } from "../utils/auto-box-collider";
import { Mesh, Vector3 } from "three";
import { takeSoftOwnership } from "../utils/take-soft-ownership";
import { EntityID } from "../utils/networking-types";
import { COLLISION_LAYERS } from "../constants";

const tmpVector = new Vector3();

const interactableQuery = defineQuery([Holdable, Rigidbody, Networked]);
const interactableEnterQuery = enterQuery(interactableQuery);
export function interactableSystem(world: HubsWorld) {
interactableEnterQuery(world).forEach((eid: EntityID) => {
// Somebody must own a scene grabbable otherwise the networked transform will fight with physics.
if (Networked.creator[eid] === APP.getSid("scene") && Networked.owner[eid] === APP.getSid("reticulum")) {
takeSoftOwnership(world, eid);
}

const obj = world.eid2obj.get(eid);
let hasMesh = false;
obj?.traverse(child => {
if ((child as Mesh).isMesh) {
hasMesh = true;
}
});

// If it has media frame collision mask, it needs to have content bounds
if (hasMesh && Rigidbody.collisionFilterMask[eid] & COLLISION_LAYERS.MEDIA_FRAMES) {
const box = getBox(obj, obj);
if (!box.isEmpty()) {
box.getSize(tmpVector);
addComponent(world, MediaContentBounds, eid);
MediaContentBounds.bounds[eid].set(tmpVector.toArray());
} else {
console.error(`Couldn't create content bounds for entity ${eid}. It seems to be empty or have negative scale.`);
}
}
});
}
6 changes: 3 additions & 3 deletions src/bit-systems/media-loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ export function mediaLoadingSystem(world: HubsWorld) {
jobs.add(eid, clearRollbacks => loadAndAnimateMedia(world, eid, clearRollbacks));
});

mediaLoadingExitQuery(world).forEach(function (eid) {
mediaLoadingExitQuery(world).forEach(function (eid: EntityID) {
jobs.stop(eid);

if (MediaImageLoaderData.has(eid)) {
Expand Down Expand Up @@ -406,7 +406,7 @@ export function mediaLoadingSystem(world: HubsWorld) {
}
});

mediaLoadingQuery(world).forEach(eid => {
mediaLoadingQuery(world).forEach((eid: EntityID) => {
const mediaLoaderObj = world.eid2obj.get(eid)!;
transformPosition.fromArray(NetworkedTransform.position[eid]);
if (mediaLoaderObj.position.near(transformPosition, 0.001)) {
Expand All @@ -417,7 +417,7 @@ export function mediaLoadingSystem(world: HubsWorld) {
mediaLoadedEnterQuery(world).forEach(() => APP.scene?.emit("listed_media_changed"));
mediaLoadedExitQuery(world).forEach(() => APP.scene?.emit("listed_media_changed"));

mediaRefreshEnterQuery(world).forEach(eid => {
mediaRefreshEnterQuery(world).forEach((eid: EntityID) => {
if (!jobs.has(eid)) {
jobs.add(eid, clearRollbacks => refreshMedia(world, eid, clearRollbacks));
}
Expand Down
4 changes: 2 additions & 2 deletions src/bit-systems/object-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function startRotation(world: HubsWorld, menuEid: EntityID, targetEid: EntityID)
}
const transformSystem = APP.scene!.systems["transform-selected-object"];
const physicsSystem = AFRAME.scenes[0].systems["hubs-systems"].physicsSystem;
physicsSystem.updateRigidBodyOptions(Rigidbody.bodyId[targetEid], { type: "kinematic" });
physicsSystem.updateRigidBody(Rigidbody.bodyId[targetEid], { type: "kinematic" });
const rightCursorEid = anyEntityWith(world, RemoteRight)!;
transformSystem.startTransform(world.eid2obj.get(targetEid)!, world.eid2obj.get(rightCursorEid)!, {
mode: TRANSFORM_MODE.CURSOR
Expand Down Expand Up @@ -137,7 +137,7 @@ function startScaling(world: HubsWorld, menuEid: EntityID, targetEid: EntityID)
// TODO: Remove the dependency with AFRAME
const transformSystem = (AFRAME as any).scenes[0].systems["transform-selected-object"];
const physicsSystem = AFRAME.scenes[0].systems["hubs-systems"].physicsSystem;
physicsSystem.updateRigidBodyOptions(Rigidbody.bodyId[targetEid], { type: "kinematic" });
physicsSystem.updateRigidBody(Rigidbody.bodyId[targetEid], { type: "kinematic" });
const rightCursorEid = anyEntityWith(world, RemoteRight)!;
scalingHandler = new ScalingHandler(world.eid2obj.get(targetEid), transformSystem);
scalingHandler!.objectToScale = world.eid2obj.get(targetEid);
Expand Down
1 change: 0 additions & 1 deletion src/bit-systems/scene-loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
HeightFieldTag,
NavMesh,
Networked,
PhysicsShape,
SceneLoader,
ScenePreviewCamera,
SceneRoot,
Expand Down
2 changes: 2 additions & 0 deletions src/components/body-helper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { addComponent, removeComponent } from "bitecs";
import { CONSTANTS } from "three-ammo";
import { Rigidbody } from "../bit-components";
import { updateBodyParams } from "../inflators/rigid-body";
const ACTIVATION_STATE = CONSTANTS.ACTIVATION_STATE,
TYPE = CONSTANTS.TYPE;

Expand Down Expand Up @@ -41,6 +42,7 @@ AFRAME.registerComponent("body-helper", {
this.uuid = this.system.addBody(this.el.object3D, this.data);
const eid = this.el.object3D.eid;
addComponent(APP.world, Rigidbody, eid);
updateBodyParams(eid, this.data);
Rigidbody.bodyId[eid] = this.uuid; //uuid is a lie, it's actually an int
},

Expand Down
6 changes: 4 additions & 2 deletions src/components/media-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,10 @@ AFRAME.registerComponent("media-loader", {

// TODO this does duplicate work in some cases, but finish() is the only consistent place to do it
const contentBounds = getBox(this.el.object3D, this.el.getObject3D("mesh")).getSize(new THREE.Vector3());
addComponent(APP.world, MediaContentBounds, el.eid);
MediaContentBounds.bounds[el.eid].set(contentBounds.toArray());
if (el.eid) {
addComponent(APP.world, MediaContentBounds, el.eid);
MediaContentBounds.bounds[el.eid].set(contentBounds.toArray());
}

el.emit("media-loaded");
};
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export enum COLLISION_LAYERS {
DEFAULT_INTERACTABLE = INTERACTABLES | ENVIRONMENT | AVATAR | HANDS | MEDIA_FRAMES,
UNOWNED_INTERACTABLE = INTERACTABLES | HANDS | MEDIA_FRAMES,
DEFAULT_SPAWNER = INTERACTABLES | HANDS
};
}

export enum AAModes {
NONE = "NONE",
Expand Down
42 changes: 32 additions & 10 deletions src/inflators/media-frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,28 @@ export const AxisAlignType = {
};

export const MEDIA_FRAME_FLAGS = {
SCALE_TO_BOUNDS: 1 << 0
SCALE_TO_BOUNDS: 1 << 0,
ACTIVE: 1 << 1,
SNAP_TO_CENTER: 1 << 2,
LOCKED: 1 << 3
};

export const MediaTypes = {
all: MediaType.ALL,
"all-2d": MediaType.ALL_2D,
model: MediaType.MODEL,
image: MediaType.IMAGE,
video: MediaType.VIDEO,
pdf: MediaType.PDF
};

const DEFAULTS = {
bounds: { x: 1, y: 1, z: 1 },
mediaType: "all",
scaleToBounds: true,
align: { x: "center", y: "center", z: "center" }
align: { x: "center", y: "center", z: "center" },
active: true,
locked: false
};
export function inflateMediaFrame(world, eid, componentProps) {
componentProps = Object.assign({}, DEFAULTS, componentProps);
Expand Down Expand Up @@ -68,17 +82,16 @@ export function inflateMediaFrame(world, eid, componentProps) {
addComponent(world, MediaFrame, eid, true);
addComponent(world, NetworkedMediaFrame, eid, true);

NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.ACTIVE;
if (componentProps.snapToCenter) {
NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.SNAP_TO_CENTER;
}

if (!hasComponent(world, Networked, eid)) addComponent(world, Networked, eid);

// Media types accepted
MediaFrame.mediaType[eid] = {
all: MediaType.ALL,
"all-2d": MediaType.ALL_2D,
model: MediaType.MODEL,
image: MediaType.IMAGE,
video: MediaType.VIDEO,
pdf: MediaType.PDF
}[componentProps.mediaType];
MediaFrame.mediaType[eid] = MediaTypes[componentProps.mediaType];
NetworkedMediaFrame.mediaType[eid] = MediaFrame.mediaType[eid];
// Bounds
MediaFrame.bounds[eid].set([componentProps.bounds.x, componentProps.bounds.y, componentProps.bounds.z]);
// Axis alignment
Expand All @@ -101,6 +114,15 @@ export function inflateMediaFrame(world, eid, componentProps) {
if (componentProps.scaleToBounds) flags |= MEDIA_FRAME_FLAGS.SCALE_TO_BOUNDS;
MediaFrame.flags[eid] = flags;

if (componentProps.active) {
NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.ACTIVE;
MediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.ACTIVE;
}
if (componentProps.locked) {
NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.LOCKED;
MediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.LOCKED;
}

inflateRigidBody(world, eid, {
type: Type.KINEMATIC,
collisionGroup: COLLISION_LAYERS.MEDIA_FRAMES,
Expand Down
10 changes: 1 addition & 9 deletions src/inflators/model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,7 @@ function camelCase(s: string) {
export type ModelParams = { model: Object3D };

// These components are all handled in some special way, not through inflators
const ignoredComponents = [
"visible",
"frustum",
"frustrum",
"shadow",
"networked",
"animation-mixer",
"loop-animation"
];
const ignoredComponents = ["visible", "frustum", "frustrum", "shadow", "animation-mixer", "loop-animation"];

function inflateComponents(
world: HubsWorld,
Expand Down
Loading

0 comments on commit 4324d10

Please sign in to comment.