Skip to content

Commit 4324d10

Browse files
authored
Merge pull request #6487 from mozilla/scene-grabbables
Scene grabbables support
2 parents 746413d + c23b7d4 commit 4324d10

28 files changed

+495
-141
lines changed

src/bit-components.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ export const Owned = defineComponent();
2121
export const EntityStateDirty = defineComponent();
2222
export const NetworkedMediaFrame = defineComponent({
2323
capturedNid: Types.ui32,
24-
scale: [Types.f32, 3]
24+
scale: [Types.f32, 3],
25+
flags: Types.ui8,
26+
mediaType: Types.ui8
2527
});
2628
NetworkedMediaFrame.capturedNid[$isStringType] = true;
2729

@@ -119,7 +121,11 @@ export const Rigidbody = defineComponent({
119121
activationState: Types.ui8,
120122
collisionFilterGroup: Types.ui32,
121123
collisionFilterMask: Types.ui32,
122-
flags: Types.ui8
124+
flags: Types.ui8,
125+
initialCollisionFilterMask: Types.ui32
126+
});
127+
export const NetworkedRigidBody = defineComponent({
128+
prevType: Types.ui8
123129
});
124130
export const PhysicsShape = defineComponent({
125131
bodyId: Types.ui16,

src/bit-systems/camera-tool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ function rotateWithRightClick(world, camera) {
211211
userinput.get(paths.device.mouse.buttonRight)
212212
) {
213213
const rightCursor = anyEntityWith(world, RemoteRight);
214-
physicsSystem.updateRigidBodyOptions(camera, { type: "kinematic" });
214+
physicsSystem.updateRigidBody(camera, { type: "kinematic" });
215215
transformSystem.startTransform(world.eid2obj.get(camera), world.eid2obj.get(rightCursor), {
216216
mode: "cursor"
217217
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { addComponent, defineQuery, enterQuery } from "bitecs";
2+
import { HubsWorld } from "../app";
3+
import { Holdable, MediaContentBounds, Networked, Rigidbody } from "../bit-components";
4+
import { getBox } from "../utils/auto-box-collider";
5+
import { Mesh, Vector3 } from "three";
6+
import { takeSoftOwnership } from "../utils/take-soft-ownership";
7+
import { EntityID } from "../utils/networking-types";
8+
import { COLLISION_LAYERS } from "../constants";
9+
10+
const tmpVector = new Vector3();
11+
12+
const interactableQuery = defineQuery([Holdable, Rigidbody, Networked]);
13+
const interactableEnterQuery = enterQuery(interactableQuery);
14+
export function interactableSystem(world: HubsWorld) {
15+
interactableEnterQuery(world).forEach((eid: EntityID) => {
16+
// Somebody must own a scene grabbable otherwise the networked transform will fight with physics.
17+
if (Networked.creator[eid] === APP.getSid("scene") && Networked.owner[eid] === APP.getSid("reticulum")) {
18+
takeSoftOwnership(world, eid);
19+
}
20+
21+
const obj = world.eid2obj.get(eid);
22+
let hasMesh = false;
23+
obj?.traverse(child => {
24+
if ((child as Mesh).isMesh) {
25+
hasMesh = true;
26+
}
27+
});
28+
29+
// If it has media frame collision mask, it needs to have content bounds
30+
if (hasMesh && Rigidbody.collisionFilterMask[eid] & COLLISION_LAYERS.MEDIA_FRAMES) {
31+
const box = getBox(obj, obj);
32+
if (!box.isEmpty()) {
33+
box.getSize(tmpVector);
34+
addComponent(world, MediaContentBounds, eid);
35+
MediaContentBounds.bounds[eid].set(tmpVector.toArray());
36+
} else {
37+
console.error(`Couldn't create content bounds for entity ${eid}. It seems to be empty or have negative scale.`);
38+
}
39+
}
40+
});
41+
}

src/bit-systems/media-loading.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ export function mediaLoadingSystem(world: HubsWorld) {
359359
jobs.add(eid, clearRollbacks => loadAndAnimateMedia(world, eid, clearRollbacks));
360360
});
361361

362-
mediaLoadingExitQuery(world).forEach(function (eid) {
362+
mediaLoadingExitQuery(world).forEach(function (eid: EntityID) {
363363
jobs.stop(eid);
364364

365365
if (MediaImageLoaderData.has(eid)) {
@@ -406,7 +406,7 @@ export function mediaLoadingSystem(world: HubsWorld) {
406406
}
407407
});
408408

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

420-
mediaRefreshEnterQuery(world).forEach(eid => {
420+
mediaRefreshEnterQuery(world).forEach((eid: EntityID) => {
421421
if (!jobs.has(eid)) {
422422
jobs.add(eid, clearRollbacks => refreshMedia(world, eid, clearRollbacks));
423423
}

src/bit-systems/object-menu.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ function startRotation(world: HubsWorld, menuEid: EntityID, targetEid: EntityID)
105105
}
106106
const transformSystem = APP.scene!.systems["transform-selected-object"];
107107
const physicsSystem = AFRAME.scenes[0].systems["hubs-systems"].physicsSystem;
108-
physicsSystem.updateRigidBodyOptions(Rigidbody.bodyId[targetEid], { type: "kinematic" });
108+
physicsSystem.updateRigidBody(Rigidbody.bodyId[targetEid], { type: "kinematic" });
109109
const rightCursorEid = anyEntityWith(world, RemoteRight)!;
110110
transformSystem.startTransform(world.eid2obj.get(targetEid)!, world.eid2obj.get(rightCursorEid)!, {
111111
mode: TRANSFORM_MODE.CURSOR
@@ -137,7 +137,7 @@ function startScaling(world: HubsWorld, menuEid: EntityID, targetEid: EntityID)
137137
// TODO: Remove the dependency with AFRAME
138138
const transformSystem = (AFRAME as any).scenes[0].systems["transform-selected-object"];
139139
const physicsSystem = AFRAME.scenes[0].systems["hubs-systems"].physicsSystem;
140-
physicsSystem.updateRigidBodyOptions(Rigidbody.bodyId[targetEid], { type: "kinematic" });
140+
physicsSystem.updateRigidBody(Rigidbody.bodyId[targetEid], { type: "kinematic" });
141141
const rightCursorEid = anyEntityWith(world, RemoteRight)!;
142142
scalingHandler = new ScalingHandler(world.eid2obj.get(targetEid), transformSystem);
143143
scalingHandler!.objectToScale = world.eid2obj.get(targetEid);

src/bit-systems/scene-loading.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
HeightFieldTag,
88
NavMesh,
99
Networked,
10-
PhysicsShape,
1110
SceneLoader,
1211
ScenePreviewCamera,
1312
SceneRoot,

src/components/body-helper.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { addComponent, removeComponent } from "bitecs";
22
import { CONSTANTS } from "three-ammo";
33
import { Rigidbody } from "../bit-components";
4+
import { updateBodyParams } from "../inflators/rigid-body";
45
const ACTIVATION_STATE = CONSTANTS.ACTIVATION_STATE,
56
TYPE = CONSTANTS.TYPE;
67

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

src/components/media-loader.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,10 @@ AFRAME.registerComponent("media-loader", {
284284

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

290292
el.emit("media-loaded");
291293
};

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export enum COLLISION_LAYERS {
1111
DEFAULT_INTERACTABLE = INTERACTABLES | ENVIRONMENT | AVATAR | HANDS | MEDIA_FRAMES,
1212
UNOWNED_INTERACTABLE = INTERACTABLES | HANDS | MEDIA_FRAMES,
1313
DEFAULT_SPAWNER = INTERACTABLES | HANDS
14-
};
14+
}
1515

1616
export enum AAModes {
1717
NONE = "NONE",

src/inflators/media-frame.js

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,28 @@ export const AxisAlignType = {
1515
};
1616

1717
export const MEDIA_FRAME_FLAGS = {
18-
SCALE_TO_BOUNDS: 1 << 0
18+
SCALE_TO_BOUNDS: 1 << 0,
19+
ACTIVE: 1 << 1,
20+
SNAP_TO_CENTER: 1 << 2,
21+
LOCKED: 1 << 3
22+
};
23+
24+
export const MediaTypes = {
25+
all: MediaType.ALL,
26+
"all-2d": MediaType.ALL_2D,
27+
model: MediaType.MODEL,
28+
image: MediaType.IMAGE,
29+
video: MediaType.VIDEO,
30+
pdf: MediaType.PDF
1931
};
2032

2133
const DEFAULTS = {
2234
bounds: { x: 1, y: 1, z: 1 },
2335
mediaType: "all",
2436
scaleToBounds: true,
25-
align: { x: "center", y: "center", z: "center" }
37+
align: { x: "center", y: "center", z: "center" },
38+
active: true,
39+
locked: false
2640
};
2741
export function inflateMediaFrame(world, eid, componentProps) {
2842
componentProps = Object.assign({}, DEFAULTS, componentProps);
@@ -68,17 +82,16 @@ export function inflateMediaFrame(world, eid, componentProps) {
6882
addComponent(world, MediaFrame, eid, true);
6983
addComponent(world, NetworkedMediaFrame, eid, true);
7084

85+
NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.ACTIVE;
86+
if (componentProps.snapToCenter) {
87+
NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.SNAP_TO_CENTER;
88+
}
89+
7190
if (!hasComponent(world, Networked, eid)) addComponent(world, Networked, eid);
7291

7392
// Media types accepted
74-
MediaFrame.mediaType[eid] = {
75-
all: MediaType.ALL,
76-
"all-2d": MediaType.ALL_2D,
77-
model: MediaType.MODEL,
78-
image: MediaType.IMAGE,
79-
video: MediaType.VIDEO,
80-
pdf: MediaType.PDF
81-
}[componentProps.mediaType];
93+
MediaFrame.mediaType[eid] = MediaTypes[componentProps.mediaType];
94+
NetworkedMediaFrame.mediaType[eid] = MediaFrame.mediaType[eid];
8295
// Bounds
8396
MediaFrame.bounds[eid].set([componentProps.bounds.x, componentProps.bounds.y, componentProps.bounds.z]);
8497
// Axis alignment
@@ -101,6 +114,15 @@ export function inflateMediaFrame(world, eid, componentProps) {
101114
if (componentProps.scaleToBounds) flags |= MEDIA_FRAME_FLAGS.SCALE_TO_BOUNDS;
102115
MediaFrame.flags[eid] = flags;
103116

117+
if (componentProps.active) {
118+
NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.ACTIVE;
119+
MediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.ACTIVE;
120+
}
121+
if (componentProps.locked) {
122+
NetworkedMediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.LOCKED;
123+
MediaFrame.flags[eid] |= MEDIA_FRAME_FLAGS.LOCKED;
124+
}
125+
104126
inflateRigidBody(world, eid, {
105127
type: Type.KINEMATIC,
106128
collisionGroup: COLLISION_LAYERS.MEDIA_FRAMES,

src/inflators/model.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,7 @@ function camelCase(s: string) {
1414
export type ModelParams = { model: Object3D };
1515

1616
// These components are all handled in some special way, not through inflators
17-
const ignoredComponents = [
18-
"visible",
19-
"frustum",
20-
"frustrum",
21-
"shadow",
22-
"networked",
23-
"animation-mixer",
24-
"loop-animation"
25-
];
17+
const ignoredComponents = ["visible", "frustum", "frustrum", "shadow", "animation-mixer", "loop-animation"];
2618

2719
function inflateComponents(
2820
world: HubsWorld,

0 commit comments

Comments
 (0)