Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement rotate and scale button functions with bitecs #5993

Merged
merged 1 commit into from
May 11, 2023

Conversation

takahirox
Copy link
Contributor

@takahirox takahirox commented Mar 11, 2023

This commit adds the implementations of Object menu rotate and scale button functions.

Note that this commit focuses on making them just functional with minimal change.

The implementation relys on the old systems to save development time. It should be rewritten more elegantly to fit more to bitECS.

The main logic of src/components/scale-button is exposed to be reused from the new and old systems.

@takahirox
Copy link
Contributor Author

Ready for review.


AFRAME.registerComponent("scale-button", {
init() {
this.handler = new ScalingHandler(this.el.object3D, this.el.sceneEl.systems["transform-selected-object"]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with A-Frame component/system lifecycles. Is it safe to assume that transform-selected-object system is already registered here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

And if I'm right, system seems to be registered to sceneEl.systems when AFRAME.registerSystem is called (when a file is imported) while Component.init() seems to be called later (when the component first initialized?). So probably it is safe to assume here.

Copy link
Contributor

@keianhzo keianhzo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a few nits. The menu placement improvements can probably be addressed in a follow-up.

@@ -1,7 +1,15 @@
import { defineQuery, entityExists, hasComponent } from "bitecs";
import { Matrix4, Vector3 } from "three";
import { addComponent, defineQuery, enterQuery, entityExists, exitQuery, hasComponent } from "bitecs";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addComponent and path import are not used anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, updated.

const _mat4 = new Matrix4();

// TODO: Avoid any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't this be of type ScalingHandler?

let scalingHandler: ScalingHandler | null = null;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, updated.

@@ -39,10 +54,69 @@ function moveToTarget(world: HubsWorld, menu: EntityID) {
const targetObj = world.eid2obj.get(ObjectMenu.targetRef[menu])!;
targetObj.updateMatrices();

// TODO: position the menu more carefully...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably do this before removing the newLoader flag, the menu interesects with the objects pretty easily. We can do it in follow-up PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do it in follow-up PR.

Yes, that's the plan.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably just aim for roughly what we have now in terms of menu positioning, we still would like to ultimately not have these in world object menus in their current form on most platforms. On desktop and mobile we likely end up with more traditional 2d context menus, and in VR we likely don't need most of what the menus do since direct manipulation is perdurable (we still need to figure out what to do with the rest of the options)

}

// TODO: startRotation/Scaling() and stopRotation/Scaling() are
// temporarl implementation that rely on the old systems.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

temporarl -> temporary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, updated.

Comment on lines 86 to 87
// TODO: Don't use any
// TODO: Remove the dependency with AFRAME
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want avoid using any and avoid using the AFRAME symbol you can also use:

APP.scene!

and the add the type to the aframe.d.ts:

 interface TransformSelectedObjectSystem extends ASystem {
    startTransform(Object3D, EntityID, any): void;
    stopTransform(): void;
  }

  interface AScene extends AElement {
    object3D: Scene;
    renderStarted: boolean;
    renderer: WebGLRenderer;
    tick(time: number, delta: number): void;
    isPlaying: boolean;
    behaviors: {
      tick: AComponent[];
      tock: AComponent[];
    };
    systemNames: Array<keyof AScene["systems"]>;
    systems: {
      "hubs-systems": HubsSystems;
      "personal-space-bubble": PersonalSpaceBubbleSystem;
      "transform-selected-object": TransformSelectedObjectSystem;
      userinput: UserInputSystem;
      /** @deprecated see bit-interaction-system */
      interaction: InteractionSystem;
      nav: NavSystem;
    };
    emit(string, any?): void;
    addState(string): void;
    is(string): boolean;
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some other bitecs systems that have AFRAME dependency. I hope we will work on it when we remove the dependency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with Manuel that just adding the type to the aframe.d.ts would be nice. Its fairly minor either way but prevents from making some accidental mistakes leaking the any around.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, two developers suggested the same thing. And the change is minor. Updated.

Comment on lines 98 to 99
// TODO: Don't use any
// TODO: Remove the dependency with AFRAME
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

scalingHandler.startScaling(world.eid2obj.get(rightCursorEid));
}

function stopScaling(world: HubsWorld, targetEid: EntityID) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetEid doens't seem to be needed anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, updated.

@takahirox
Copy link
Contributor Author

This PR needs to be unlocked by the reviewers to get merged.

Copy link
Contributor

@netpro2k netpro2k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. Made a few comments but most are just observations or thoughts I had while reviewing and not really suggestions for changes.

@@ -39,10 +54,69 @@ function moveToTarget(world: HubsWorld, menu: EntityID) {
const targetObj = world.eid2obj.get(ObjectMenu.targetRef[menu])!;
targetObj.updateMatrices();

// TODO: position the menu more carefully...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably just aim for roughly what we have now in terms of menu positioning, we still would like to ultimately not have these in world object menus in their current form on most platforms. On desktop and mobile we likely end up with more traditional 2d context menus, and in VR we likely don't need most of what the menus do since direct manipulation is perdurable (we still need to figure out what to do with the rest of the options)

Comment on lines 86 to 87
// TODO: Don't use any
// TODO: Remove the dependency with AFRAME
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with Manuel that just adding the type to the aframe.d.ts would be nice. Its fairly minor either way but prevents from making some accidental mistakes leaking the any around.

// 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.updateBodyOptions(Rigidbody.bodyId[targetEid], { type: "kinematic" });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not something to address here but just to get it bouncing around in everyone's head. We change these physics properties pretty arbitrarily all over and its very easy for things to end up in weird states and to overwrite one system's desired physics settings with another. We need to think of how to manage that. It mostly comes about when something wants to set the position/rotation of a physics object since it must be kinematic or static to do so, but then it needs to be able to return to its previous state.

handleClicks(world, menu, hubChannel);

heldExitQuery(world).forEach(eid => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first thought would have been to do hasComponent(world, Held, ObjectMenu.rotateButtonRef[menuEid) comparison to the current transform system state.

Using quires is fine, and maybe its nice that the previous frame state is handled by the enter/exit queries but just noting. Not sure which I like better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can understand.

Using hasComponent(world, Held, ObjectMenu.rotateButtonRef[menuEid]) may be more efficient because Held component may be a common Component so heldQuery might include a way more entity ids than needed here.

But it required to manage previous frame state. I want to avoid to manage a previous frame state in a system for simplicity.

Using queries may be inefficient but we don't need to manually manage previous frame state so it is simpler.

I want to go as is for now. We may revisit later if we face performance problem.

@@ -198,6 +199,8 @@ function ScaleButton(props: Attrs) {
height={buttonHeight}
type={BUTTON_TYPES.ACTION}
text={"scale"}
holdable
holdableButton
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit weird to have to specify holdableButton on a Button3D should probably be handled in Button3D based on just holdable.

The disconnect between things being components and things just being properties to a JSX function here is definitely something I don't love, but its just how JSX works. Like here "height" is not a component nor is "text".

I think mixing components "holdable" and "holdableButton" into it makes it even more confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to remove holdableButton here.

if (!(NAF.utils.isMine(this.networkedEl) || NAF.utils.takeOwnership(this.networkedEl))) {
return;
}
startScaling(object3D) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is temporary transition code so it doesn't really matter much, but we might try to name this parameter a bit better. Maybe cursorObj? interactor?

}

function stopScaling(world: HubsWorld) {
const rightCursorEid = anyEntityWith(world, RemoteRight)!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a suggestion for here but reminds me of an observation I want us to think about.

I find it annoying that we don't have a good way to statically define references like this and have to "look them up" every frame with a query like this. Its not particularly expensive or anything, just silly because we actually know what number entity this is going to be every time. The only thing really stopping us from doing it is module loading order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love anyEntityWith(). Added this topic in the internal design document.

@takahirox takahirox force-pushed the BitECSRotateAndScaleButtons branch from a76fef2 to ee1eeed Compare May 11, 2023 21:58
This commit adds the implementations of Object menu
rotate and scale button functions.

Note that this commit focuses on making them just functional
with minimal change.

The implementation relys on the old systems to save
development time. It should be rewritten more elegantly to
fit more to bitECS.

The main logic of src/components/scale-button is exposed
to be reused from the new and old systems.
@takahirox takahirox force-pushed the BitECSRotateAndScaleButtons branch from ee1eeed to aa42562 Compare May 11, 2023 22:01
@takahirox takahirox merged commit b2136ea into master May 11, 2023
@takahirox takahirox deleted the BitECSRotateAndScaleButtons branch May 11, 2023 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants