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

Transform Gizmo Refactor #1085

Merged
merged 40 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e310017
Adding GizmoSceneObject
Dhruv-0-Arora Aug 7, 2024
4fa1ccd
Working gizmosceneobject on mirabuf objects
Dhruv-0-Arora Aug 7, 2024
faea318
Fixed implementation of pickup but working on shot trajectory
Dhruv-0-Arora Aug 7, 2024
a2b9e63
Fixed Zone Config panel
Dhruv-0-Arora Aug 7, 2024
b2cfa39
Removed unused import
Dhruv-0-Arora Aug 7, 2024
8be2b6f
Fixed configuring shot trajectory panel
Dhruv-0-Arora Aug 7, 2024
10010b4
Cleanup
Dhruv-0-Arora Aug 7, 2024
bf9c086
Adding documentation
Dhruv-0-Arora Aug 7, 2024
0937d76
Added requested changes
Dhruv-0-Arora Aug 8, 2024
1b64d2b
Merge remote-tracking branch 'origin/dev' into dhruv/1798/refactoring…
Dhruv-0-Arora Aug 12, 2024
6d0bc2f
Merge remote-tracking branch 'origin/dev' into dhruv/1798/refactoring…
Dhruv-0-Arora Aug 12, 2024
6f5f2ab
Fixing more merge conflicts
Dhruv-0-Arora Aug 12, 2024
1e9dbcd
Merge remote-tracking branch 'origin/dev' into dhruv/1798/refactoring…
Dhruv-0-Arora Aug 21, 2024
9cd80ac
Renamed mesh to obj and added functional fixes
Dhruv-0-Arora Aug 21, 2024
3181c05
Fixed build errors
Dhruv-0-Arora Aug 21, 2024
ffdf3ff
Cleaned code
Dhruv-0-Arora Aug 22, 2024
03a9d3f
Merge remote-tracking branch 'origin/dev' into dhruv/1798/refactoring…
Dhruv-0-Arora Aug 22, 2024
980bf10
Adding requested changes to remove all translation code from the Mira…
Dhruv-0-Arora Aug 22, 2024
2f8c826
Added fix to zoneconfig + added map for all gizmos attached to mirabu…
Dhruv-0-Arora Aug 23, 2024
8f6c6d8
Merge branch 'dev' into dhruv/1798/refactoring-gizmos
HunterBarclay Sep 22, 2024
50f1ce3
Initial gizmo component progress
HunterBarclay Aug 30, 2024
47b9301
fix!: Locate the issue with using the transform gizmo component.
HunterBarclay Sep 16, 2024
6dbdc35
refactor: Migrate use of gizmo in config UI to new gizmo component.
HunterBarclay Sep 21, 2024
18b9383
refactor: Move input scheme selection into new component.
HunterBarclay Sep 22, 2024
8f4ded3
feat: Add initial config menu that includes gizmo controls.
HunterBarclay Sep 22, 2024
38495f7
feat: Add assembly moving to configuration, along with move panel.
HunterBarclay Sep 22, 2024
b2b648a
fix: Gizmo centers on selected assembly.
HunterBarclay Sep 22, 2024
ceaf33f
fix: Added new initial config panel to import local.
HunterBarclay Sep 22, 2024
269d333
fix: Move assemblies into the center of the field.
HunterBarclay Sep 22, 2024
b10ccc7
Format plus some syntax errors
HunterBarclay Sep 22, 2024
2fc64cc
fix: Extra semi-colons from prettier
HunterBarclay Sep 22, 2024
1177d0d
refactor: Use optional instead of union type.
HunterBarclay Sep 22, 2024
ec877bf
Remove if statement
HunterBarclay Sep 23, 2024
bcd59b9
fix: Make changes suggested by @PepperLola .
HunterBarclay Sep 23, 2024
306d807
Format
HunterBarclay Sep 23, 2024
633d20d
fix: Readd delete controls to buttons
HunterBarclay Oct 11, 2024
710bc8a
fix: Delete and confirm work as expected.
HunterBarclay Oct 11, 2024
fd519b3
feat(gizmos): Add escape and enter keys for gizmo
HunterBarclay Oct 14, 2024
e09be3c
chore: Format
HunterBarclay Oct 21, 2024
7cb3837
chore: Python type linting
HunterBarclay Oct 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 24 additions & 59 deletions fission/src/mirabuf/MirabufSceneObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import JOLT from "@/util/loading/JoltSyncLoader"
import { BodyAssociate, LayerReserve } from "@/systems/physics/PhysicsSystem"
import Mechanism from "@/systems/physics/Mechanism"
import InputSystem from "@/systems/input/InputSystem"
import TransformGizmos from "@/ui/components/TransformGizmos"
import { EjectorPreferences, FieldPreferences, IntakePreferences } from "@/systems/preferences/PreferenceTypes"
import PreferencesSystem from "@/systems/preferences/PreferencesSystem"
import { MiraType } from "./MirabufLoader"
Expand All @@ -21,6 +20,7 @@ import ScoringZoneSceneObject from "./ScoringZoneSceneObject"
import { SceneOverlayTag } from "@/ui/components/SceneOverlayEvents"
import { ProgressHandle } from "@/ui/components/ProgressNotificationData"
import SynthesisBrain from "@/systems/simulation/synthesis_brain/SynthesisBrain"
import GizmoSceneObject from "@/systems/scene/GizmoSceneObject"

