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

Commit

Permalink
VariantComponent (#8112)
Browse files Browse the repository at this point in the history
* re-commit

* reimplement distance heuristic
  • Loading branch information
dinomut1 authored Jun 23, 2023
1 parent 5fc333e commit b2b4bee
Show file tree
Hide file tree
Showing 13 changed files with 315 additions and 860 deletions.
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
56 changes: 3 additions & 53 deletions packages/editor/src/components/properties/ModelNodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,30 @@ Ethereal Engine. All Rights Reserved.
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'

import {
DefaultModelTransformParameters,
ModelTransformParameters
} from '@etherealengine/engine/src/assets/classes/ModelTransform'
import { AnimationManager } from '@etherealengine/engine/src/avatar/AnimationManager'
import { LoopAnimationComponent } from '@etherealengine/engine/src/avatar/components/LoopAnimationComponent'
import {
addComponent,
getComponent,
getOptionalComponent,
hasComponent,
removeComponent,
setComponent,
useComponent
} from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { EquippableComponent } from '@etherealengine/engine/src/interaction/components/EquippableComponent'
import { CallbackComponent, getCallback } from '@etherealengine/engine/src/scene/components/CallbackComponent'
import { getCallback } from '@etherealengine/engine/src/scene/components/CallbackComponent'
import { getEntityErrors } from '@etherealengine/engine/src/scene/components/ErrorComponent'
import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent'
import { addError, clearErrors } from '@etherealengine/engine/src/scene/functions/ErrorFunctions'
import { State, useState } from '@etherealengine/hyperflux'
import { useState } from '@etherealengine/hyperflux'

import ViewInArIcon from '@mui/icons-material/ViewInAr'

import exportGLTF from '../../functions/exportGLTF'
import { convertToScaffold, createLODsFromModel } from '../../functions/lodsFromModel'
import { LODsFromModelParameters } from '../../functions/lodsFromModel'
import BooleanInput from '../inputs/BooleanInput'
import { Button, PropertiesPanelButton } from '../inputs/Button'
import { PropertiesPanelButton } from '../inputs/Button'
import InputGroup from '../inputs/InputGroup'
import ModelInput from '../inputs/ModelInput'
import SelectInput from '../inputs/SelectInput'
import CollapsibleBlock from '../layout/CollapsibleBlock'
import PaginatedList from '../layout/PaginatedList'
import Well from '../layout/Well'
import GLTFTransformProperties from './GLTFTransformProperties'
import ModelTransformProperties from './ModelTransformProperties'
import NodeEditor from './NodeEditor'
import ScreenshareTargetNodeEditor from './ScreenshareTargetNodeEditor'
Expand Down Expand Up @@ -89,11 +77,6 @@ export const ModelNodeEditor: EditorComponentType = (props) => {

const loopAnimationComponent = getOptionalComponent(entity, LoopAnimationComponent)

const lodParms = useState<LODsFromModelParameters>(() => ({
serialize: false,
levels: []
}))

const onChangeEquippable = useCallback(() => {
if (isEquippable.value) {
removeComponent(props.entity, EquippableComponent)
Expand Down Expand Up @@ -156,12 +139,6 @@ export const ModelNodeEditor: EditorComponentType = (props) => {
getCallback(props.entity, 'xre.play')!()
}

const onAddLODLevel = useCallback(() => {
lodParms.levels[lodParms.levels.length].set({
...DefaultModelTransformParameters
})
}, [])

return (
<NodeEditor
name={t('editor:properties.model.title')}
Expand Down Expand Up @@ -208,33 +185,6 @@ export const ModelNodeEditor: EditorComponentType = (props) => {
</InputGroup>
<ScreenshareTargetNodeEditor entity={props.entity} multiEdit={props.multiEdit} />
<ShadowProperties entity={props.entity} />
<CollapsibleBlock label={t('editor:properties.model.lods.label')}>
<div className="bg-gradient-to-b from-blue-gray-400 to-cool-gray-800 rounded-lg shadow-lg">
<div className="px-4 py-2 border-b border-gray-300">
<h2 className="text-lg font-semibold text-gray-100">LODs</h2>
</div>
<InputGroup name="Serialize" label={t('editor:properties.model.lods.serialize')}>
<BooleanInput value={lodParms.value.serialize} onChange={lodParms.serialize.set} />
</InputGroup>
<InputGroup name="LOD Level Parameters" label={t('editor:properties.model.lods.lodLevelParameters')}>
<Button onClick={onAddLODLevel}>Add LOD Level</Button>
</InputGroup>
<PaginatedList
list={lodParms.levels}
element={(lodLevel: State<ModelTransformParameters>) => {
return <GLTFTransformProperties transformParms={lodLevel} onChange={lodLevel.set} />
}}
/>
<div className="p-4">
<Button onClick={convertToScaffold.bind({}, entity)}>Convert to Scaffold</Button>
</div>
<div className="p-4">
<Button onClick={createLODsFromModel.bind({}, entity, lodParms.value)}>
{t('editor:properties.model.lods.generate')}
</Button>
</div>
</div>
</CollapsibleBlock>
<ModelTransformProperties modelState={modelComponent} onChangeModel={(val) => modelComponent.src.set(val)} />
{!exporting.value && modelComponent.src.value && (
<Well>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,26 @@ import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'

import { Entity } from '@etherealengine/engine/src/ecs/classes/Entity'
import {
getComponent,
getMutableComponent,
useComponent
} from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { LODComponent, LODLevel } from '@etherealengine/engine/src/scene/components/LODComponent'
import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent'
import { getComponent, useComponent } from '@etherealengine/engine/src/ecs/functions/ComponentFunctions'
import { NameComponent } from '@etherealengine/engine/src/scene/components/NameComponent'
import { VariantComponent, VariantLevel } from '@etherealengine/engine/src/scene/components/VariantComponent'
import { State } from '@etherealengine/hyperflux'

import DeblurIcon from '@mui/icons-material/Deblur'

import { serializeLOD } from '../../functions/lodsFromModel'
import { Button } from '../inputs/Button'
import InputGroup, { InputGroupContainer } from '../inputs/InputGroup'
import InputGroup from '../inputs/InputGroup'
import ModelInput from '../inputs/ModelInput'
import NumericInput from '../inputs/NumericInput'
import NumericInputGroup from '../inputs/NumericInputGroup'
import SelectInput from '../inputs/SelectInput'
import PaginatedList from '../layout/PaginatedList'
import NodeEditor from './NodeEditor'
import { EditorComponentType } from './Util'

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

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

const onChangeLevelProperty = useCallback(
Expand All @@ -64,90 +58,92 @@ export const LODProperties: EditorComponentType = ({ entity }: { entity: Entity
[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={lodComponent.lodHeuristic.value}
onChange={(val: typeof lodComponent.lodHeuristic.value) => lodComponent.lodHeuristic.set(val)}
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>
<Button
onClick={() =>
lodComponent.levels[lodComponent.levels.length].set({
distance: 0,
variantComponent.levels[variantComponent.levels.length].set({
src: '',
loaded: false,
metadata: {},
model: null
metadata: {}
})
}
>
Add LOD
Add Variant
</Button>
<PaginatedList
options={{ countPerPage: 1 }}
list={lodComponent.levels}
element={(level: State<LODLevel>) => {
options={{ countPerPage: 6 }}
list={variantComponent.levels}
element={(level: State<VariantLevel>) => {
return (
<div className="bg-gray-900 m-2">
<div style={{ margin: '2em' }}>
<InputGroup name="distance" label={t('editor:properties.lod.distance')}>
<NumericInput value={level.distance.value} onChange={onChangeLevelProperty(level, 'distance')} />
</InputGroup>
<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>
{lodComponent.lodHeuristic.value === 'DEVICE' && (
{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
onClick={() => {
const index = lodComponent.levels.indexOf(level)
lodComponent.levels.set(lodComponent.levels.value.filter((_, i) => i !== index))
const index = variantComponent.levels.indexOf(level)
variantComponent.levels.set(variantComponent.levels.value.filter((_, i) => i !== index))
}}
>
Remove
</Button>
</div>
<div className="flex justify-end">
<Button
onClick={() => {
const model = getComponent(lodComponent.target.value, ModelComponent)
serializeLOD(model.src, entity, level)
}}
>
Serialize
</Button>
</div>
</div>
)
}}
/>
</div>
</div>
</NodeEditor>
)
}

LODProperties.iconComponent = DeblurIcon
VariantNodeEditor.iconComponent = DeblurIcon
6 changes: 3 additions & 3 deletions packages/editor/src/functions/PrefabEditors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { HemisphereLightComponent } from '@etherealengine/engine/src/scene/compo
import { ImageComponent } from '@etherealengine/engine/src/scene/components/ImageComponent'
import { InstancingComponent } from '@etherealengine/engine/src/scene/components/InstancingComponent'
import { InteriorComponent } from '@etherealengine/engine/src/scene/components/InteriorComponent'
import { LODComponent } from '@etherealengine/engine/src/scene/components/LODComponent'
import { MediaComponent } from '@etherealengine/engine/src/scene/components/MediaComponent'
import { MediaSettingsComponent } from '@etherealengine/engine/src/scene/components/MediaSettingsComponent'
import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent'
Expand All @@ -60,6 +59,7 @@ import { SpawnPointComponent } from '@etherealengine/engine/src/scene/components
import { SplineComponent } from '@etherealengine/engine/src/scene/components/SplineComponent'
import { SpotLightComponent } from '@etherealengine/engine/src/scene/components/SpotLightComponent'
import { SystemComponent } from '@etherealengine/engine/src/scene/components/SystemComponent'
import { VariantComponent } from '@etherealengine/engine/src/scene/components/VariantComponent'
import { VideoComponent } from '@etherealengine/engine/src/scene/components/VideoComponent'
import { VolumetricComponent } from '@etherealengine/engine/src/scene/components/VolumetricComponent'
import { WaterComponent } from '@etherealengine/engine/src/scene/components/WaterComponent'
Expand All @@ -84,7 +84,6 @@ import HemisphereLightNodeEditor from '../components/properties/HemisphereLightN
import ImageNodeEditor from '../components/properties/ImageNodeEditor'
import InstancingNodeEditor from '../components/properties/InstancingNodeEditor'
import InteriorNodeEditor from '../components/properties/InteriorNodeEditor'
import { LODProperties } from '../components/properties/LODProperties'
import MediaNodeEditor from '../components/properties/MediaNodeEditor'
import { MediaSettingsEditor } from '../components/properties/MediaSettingsEditor'
import ModelNodeEditor from '../components/properties/ModelNodeEditor'
Expand All @@ -107,6 +106,7 @@ import SpotLightNodeEditor from '../components/properties/SpotLightNodeEditor'
import SystemNodeEditor from '../components/properties/SystemNodeEditor'
import TransformPropertyGroup from '../components/properties/TransformPropertyGroup'
import { EditorComponentType } from '../components/properties/Util'
import { VariantNodeEditor } from '../components/properties/VariantNodeEditor'
import VideoNodeEditor from '../components/properties/VideoNodeEditor'
import VolumetricNodeEditor from '../components/properties/VolumetricNodeEditor'
import WaterNodeEditor from '../components/properties/WaterNodeEditor'
Expand Down Expand Up @@ -150,7 +150,7 @@ EntityNodeEditor.set(EnvmapComponent, EnvMapEditor)
EntityNodeEditor.set(EnvMapBakeComponent, EnvMapBakeNodeEditor)
EntityNodeEditor.set(InstancingComponent, InstancingNodeEditor)
EntityNodeEditor.set(PersistentAnchorComponent, PersistentAnchorNodeEditor)
EntityNodeEditor.set(LODComponent, LODProperties)
EntityNodeEditor.set(VariantComponent, VariantNodeEditor)

export const prefabIcons = {
[LightPrefabs.ambientLight]: AmbientLightNodeEditor.iconComponent,
Expand Down
Loading

0 comments on commit b2b4bee

Please sign in to comment.