Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
IR-1293 click to select mesh objects in scene edit mode (#10300)
Browse files Browse the repository at this point in the history
* enabling click to select in scene, fixing interactable issue from studio update

* adding fix to select the model component or gltf component ancestor of the selected mesh

* fixed the selection properly this time

* adding functionality for cycling clicks either to root model or sub-mesh of model

---------

Co-authored-by: Daniel Belmes <[email protected]>
  • Loading branch information
SamMazerIR and DanielBelmes authored May 31, 2024
1 parent e87e153 commit 7518068
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 23 deletions.
15 changes: 13 additions & 2 deletions packages/editor/src/systems/EditorControlSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ import { InputComponent } from '@etherealengine/spatial/src/input/components/Inp
import { InputSourceComponent } from '@etherealengine/spatial/src/input/components/InputSourceComponent'
import { InfiniteGridComponent } from '@etherealengine/spatial/src/renderer/components/InfiniteGridHelper'
import { RendererState } from '@etherealengine/spatial/src/renderer/RendererState'
import { EntityTreeComponent } from '@etherealengine/spatial/src/transform/components/EntityTree'
import {
EntityTreeComponent,
getAncestorWithComponent
} from '@etherealengine/spatial/src/transform/components/EntityTree'

import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent'
import { TransformGizmoControlComponent } from '../classes/TransformGizmoControlComponent'
import { TransformGizmoControlledComponent } from '../classes/TransformGizmoControlledComponent'
import { addMediaNode } from '../functions/addMediaNode'
Expand Down Expand Up @@ -292,7 +296,14 @@ const execute = () => {
clickedEntity = getComponent(clickedEntity, EntityTreeComponent).parentEntity!
}
if (hasComponent(clickedEntity, SourceComponent)) {
SelectionState.updateSelection([getComponent(clickedEntity, UUIDComponent)])
const modelComponent = getAncestorWithComponent(clickedEntity, ModelComponent)
const ancestorModelEntity = modelComponent || clickedEntity
SelectionState.updateSelection([
getComponent(
SelectionState.getSelectedEntities()[0] === ancestorModelEntity ? clickedEntity : ancestorModelEntity,
UUIDComponent
)
])
}
}
}
Expand Down
31 changes: 17 additions & 14 deletions packages/spatial/src/input/systems/ClientInputSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,10 @@ const execute = () => {
raycaster.set(inputRaycast.origin, inputRaycast.direction)
raycaster.layers.enable(ObjectLayers.Default)

const inputState = getState(InputState)
const isEditing = getState(EngineState).isEditing
// only heuristic is scene objects when in the editor
if (getState(EngineState).isEditing) {
if (isEditing) {
const pickerObj = gizmoPickerObjects() // gizmo heuristic
const inputObj = inputObjects()

Expand Down Expand Up @@ -277,7 +279,7 @@ const execute = () => {
intersectionData.add({ entity: hit.entity, distance: hit.distance })
}
}
const inputState = getState(InputState)

// 3rd heuristic is bboxes
for (const entity of inputState.inputBoundingBoxes) {
const boundingBox = getComponent(entity, BoundingBoxComponent)
Expand All @@ -286,19 +288,19 @@ const execute = () => {
intersectionData.add({ entity, distance: inputRay.origin.distanceTo(bboxHitTarget) })
}
}
}

// 4th heuristic is meshes
const objects = Array.from(inputState.inputMeshes) // gizmo heuristic
.filter((eid) => hasComponent(eid, GroupComponent))
.map((eid) => getComponent(eid, GroupComponent))
.flat()

const hits = raycaster.intersectObjects<Object3D>(objects, true)
for (const hit of hits) {
const parentObject = Object3DUtils.findAncestor(hit.object, (obj) => obj.entity != undefined)
if (parentObject) {
intersectionData.add({ entity: parentObject.entity, distance: hit.distance })
}
// 4th heuristic is meshes
const objects = (isEditing ? meshesQuery() : Array.from(inputState.inputMeshes)) // gizmo heuristic
.filter((eid) => hasComponent(eid, GroupComponent))
.map((eid) => getComponent(eid, GroupComponent))
.flat()

const hits = raycaster.intersectObjects<Object3D>(objects, true)
for (const hit of hits) {
const parentObject = Object3DUtils.findAncestor(hit.object, (obj) => obj.entity != undefined)
if (parentObject) {
intersectionData.add({ entity: parentObject.entity, distance: hit.distance })
}
}
}
Expand Down Expand Up @@ -672,6 +674,7 @@ const reactor = () => {
const MeshInputReactor = () => {
const entity = useEntityContext()
const shouldReceiveInput = !!useAncestorWithComponent(entity, InputComponent)

useImmediateEffect(() => {
const inputState = getState(InputState)
if (shouldReceiveInput) inputState.inputMeshes.add(entity)
Expand Down
28 changes: 25 additions & 3 deletions packages/ui/src/components/editor/properties/link/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,21 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
Ethereal Engine. All Rights Reserved.
*/

import React from 'react'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { PiLinkBreak } from 'react-icons/pi'

import { useComponent } from '@etherealengine/ecs'
import { getComponent, hasComponent, useComponent, UUIDComponent } from '@etherealengine/ecs'
import {
EditorComponentType,
commitProperty,
EditorComponentType,
updateProperty
} from '@etherealengine/editor/src/components/properties/Util'
import { EditorControlFunctions } from '@etherealengine/editor/src/functions/EditorControlFunctions'
import {
InteractableComponent,
XRUIActivationType
} from '@etherealengine/engine/src/interaction/components/InteractableComponent'
import { getEntityErrors } from '@etherealengine/engine/src/scene/components/ErrorComponent'
import { LinkComponent } from '@etherealengine/engine/src/scene/components/LinkComponent'
import BooleanInput from '../../input/Boolean'
Expand All @@ -49,6 +54,23 @@ export const LinkNodeEditor: EditorComponentType = (props) => {
const linkComponent = useComponent(props.entity, LinkComponent)
const errors = getEntityErrors(props.entity, LinkComponent)

useEffect(() => {
if (!hasComponent(props.entity, InteractableComponent)) {
EditorControlFunctions.addOrRemoveComponent([props.entity], InteractableComponent, true, {
label: LinkComponent.interactMessage,
uiInteractable: false,
clickInteract: true,
uiActivationType: XRUIActivationType.hover,
callbacks: [
{
callbackID: LinkComponent.linkCallbackName,
target: getComponent(props.entity, UUIDComponent)
}
]
})
}
}, [])

return (
<NodeEditor
{...props}
Expand Down
27 changes: 23 additions & 4 deletions packages/ui/src/components/editor/properties/mountPoint/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,21 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
Ethereal Engine. All Rights Reserved.
*/

import React from 'react'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'

import { useComponent } from '@etherealengine/ecs'
import { getComponent, getMutableComponent, hasComponent, useComponent, UUIDComponent } from '@etherealengine/ecs'
import InputGroup from '@etherealengine/editor/src/components/inputs/InputGroup'
import {
EditorComponentType,
commitProperty,
EditorComponentType,
updateProperty
} from '@etherealengine/editor/src/components/properties/Util'
import { EditorControlFunctions } from '@etherealengine/editor/src/functions/EditorControlFunctions'
import { InteractableComponent } from '@etherealengine/engine/src/interaction/components/InteractableComponent'
import { MountPoint, MountPointComponent } from '@etherealengine/engine/src/scene/components/MountPointComponent'
import { LuUsers2 } from 'react-icons/lu'
import { Vector3 } from 'three'
import SelectInput from '../../input/Select'
import Vector3Input from '../../input/Vector3'
import NodeEditor from '../nodeEditor'
Expand All @@ -48,7 +51,23 @@ export const MountPointNodeEditor: EditorComponentType = (props) => {
const { t } = useTranslation()

const mountComponent = useComponent(props.entity, MountPointComponent)

const onChangeOffset = (value: Vector3) => {
getMutableComponent(props.entity, MountPointComponent).dismountOffset.set(value)
}
useEffect(() => {
if (!hasComponent(props.entity, InteractableComponent)) {
const mountPoint = getComponent(props.entity, MountPointComponent)
EditorControlFunctions.addOrRemoveComponent([props.entity], InteractableComponent, true, {
label: MountPointComponent.mountPointInteractMessages[mountPoint.type],
callbacks: [
{
callbackID: MountPointComponent.mountCallbackName,
target: getComponent(props.entity, UUIDComponent)
}
]
})
}
}, [])
return (
<NodeEditor
{...props}
Expand Down

0 comments on commit 7518068

Please sign in to comment.