const DEBUG_BODIES = false

Expand All @@ -38,8 +38,6 @@ class MirabufSceneObject extends SceneObject {
private _debugBodies: Map<string, RnDebugMeshes> | null
private _physicsLayerReserve: LayerReserve | undefined

private _transformGizmos: TransformGizmos | undefined

private _intakePreferences: IntakePreferences | undefined
private _ejectorPreferences: EjectorPreferences | undefined

Expand All @@ -49,6 +47,8 @@ class MirabufSceneObject extends SceneObject {
private _ejectable?: EjectableSceneObject
private _scoringZones: ScoringZoneSceneObject[] = []

private _gizmo: GizmoSceneObject | undefined
Copy link
Member

Choose a reason for hiding this comment

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

Since we've decided that only once gizmo will exist, this should be some kind of static either in the SceneRenderer or GizmoSceneObject itself.

Copy link
Member

Choose a reason for hiding this comment

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

I can think of a case where we would want more than one gizmo in a scene at a time. For instance, what about placing more than one robot during the initialization of match mode?

Copy link
Member

@HunterBarclay HunterBarclay Sep 27, 2024

Choose a reason for hiding this comment

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

Honestly, I think for initial robot placement, we should move away from using the gizmo tool altogether and move towards Luca's placement for bots for match mode in v6 where you can click and place. In which case, gizmo controls should be reserved for fine movement/orientation/scale control.


private _nameTag: SceneOverlayTag | undefined

get mirabufInstance() {
Expand Down Expand Up @@ -106,8 +106,6 @@ class MirabufSceneObject extends SceneObject {

this._debugBodies = null

this.EnableTransformControls() // adding transform gizmo to mirabuf object on its creation

this.getPreferences()

// creating nametag for robots
Expand Down Expand Up @@ -159,6 +157,17 @@ class MirabufSceneObject extends SceneObject {
this.UpdateIntakeSensor()

this.UpdateScoringZones()

// Adding a transform gizmo to the assembly when it spawns
this._gizmo = new GizmoSceneObject(
new THREE.Mesh(
new THREE.SphereGeometry(3.0),
new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 })
),
"translate",
3,
this
)
}

public Update(): void {
Expand All @@ -180,29 +189,6 @@ class MirabufSceneObject extends SceneObject {
meshes.forEach(([batch, id]) => batch.setMatrixAt(id, partTransform))
})

/**
* Update the position and rotation of the body to match the position of the transform gizmo.
*
* This block of code should only be executed if the transform gizmo exists.
*/
if (this._transformGizmos) {
if (InputSystem.isKeyPressed("Enter")) {
// confirming placement of the mirabuf object
this.DisableTransformControls()
return
} else if (InputSystem.isKeyPressed("Escape")) {
// cancelling the creation of the mirabuf scene object
World.SceneRenderer.RemoveSceneObject(this.id)
return
}

// if the gizmo is being dragged, copy the mesh position and rotation to the Mirabuf body
if (this._transformGizmos.isBeingDragged()) {
this._transformGizmos.UpdateMirabufPositioning(this, rn)
World.PhysicsSystem.DisablePhysicsForBody(this._mechanism.GetBodyByNodeId(rn.id)!)
}
}

if (isNaN(body.GetPosition().GetX())) {
const vel = body.GetLinearVelocity()
const pos = body.GetPosition()
Expand Down Expand Up @@ -243,6 +229,10 @@ class MirabufSceneObject extends SceneObject {
}

public Dispose(): void {
if (this._gizmo) {
World.SceneRenderer.RemoveSceneObject(this._gizmo.id)
}

if (this._intakeSensor) {
World.SceneRenderer.RemoveSceneObject(this._intakeSensor.id)
this._intakeSensor = undefined
Expand All @@ -261,7 +251,6 @@ class MirabufSceneObject extends SceneObject {
})

this._nameTag?.Dispose()
this.DisableTransformControls()
World.SimulationSystem.UnregisterMechanism(this._mechanism)
World.PhysicsSystem.DestroyMechanism(this._mechanism)
this._mirabufInstance.Dispose(World.SceneRenderer.scene)
Expand Down Expand Up @@ -371,34 +360,6 @@ class MirabufSceneObject extends SceneObject {
}
}

/**
* Changes the mode of the mirabuf object from being interacted with to being placed.
*/
public EnableTransformControls(): void {
if (this._transformGizmos) return

this._transformGizmos = new TransformGizmos(
new THREE.Mesh(
new THREE.SphereGeometry(3.0),
new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0 })
)
)
this._transformGizmos.AddMeshToScene()
this._transformGizmos.CreateGizmo("translate", 5.0)

this.DisablePhysics()
}

/**
* Changes the mode of the mirabuf object from being placed to being interacted with.
*/
public DisableTransformControls(): void {
if (!this._transformGizmos) return
this._transformGizmos?.RemoveGizmos()
this._transformGizmos = undefined
this.EnablePhysics()
}

/**
*
* @returns The bounding box of the mirabuf object.
Expand All @@ -419,13 +380,17 @@ class MirabufSceneObject extends SceneObject {
this._fieldPreferences = PreferencesSystem.getFieldPreferences(this.assemblyName)
}

private EnablePhysics() {
public RemoveGizmo() {
this._gizmo = undefined
}

public EnablePhysics() {
this._mirabufInstance.parser.rigidNodes.forEach(rn => {
World.PhysicsSystem.EnablePhysicsForBody(this._mechanism.GetBodyByNodeId(rn.id)!)
})
}

private DisablePhysics() {
public DisablePhysics() {
this._mirabufInstance.parser.rigidNodes.forEach(rn => {
World.PhysicsSystem.DisablePhysicsForBody(this._mechanism.GetBodyByNodeId(rn.id)!)
})
Expand Down
163 changes: 163 additions & 0 deletions fission/src/systems/scene/GizmoSceneObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import SceneObject from "./SceneObject"
import { TransformControls } from "three/examples/jsm/controls/TransformControls.js"
import InputSystem from "../input/InputSystem"
import World from "../World"
import MirabufSceneObject from "@/mirabuf/MirabufSceneObject"
import { PerspectiveCamera } from "three"
import { ThreeMatrix4_JoltMat44, ThreeQuaternion_JoltQuat } from "@/util/TypeConversions"

export type GizmoMode = "translate" | "rotate" | "scale"

class GizmoSceneObject extends SceneObject {
private _gizmo: TransformControls
private _mesh: THREE.Mesh
private _parentObject: MirabufSceneObject | undefined
HunterBarclay marked this conversation as resolved.
Show resolved Hide resolved

private _mainCamera: PerspectiveCamera

private _size: number

public get gizmo() {
return this._gizmo
}

public get mesh() {
return this._mesh
}

public constructor(mesh: THREE.Mesh, mode: GizmoMode, size: number, parentObject?: MirabufSceneObject) {
super()

this._mesh = mesh
this._parentObject = parentObject
this._mainCamera = World.SceneRenderer.mainCamera

this._size = size

this._gizmo = new TransformControls(World.SceneRenderer.mainCamera, World.SceneRenderer.renderer.domElement)
this._gizmo.setMode(mode)

World.SceneRenderer.RegisterSceneObject(this)
}

public Setup(): void {
// adding the mesh and gizmo to the scene
World.SceneRenderer.AddObject(this._mesh)
World.SceneRenderer.AddObject(this._gizmo)

// forcing the gizmo to rotate and transform with the object
this._gizmo.setSpace("local")
this._gizmo.attach(this._mesh)

this._gizmo.addEventListener("dragging-changed", (event: { target: TransformControls; value: unknown }) => {
// disable orbit controls when dragging the transform gizmo
const gizmoDragging = World.SceneRenderer.IsAnyGizmoDragging()
if (!event.value && !gizmoDragging) {
World.SceneRenderer.orbitControls.enabled = true // enable orbit controls when not dragging another transform gizmo
} else if (!event.value && gizmoDragging) {
World.SceneRenderer.orbitControls.enabled = false // disable orbit controls when dragging another transform gizmo
} else {
World.SceneRenderer.orbitControls.enabled = !event.value // disable orbit controls when dragging transform gizmo
}
HunterBarclay marked this conversation as resolved.
Show resolved Hide resolved

if (event.target.mode === "translate") {
// disable other gizmos when translating
Array.from(World.SceneRenderer.sceneObjects.values())
.filter(obj => obj instanceof GizmoSceneObject)
.forEach(obj => {
if (obj.gizmo.object === event.target.object && obj.gizmo.mode !== "translate") {
obj.gizmo.dragging = false
obj.gizmo.enabled = !event.value
return
}
})
Copy link
Member

Choose a reason for hiding this comment

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

Since you have the SceneRenderer._gizmosOnMirabuf map, you should no longer filter sceneObjects. In this case, you should make it so that you either make _gizmosOnMirabuf publicly available or have a method in SceneRenderer to test if some object has a gizmo (which would be as simple as this._gizmosOnMirabuf.has(mirabuf_id) from inside SceneRenderer).

As long as the mirabuf instance id that would be the key in gizmosOnMirabuf is available inside this function that I'm commenting on, you can then reduce this from O(n) to O(probably 1) since it would only require a Map lookup instead of an array filter and then foreach.

} else if (
event.target.mode === "scale" &&
(InputSystem.isKeyPressed("ShiftRight") || InputSystem.isKeyPressed("ShiftLeft"))
) {
// scale uniformly if shift is pressed
event.target.axis = "XYZE"
} else if (event.target.mode === "rotate") {
// scale on all axes
Array.from(World.SceneRenderer.sceneObjects.values())
.filter(obj => obj instanceof GizmoSceneObject)
.forEach(obj => {
if (
obj.gizmo.mode === "scale" &&
event.target !== obj.gizmo &&
obj.gizmo.object === event.target.object
) {
obj.gizmo.dragging = false
obj.gizmo.enabled = !event.value
return
}
})
Copy link
Member

Choose a reason for hiding this comment

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

Same thing here - use the _gizmosOnMirabuf map.

}
Copy link
Member

Choose a reason for hiding this comment

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

Would a switch be better here? I'm not sure if the if will be optimized, especially since you're checking inputs in one of the conditions.

})

if (this._parentObject !== undefined) this._parentObject.DisablePhysics()
}
public Update(): void {
// updating the size of the gizmo based on the distance from the camera
const mainCameraFovRadians = (Math.PI * (this._mainCamera.fov * 0.5)) / 180
this._gizmo.setSize(
(this._size / this._mainCamera.position.distanceTo(this.gizmo.object!.position)) *
Copy link
Member

Choose a reason for hiding this comment

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

Are we sure object is always going to be non-null?

Math.tan(mainCameraFovRadians) *
1.9
)

// mapping the mesh transformations to the mirabuf object
if (this._parentObject !== undefined) {
this._parentObject.DisablePhysics()

if (this._gizmo.dragging) {
this._parentObject.mirabufInstance.parser.rigidNodes.forEach(rn => {
World.PhysicsSystem.SetBodyPosition(
this._parentObject!.mechanism.GetBodyByNodeId(rn.id)!,
ThreeMatrix4_JoltMat44(this._mesh.matrix).GetTranslation()
)
World.PhysicsSystem.SetBodyRotation(
this._parentObject!.mechanism.GetBodyByNodeId(rn.id)!,
ThreeQuaternion_JoltQuat(this._mesh.quaternion)
)

rn.parts.forEach(part => {
const partTransform = this._parentObject!.mirabufInstance.parser.globalTransforms.get(part)!
.clone()
.premultiply(this._mesh.matrix)

const meshes = this._parentObject!.mirabufInstance.meshes.get(part) ?? []
meshes.forEach(([batch, id]) => batch.setMatrixAt(id, partTransform))
})
})
}
}

// creating enter key and escape key event listeners
if (InputSystem.isKeyPressed("Enter") && this._parentObject) {
// confirming placement of object
if (this._parentObject !== undefined) this._parentObject.EnablePhysics()
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (this._parentObject !== undefined) this._parentObject.EnablePhysics()
if (this._parentObject) this._parentObject.EnablePhysics()

I know this._parentObject can only be a MirabufSceneObject or undefined but I still prefer a truthiness check rather than checking if it's not exactly undefined. It doesn't really matter very much in this instance though.

World.SceneRenderer.RemoveSceneObject(this.id)
return
} else if (InputSystem.isKeyPressed("Escape") && this._parentObject) {
// cancelling the creation of the mirabuf scene object
World.SceneRenderer.RemoveSceneObject(this._parentObject.id)
World.SceneRenderer.RemoveSceneObject(this.id)
return
}
Copy link
Member

Choose a reason for hiding this comment

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

Should Dispose be called somewhere in here instead of one of these calls? I'm genuinely asking since I don't know the answer, it very well could be no.

}

public Dispose(): void {
this._gizmo.detach()
if (this._parentObject) this._parentObject.RemoveGizmo()
World.SceneRenderer.RemoveObject(this._mesh)
World.SceneRenderer.RemoveObject(this._gizmo)
}

/** changes the mode of the gizmo */
public SetMode(mode: GizmoMode) {
this._gizmo.setMode(mode)
}
}

export default GizmoSceneObject
Loading
Loading