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

Commit

Permalink
Highlight Effect Refactor (#8274)
Browse files Browse the repository at this point in the history
* add highlight option to input component

* finalize highlight input for editor and post processing schema

* tweak reactors

* update editor
  • Loading branch information
HexaField authored Jul 13, 2023
1 parent 57f82ae commit 2df35fb
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 165 deletions.
3 changes: 1 addition & 2 deletions packages/client-core/src/world/startClientSystems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import { EntityNetworkStateSystem } from '@etherealengine/engine/src/networking/
import { IncomingNetworkSystem } from '@etherealengine/engine/src/networking/systems/IncomingNetworkSystem'
import { OutgoingNetworkSystem } from '@etherealengine/engine/src/networking/systems/OutgoingNetworkSystem'
import { PhysicsSystem } from '@etherealengine/engine/src/physics/systems/PhysicsSystem'
import { HighlightSystem } from '@etherealengine/engine/src/renderer/HighlightSystem'
import { WebGLRendererSystem } from '@etherealengine/engine/src/renderer/WebGLRendererSystem'
import { SceneSystemLoadGroup, SceneSystemUpdateGroup } from '@etherealengine/engine/src/scene/SceneClientModule'
import { PortalSystem } from '@etherealengine/engine/src/scene/systems/PortalSystem'
Expand Down Expand Up @@ -88,7 +87,7 @@ export const startClientSystems = () => {
startSystems([XRUISystem, InteractiveSystem, MediaControlSystem], { before: TransformSystem })

/** Post Transform / Pre Render */
startSystems([HighlightSystem, MediaSystem, DebugRendererSystem, SceneSystemUpdateGroup], {
startSystems([MediaSystem, DebugRendererSystem, SceneSystemUpdateGroup], {
before: PresentationSystemGroup
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,6 @@ type EffectPropertiesType = { [key: string]: EffectPropertyDetail }
type EffectOptionsType = { [key in keyof typeof Effects]: EffectPropertiesType }

const EffectsOptions: EffectOptionsType = {
// FXAAEffect: {
// blendFunction: { propertyType: PropertyTypes.BlendFunction, name: 'Blend Function' }
// },
SMAAEffect: {
blendFunction: { propertyType: PropertyTypes.BlendFunction, name: 'Blend Function' },
preset: { propertyType: PropertyTypes.SMAAPreset, name: 'Preset' },
edgeDetectionMode: { propertyType: PropertyTypes.EdgeDetectionMode, name: 'Edge Detection Mode' },
predicationMode: { propertyType: PropertyTypes.PredicationMode, name: 'Predication Mode' }
},
OutlineEffect: {
blendFunction: { propertyType: PropertyTypes.BlendFunction, name: 'Blend Function' },
edgeStrength: { propertyType: PropertyTypes.Number, name: 'Edge Strength', min: -1, max: 1, step: 0.01 },
pulseSpeed: { propertyType: PropertyTypes.Number, name: 'Pulse Speed', min: -1, max: 1, step: 0.01 },
visibleEdgeColor: { propertyType: PropertyTypes.Color, name: 'Visible Edge Color' },
hiddenEdgeColor: { propertyType: PropertyTypes.Color, name: 'Hidden Edge Color' },
resolutionScale: { propertyType: PropertyTypes.Number, name: 'Resolution Scale', min: -1, max: 1, step: 0.01 },
kernelSize: { propertyType: PropertyTypes.KernelSize, name: 'Kernel Size' },
blur: { propertyType: PropertyTypes.Boolean, name: 'Blur' },
xRay: { propertyType: PropertyTypes.Boolean, name: 'XRay' }
},
SSAOEffect: {
blendFunction: { propertyType: PropertyTypes.BlendFunction, name: 'Blend Function' },
distanceScaling: { propertyType: PropertyTypes.Boolean, name: 'Distance Scaling' },
Expand Down
58 changes: 0 additions & 58 deletions packages/editor/src/functions/updateOutlinePassSelection.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/editor/src/services/SelectionServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import { defineAction, defineActionQueue, defineState, getMutableState } from '@

import { cancelGrabOrPlacement } from '../functions/cancelGrabOrPlacement'
import { filterParentEntities } from '../functions/filterParentEntities'
import { updateOutlinePassSelection } from '../functions/updateOutlinePassSelection'

const transformProps = ['position', 'rotation', 'scale', 'matrix']

Expand Down Expand Up @@ -111,7 +110,6 @@ const execute = () => {
selectedEntities: action.selectedEntities,
selectedParentEntities: filterParentEntities(action.selectedEntities)
})
updateOutlinePassSelection()
}
for (const action of changedObjectQueue())
selectionState.merge({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
Ethereal Engine. All Rights Reserved.
*/

import { useEffect } from 'react'
import React, { useEffect } from 'react'
import {
Box3,
Intersection,
Expand Down Expand Up @@ -51,18 +51,21 @@ import {
hasComponent,
removeComponent,
removeQuery,
setComponent
setComponent,
useQuery
} from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { createEntity } from '@etherealengine/engine/src/ecs/functions/EntityFunctions'
import { createEntity, entityExists } from '@etherealengine/engine/src/ecs/functions/EntityFunctions'
import {
EntityTreeComponent,
getEntityNodeArrayFromEntities
} from '@etherealengine/engine/src/ecs/functions/EntityTree'
import { defineSystem } from '@etherealengine/engine/src/ecs/functions/SystemFunctions'
import { InputComponent } from '@etherealengine/engine/src/input/components/InputComponent'
import { InputSourceComponent } from '@etherealengine/engine/src/input/components/InputSourceComponent'
import InfiniteGridHelper from '@etherealengine/engine/src/scene/classes/InfiniteGridHelper'
import { addObjectToGroup, GroupComponent } from '@etherealengine/engine/src/scene/components/GroupComponent'
import { NameComponent } from '@etherealengine/engine/src/scene/components/NameComponent'
import { SceneObjectComponent } from '@etherealengine/engine/src/scene/components/SceneObjectComponent'
import { TransformGizmoComponent } from '@etherealengine/engine/src/scene/components/TransformGizmo'
import { VisibleComponent } from '@etherealengine/engine/src/scene/components/VisibleComponent'
import {
Expand Down Expand Up @@ -711,7 +714,20 @@ const execute = () => {
}
}

const SceneObjectEntityReactor = (props: { entity: Entity }) => {
useEffect(() => {
setComponent(props.entity, InputComponent)
return () => {
removeComponent(props.entity, InputComponent)
}
}, [])

return null
}

const reactor = () => {
const sceneObjectEntities = useQuery([SceneObjectComponent])

useEffect(() => {
// todo figure out how to do these with our input system
window.addEventListener('copy', copy)
Expand All @@ -722,7 +738,14 @@ const reactor = () => {
window.removeEventListener('paste', paste)
}
}, [])
return null

return (
<>
{sceneObjectEntities.map((entity) => (
<SceneObjectEntityReactor key={entity} entity={entity} />
))}
</>
)
}

export const EditorControlSystem = defineSystem({
Expand Down
24 changes: 24 additions & 0 deletions packages/engine/src/common/functions/Object3DUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,30 @@ export class Object3DUtils {
}
}

static traverseAncestors(object: Object3D, callback) {
if (!object) return false

if (callback(object)) return true
const parent = object.parent

if (parent) {
if (Object3DUtils.traverseAncestors(parent, callback)) return true
}
}

static findAncestor(object: Object3D, callback) {
if (!object) return null

if (callback(object)) return object
const parent = object.parent

if (parent) {
return Object3DUtils.findAncestor(parent, callback)
}

return null
}

/**
* Finds the topmost object in the Object3D hierarchy
* @param object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
Ethereal Engine. All Rights Reserved.
*/

import React, { useEffect, useLayoutEffect } from 'react'
import { useLayoutEffect } from 'react'

import { Entity } from '../../ecs/classes/Entity'
import { defineComponent, removeComponent, setComponent, useComponent } from '../../ecs/functions/ComponentFunctions'
import { useEntityContext } from '../../ecs/functions/EntityFunctions'
import { BoundingBoxComponent } from '../../interaction/components/BoundingBoxComponents'
import { HighlightComponent } from '../../renderer/components/HighlightComponent'

export const InputComponent = defineComponent({
Expand All @@ -37,21 +36,28 @@ export const InputComponent = defineComponent({
onInit: () => {
return {
/** populated automatically by ClientInputSystem */
inputSources: [] as Entity[]
inputSources: [] as Entity[],
highlight: true
// priority: 0
}
},

onSet(entity, component, json) {
if (!json) return

if (typeof json.highlight === 'string') component.highlight.set(json.highlight)
},

reactor: () => {
const entity = useEntityContext()
const input = useComponent(entity, InputComponent)
useLayoutEffect(() => {
if (input.inputSources.length === 0) return
if (!input.inputSources.length || !input.highlight.value) return
setComponent(entity, HighlightComponent)
return () => {
removeComponent(entity, HighlightComponent)
}
}, [input.inputSources])
}, [input.inputSources, input.highlight])
return null
}
})
27 changes: 24 additions & 3 deletions packages/engine/src/input/systems/ClientInputSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ Ethereal Engine. All Rights Reserved.
*/

import { useEffect } from 'react'
import { LineBasicMaterial, Mesh, MeshBasicMaterial, Quaternion, Ray, Vector3 } from 'three'
import { LineBasicMaterial, Mesh, MeshBasicMaterial, Quaternion, Ray, Raycaster, Vector3 } from 'three'

import { dispatchAction, getMutableState, getState, useHookstate } from '@etherealengine/hyperflux'

import { ObjectDirection } from '../../common/constants/Axis3D'
import { Object3DUtils } from '../../common/functions/Object3DUtils'
import { Engine } from '../../ecs/classes/Engine'
import { EngineActions } from '../../ecs/classes/EngineState'
import { EngineActions, EngineState } from '../../ecs/classes/EngineState'
import { Entity, UndefinedEntity } from '../../ecs/classes/Entity'
import {
defineQuery,
Expand All @@ -50,6 +51,7 @@ import { AllCollisionMask } from '../../physics/enums/CollisionGroups'
import { getInteractionGroups } from '../../physics/functions/getInteractionGroups'
import { SceneQueryType } from '../../physics/types/PhysicsTypes'
import { EngineRenderer } from '../../renderer/WebGLRendererSystem'
import { GroupComponent, Object3DWithEntity } from '../../scene/components/GroupComponent'
import { NameComponent } from '../../scene/components/NameComponent'
import { VisibleComponent } from '../../scene/components/VisibleComponent'
import { TransformComponent } from '../../transform/components/TransformComponent'
Expand Down Expand Up @@ -368,6 +370,7 @@ const xrSpaces = defineQuery([XRSpaceComponent, TransformComponent])
const inputSources = defineQuery([InputSourceComponent])

const inputXRUIs = defineQuery([InputComponent, VisibleComponent, XRUIComponent])
const inputObjects = defineQuery([InputComponent, VisibleComponent, GroupComponent])

const rayRotation = new Quaternion()

Expand All @@ -381,6 +384,7 @@ const inputRaycast = {
} as RaycastArgs

const inputRay = new Ray()
const raycaster = new Raycaster()

const execute = () => {
Engine.instance.pointerScreenRaycaster.setFromCamera(Engine.instance.pointerState.position, Engine.instance.camera)
Expand Down Expand Up @@ -459,7 +463,24 @@ const execute = () => {
break
}

// 2nd heuristic is physics colliders
// 2nd heuristic is scene objects when in the editor
if (getState(EngineState).isEditor) {
raycaster.set(inputRaycast.origin, inputRaycast.direction)
const objects = inputObjects()
.map((eid) => getComponent(eid, GroupComponent))
.flat()
const hits = raycaster
.intersectObjects<Object3DWithEntity>(objects, true)
.sort((a, b) => a.distance - b.distance)

if (hits.length) {
const object = hits[0].object
const parentObject = Object3DUtils.findAncestor(object, (obj) => obj.parent === Engine.instance.scene)
assignedInputEntity = parentObject.entity
}
}

// 3nd heuristic is physics colliders
if (Engine.instance.physicsWorld && !assignedInputEntity) {
const hit = Physics.castRay(Engine.instance.physicsWorld, inputRaycast)[0]
if (hit) assignedInputEntity = hit.entity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,31 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
Ethereal Engine. All Rights Reserved.
*/

import { useEffect } from 'react'
import { Object3D } from 'three'

import { defineQuery, getComponent, removeQuery } from '../ecs/functions/ComponentFunctions'
import { defineSystem } from '../ecs/functions/SystemFunctions'
import { GroupComponent } from '../scene/components/GroupComponent'
import { HighlightComponent } from './components/HighlightComponent'
import { EngineRenderer } from './WebGLRendererSystem'

const highlightedObjectQuery = defineQuery([GroupComponent, HighlightComponent])

const addToSelection = (obj: Object3D) => {
EngineRenderer.instance.effectComposer.OutlineEffect.selection.add(obj)
}

const execute = () => {
if (!EngineRenderer.instance.effectComposer.OutlineEffect) return

EngineRenderer.instance.effectComposer.OutlineEffect.selection.clear()

for (const entity of highlightedObjectQuery()) {
const group = getComponent(entity, GroupComponent)
for (const object of group) object.traverse(addToSelection)
import { KernelSize, Resolution } from 'postprocessing'
import { Texture } from 'three'

import { defineState } from '@etherealengine/hyperflux'

import { BlendFunction } from './effects/blending/BlendFunction'

export const HighlightState = defineState({
name: 'HighlightState',
initial: {
blendFunction: BlendFunction.SCREEN,
patternTexture: null! as Texture, // post processing args typed as (Texture | undefined) so we must override the type
patternScale: 1.0,
edgeStrength: 1.0,
pulseSpeed: 0.0,
visibleEdgeColor: 0xffffff,
hiddenEdgeColor: 0x999999,
kernelSize: KernelSize.MEDIUM,
blur: false,
xRay: true,
multisampling: 0,
resolutionScale: 0.5,
resolutionX: Resolution.AUTO_SIZE,
resolutionY: Resolution.AUTO_SIZE,
width: Resolution.AUTO_SIZE,
height: Resolution.AUTO_SIZE
}
}

export const HighlightSystem = defineSystem({
uuid: 'ee.engine.HighlightSystem',
execute
})
Loading

0 comments on commit 2df35fb

Please sign in to comment.