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

VariantComponent #8112

Merged
merged 2 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
7 changes: 5 additions & 2 deletions packages/client-core/i18n/en/editor.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@
"description": "Link to a room or a website.",
"lbl-url": "URL"
},
"lod": {
"variant": {
"name": "Variant",
"description": "Load different assets based on heuristics",
"device": "Device",
"device-mobile": "Mobile",
"device-desktop": "Desktop",
Expand All @@ -246,7 +248,8 @@
"heuristic-sceneScale": "Scene Scale",
"heuristic-manual": "Manual",
"heuristic-device": "Device",
"distance": "Distance",
"minDistance": "Minimum Distance",
"maxDistance": "Maximum Distance",
"src": "Source"
},
"map": {
Expand Down
50 changes: 35 additions & 15 deletions packages/editor/src/components/properties/VariantNodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ import DeblurIcon from '@mui/icons-material/Deblur'
import { Button } from '../inputs/Button'
import InputGroup from '../inputs/InputGroup'
import ModelInput from '../inputs/ModelInput'
import NumericInput from '../inputs/NumericInput'
import SelectInput from '../inputs/SelectInput'
import PaginatedList from '../layout/PaginatedList'
import NodeEditor from './NodeEditor'
import { EditorComponentType } from './Util'

export const VariantNodeEditor: EditorComponentType = ({ entity }: { entity: Entity }) => {
export const VariantNodeEditor: EditorComponentType = (props: { entity: Entity }) => {
const { t } = useTranslation()

const entity = props.entity
const variantComponent = useComponent(entity, VariantComponent)
const nameComponent = getComponent(entity, NameComponent)

Expand All @@ -56,19 +58,21 @@ export const VariantNodeEditor: EditorComponentType = ({ entity }: { entity: Ent
[entity]
)
return (
<div>
<h2 className="text-white text-2xl font-bold m-4">LODs</h2>
<NodeEditor
name={t('editor:properties.variant.name')}
description={t('editor:properties.variant.description')}
{...props}
>
<div className="bg-gray-800 rounded-lg p-4 m-4">
<h2 className="text-white text-xl font-bold mb-4">{nameComponent}</h2>
<InputGroup name="lodHeuristic" label={t('editor:properties.lod.heuristic')}>
<InputGroup name="lodHeuristic" label={t('editor:properties.variant.heuristic')}>
<SelectInput
value={variantComponent.heuristic.value}
onChange={(val: typeof variantComponent.heuristic.value) => variantComponent.heuristic.set(val)}
options={[
{ value: 'DISTANCE', label: t('editor:properties.lod.heuristic-distance') },
{ value: 'SCENE_SCALE', label: t('editor:properties.lod.heuristic-sceneScale') },
{ value: 'MANUAL', label: t('editor:properties.lod.heuristic-manual') },
{ value: 'DEVICE', label: t('editor:properties.lod.heuristic-device') }
{ value: 'DISTANCE', label: t('editor:properties.variant.heuristic-distance') },
{ value: 'SCENE_SCALE', label: t('editor:properties.variant.heuristic-sceneScale') },
{ value: 'MANUAL', label: t('editor:properties.variant.heuristic-manual') },
{ value: 'DEVICE', label: t('editor:properties.variant.heuristic-device') }
]}
/>
</InputGroup>
Expand All @@ -89,23 +93,39 @@ export const VariantNodeEditor: EditorComponentType = ({ entity }: { entity: Ent
return (
<div className="bg-gray-900 m-2">
<div style={{ margin: '2em' }}>
<InputGroup name="src" label={t('editor:properties.lod.src')}>
<InputGroup name="src" label={t('editor:properties.variant.src')}>
<ModelInput value={level.src.value} onChange={onChangeLevelProperty(level, 'src')} />
</InputGroup>
{variantComponent.heuristic.value === 'DEVICE' && (
<>
<InputGroup name="device" label={t('editor:properties.lod.device')}>
<InputGroup name="device" label={t('editor:properties.variant.device')}>
<SelectInput
value={level.metadata['device'].value}
onChange={onChangeLevelProperty(level.metadata, 'device')}
options={[
{ value: 'MOBILE', label: t('editor:properties.lod.device-mobile') },
{ value: 'DESKTOP', label: t('editor:properties.lod.device-desktop') }
{ value: 'MOBILE', label: t('editor:properties.variant.device-mobile') },
{ value: 'DESKTOP', label: t('editor:properties.variant.device-desktop') }
]}
/>
</InputGroup>
</>
)}
{variantComponent.heuristic.value === 'DISTANCE' && (
<>
<InputGroup name="minDistance" label={t('editor:properties.variant.minDistance')}>
<NumericInput
value={level.metadata['minDistance'].value}
onChange={onChangeLevelProperty(level.metadata, 'minDistance')}
/>
</InputGroup>
<InputGroup name="maxDistance" label={t('editor:properties.variant.maxDistance')}>
<NumericInput
value={level.metadata['maxDistance'].value}
onChange={onChangeLevelProperty(level.metadata, 'maxDistance')}
/>
</InputGroup>
</>
)}
</div>
<div className="flex justify-end">
<Button
Expand All @@ -122,7 +142,7 @@ export const VariantNodeEditor: EditorComponentType = ({ entity }: { entity: Ent
}}
/>
</div>
</div>
</NodeEditor>
)
}

Expand Down
16 changes: 16 additions & 0 deletions packages/engine/src/scene/components/VariantComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,15 @@ import {
defineComponent,
getComponent,
getMutableComponent,
hasComponent,
removeComponent,
setComponent,
useComponent,
useOptionalComponent,
useQuery
} from '../../ecs/functions/ComponentFunctions'
import { useEntityContext } from '../../ecs/functions/EntityFunctions'
import { DistanceFromCameraComponent } from '../../transform/components/DistanceComponents'
import { isMobileXRHeadset } from '../../xr/XRState'
import { setModelVariant } from '../functions/loaders/VariantFunctions'
import { ModelComponent } from './ModelComponent'
Expand Down Expand Up @@ -107,6 +111,18 @@ const VariantLevelReactor = React.memo(({ entity, level }: { level: number; enti

const modelComponent = useOptionalComponent(entity, ModelComponent)

useEffect(() => {
//if the variant heuristic is set to Distance, add the DistanceFromCameraComponent
if (variantComponent.heuristic.value === 'DISTANCE') {
setComponent(entity, DistanceFromCameraComponent)
variantLevel.metadata['minDistance'].value === undefined && variantLevel.metadata['minDistance'].set(0)
variantLevel.metadata['maxDistance'].value === undefined && variantLevel.metadata['maxDistance'].set(0)
} else {
//otherwise, remove the DistanceFromCameraComponent
hasComponent(entity, DistanceFromCameraComponent) && removeComponent(entity, DistanceFromCameraComponent)
HexaField marked this conversation as resolved.
Show resolved Hide resolved
}
}, [variantComponent.heuristic])

useEffect(() => {
modelComponent && setModelVariant(entity)
}, [variantLevel.src, variantLevel.metadata, modelComponent])
Expand Down
16 changes: 16 additions & 0 deletions packages/engine/src/scene/functions/loaders/VariantFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { DistanceFromCameraComponent } from '@etherealengine/engine/src/transform/components/DistanceComponents'
import { getState } from '@etherealengine/hyperflux'

import { EngineState } from '../../../ecs/classes/EngineState'
import { Entity } from '../../../ecs/classes/Entity'
import { getComponent, getMutableComponent } from '../../../ecs/functions/ComponentFunctions'
import { TransformComponent } from '../../../transform/components/TransformComponent'
import { isMobileXRHeadset } from '../../../xr/XRState'
import { ModelComponent } from '../../components/ModelComponent'
import { VariantComponent } from '../../components/VariantComponent'
Expand Down Expand Up @@ -42,5 +47,16 @@ export function setModelVariant(entity: Entity) {
//set model src to mobile variant src
const deviceVariant = variantComponent.levels.find((level) => level.metadata['device'] === targetDevice)
deviceVariant && modelComponent.src.value !== deviceVariant.src && modelComponent.src.set(deviceVariant.src)
} else if (variantComponent.heuristic === 'DISTANCE') {
const distance = DistanceFromCameraComponent.squaredDistance[entity]
for (let i = 0; i < variantComponent.levels.length; i++) {
const level = variantComponent.levels[i]
if ([level.metadata['minDistance'], level.metadata['maxDistance']].includes(undefined)) continue
const minDistance = Math.pow(level.metadata['minDistance'], 2)
const maxDistance = Math.pow(level.metadata['maxDistance'], 2)
const useLevel = minDistance <= distance && distance <= maxDistance
useLevel && modelComponent.src.value !== level.src && modelComponent.src.set(level.src)
if (useLevel) break
}
}
}
13 changes: 5 additions & 8 deletions packages/engine/src/scene/systems/VariantSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,25 @@ import { getState } from '@etherealengine/hyperflux'
import { EngineState } from '../../ecs/classes/EngineState'
import { defineQuery, getMutableComponent, useQuery } from '../../ecs/functions/ComponentFunctions'
import { defineSystem } from '../../ecs/functions/SystemFunctions'
import { TransformComponent } from '../../transform/components/TransformComponent'
import { ModelComponent } from '../components/ModelComponent'
import { VariantComponent } from '../components/VariantComponent'
import { setModelVariant } from '../functions/loaders/VariantFunctions'

const updateFrequency = 0.1
let lastUpdate = 0

const modelVariantQuery = defineQuery([VariantComponent, ModelComponent, TransformComponent])

function execute() {
const engineState = getState(EngineState)
if (engineState.elapsedSeconds - lastUpdate < updateFrequency) return
lastUpdate = engineState.elapsedSeconds

modelVariantQuery().forEach(setModelVariant)
dinomut1 marked this conversation as resolved.
Show resolved Hide resolved
}

function reactor() {
const modelVariantQuery = useQuery([VariantComponent, ModelComponent])

/*useEffect(() => {
for (const entity of modelVariantQuery) {
setModelVariant(entity)
}
}, [modelVariantQuery])
*/
return null
}

Expand Down