Skip to content

Commit

Permalink
Fix GLTF Export (#9483)
Browse files Browse the repository at this point in the history
* add proxified group to all scene entities
animations reference model asset instead of scene
remove lightmapbaker

* check for material before csm teardown

* ci/cd
  • Loading branch information
dinomut1 committed Dec 22, 2023
1 parent 4140821 commit ec91819
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 255 deletions.
149 changes: 0 additions & 149 deletions packages/editor/src/components/properties/LightmapBakerProperties.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const LoopAnimationNodeEditor: EditorComponentType = (props) => {
{ label: 'None', value: -1 },
...animationComponent.animations.map((clip, index) => ({ label: clip.name, value: index }))
])
}, [modelComponent?.scene, loopAnimationComponent.hasAvatarAnimations])
}, [modelComponent?.asset, loopAnimationComponent.hasAvatarAnimations])

const onChangePlayingAnimation = (index) => {
commitProperties(LoopAnimationComponent, {
Expand Down
2 changes: 2 additions & 0 deletions packages/engine/src/assets/csm/CSM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@ export class CSM {
}

teardownMaterial(mesh: Mesh): void {
if (!mesh?.isMesh) return
const material = mesh.material as Material
if (!material) return
if (!material.userData) material.userData = {}
if (material.userData.CSMPlugin) {
removeOBCPlugin(material, material.userData.CSMPlugin)
Expand Down
3 changes: 2 additions & 1 deletion packages/engine/src/assets/functions/exportModelGLTF.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Ethereal Engine. All Rights Reserved.

import { Entity } from '../../ecs/classes/Entity'
import { getComponent } from '../../ecs/functions/ComponentFunctions'
import { GroupComponent } from '../../scene/components/GroupComponent'
import { ModelComponent } from '../../scene/components/ModelComponent'
import createGLTFExporter from './createGLTFExporter'

Expand All @@ -38,7 +39,7 @@ export default async function exportModelGLTF(
embedImages: true
}
) {
const scene = getComponent(entity, ModelComponent).scene!
const scene = getComponent(entity, ModelComponent).scene ?? getComponent(entity, GroupComponent)[0]
const exporter = createGLTFExporter()
const modelName = options.relativePath.split('/').at(-1)!.split('.').at(0)!
const resourceURI = `model-resources/${modelName}`
Expand Down
15 changes: 9 additions & 6 deletions packages/engine/src/avatar/components/LoopAnimationComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,16 @@ export const LoopAnimationComponent = defineComponent({
useEffect(() => {
if (!animComponent?.animations?.value) return
const clip = animComponent.animations.value[loopAnimationComponent.activeClipIndex.value]
if (!modelComponent?.scene?.value || !clip) {
const asset = modelComponent?.asset.get(NO_PROXY) ?? null
if (!modelComponent || !asset?.scene || !clip) {
loopAnimationComponent._action.set(null)
return
}
animComponent.mixer.time.set(0)
const assetObject = modelComponent.asset.get(NO_PROXY)
try {
const action = animComponent.mixer.value.clipAction(
assetObject instanceof VRM ? retargetMixamoAnimation(clip, modelComponent.scene.value, assetObject) : clip
assetObject instanceof VRM ? retargetMixamoAnimation(clip, asset.scene, assetObject) : clip
)
loopAnimationComponent._action.set(action)
return () => {
Expand Down Expand Up @@ -206,20 +207,22 @@ export const LoopAnimationComponent = defineComponent({
* A model is required for LoopAnimationComponent.
*/
useEffect(() => {
if (!modelComponent?.scene?.value) return
const asset = modelComponent?.asset.get(NO_PROXY) ?? null
if (!asset?.scene) return
const model = getComponent(entity, ModelComponent)

if (!hasComponent(entity, AnimationComponent)) {
setComponent(entity, AnimationComponent, {
mixer: new AnimationMixer(model.scene!),
mixer: new AnimationMixer(model.asset!.scene),
animations: []
})
}
}, [modelComponent?.scene, loopAnimationComponent.hasAvatarAnimations])
}, [modelComponent?.asset, loopAnimationComponent.hasAvatarAnimations])

useEffect(() => {
const asset = modelComponent?.asset.get(NO_PROXY) ?? null
if (
!modelComponent?.scene?.value ||
!asset?.scene ||
!animComponent ||
!loopAnimationComponent.animationPack.value ||
lastAnimationPack.value === loopAnimationComponent.animationPack.value
Expand Down
6 changes: 6 additions & 0 deletions packages/engine/src/avatar/functions/spawnAvatarReceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ import { AvatarCollisionMask, CollisionGroups } from '../../physics/enums/Collis
import { getInteractionGroups } from '../../physics/functions/getInteractionGroups'
import { PhysicsState } from '../../physics/state/PhysicsState'
import { EnvmapComponent } from '../../scene/components/EnvmapComponent'
import { addObjectToGroup } from '../../scene/components/GroupComponent'
import { NameComponent } from '../../scene/components/NameComponent'
import { ShadowComponent } from '../../scene/components/ShadowComponent'
import { UUIDComponent } from '../../scene/components/UUIDComponent'
import { VisibleComponent } from '../../scene/components/VisibleComponent'
import { EnvMapSourceType } from '../../scene/constants/EnvMapEnum'
import { proxifyParentChildRelationships } from '../../scene/functions/loadGLTFModel'
import { DistanceFromCameraComponent, FrustumCullCameraComponent } from '../../transform/components/DistanceComponents'
import { TransformComponent } from '../../transform/components/TransformComponent'
import { AnimationComponent } from '../components/AnimationComponent'
Expand Down Expand Up @@ -87,6 +89,10 @@ export const spawnAvatarReceptor = (entityUUID: EntityUUID) => {
const userName = userNames[entityUUID]
const shortId = ownerID.substring(0, 7)
setComponent(entity, NameComponent, 'avatar-' + (userName ? shortId + ' (' + userName + ')' : shortId))
const obj3d = new Object3D()
obj3d.entity = entity
addObjectToGroup(entity, obj3d)
proxifyParentChildRelationships(obj3d)

setComponent(entity, VisibleComponent, true)

Expand Down
2 changes: 1 addition & 1 deletion packages/engine/src/input/systems/ClientInputSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ const execute = () => {
if (hits.length && hits[0].distance < hitDistance) {
const object = hits[0].object
const parentObject = Object3DUtils.findAncestor(object, (obj) => obj.parent === Engine.instance.scene)
if (parentObject.entity) {
if (parentObject?.entity) {
assignedInputEntity = parentObject.entity
hitDistance = hits[0].distance
}
Expand Down
4 changes: 3 additions & 1 deletion packages/engine/src/scene/components/GroupComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export const GroupComponent = defineComponent({

onRemove: (entity, component) => {
for (const obj of component.value) {
obj.removeFromParent()
if (obj.parent) {
obj.removeFromParent()
}
}
}
})
Expand Down
63 changes: 18 additions & 45 deletions packages/engine/src/scene/components/ModelComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Ethereal Engine. All Rights Reserved.
*/

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

import { NO_PROXY, createState, getMutableState, getState, none, useHookstate } from '@etherealengine/hyperflux'

Expand All @@ -42,7 +42,6 @@ import { SceneState } from '../../ecs/classes/Scene'
import {
defineComponent,
getComponent,
getOptionalComponent,
hasComponent,
removeComponent,
serializeComponent,
Expand All @@ -52,7 +51,6 @@ import {
useQuery
} from '../../ecs/functions/ComponentFunctions'
import { useEntityContext } from '../../ecs/functions/EntityFunctions'
import { EntityTreeComponent } from '../../ecs/functions/EntityTree'
import { EngineRenderer } from '../../renderer/WebGLRendererSystem'
import { SourceType } from '../../renderer/materials/components/MaterialSource'
import { removeMaterialSource } from '../../renderer/materials/functions/MaterialLibraryFunctions'
Expand Down Expand Up @@ -145,41 +143,11 @@ function ModelReactor() {

const model = modelComponent.value
if (!model.src) {
const dudScene = new Scene() as Scene & Object3D
dudScene.entity = entity
Object.defineProperties(dudScene, {
parent: {
get() {
if (EngineRenderer.instance?.rendering) return null
if (getComponent(entity, EntityTreeComponent)?.parentEntity) {
return (
getComponent(getComponent(entity, EntityTreeComponent).parentEntity!, GroupComponent)?.[0] ??
Engine.instance.scene
)
}
},
set(value) {
throw new Error('Cannot set parent of proxified object')
}
},
children: {
get() {
if (EngineRenderer.instance?.rendering) return []
return hasComponent(entity, EntityTreeComponent)
? getComponent(entity, EntityTreeComponent)
.children.filter((child) => getOptionalComponent(child, GroupComponent)?.length)
.flatMap((child) => getComponent(child, GroupComponent))
: []
},
set(value) {
throw new Error('Cannot set children of proxified object')
}
},
isProxified: {
value: true
}
})
modelComponent.scene.set(dudScene)
// const dudScene = new Scene() as Scene & Object3D
// dudScene.entity = entity
// addObjectToGroup(entity, dudScene)
// proxifyParentChildRelationships(dudScene)
modelComponent.scene.set(null)
modelComponent.asset.set(null)
return
}
Expand All @@ -200,7 +168,8 @@ function ModelReactor() {
addError(entity, ModelComponent, 'INVALID_SOURCE', 'Invalid URL')
return
}
const boneMatchedAsset = autoconvertMixamoAvatar(loadedAsset)
const boneMatchedAsset = autoconvertMixamoAvatar(loadedAsset) as GLTF
boneMatchedAsset.scene.animations = boneMatchedAsset.animations
modelComponent.asset.set(boneMatchedAsset)
},
(onprogress) => {
Expand Down Expand Up @@ -231,11 +200,12 @@ function ModelReactor() {
if (!asset) return
removeError(entity, ModelComponent, 'INVALID_SOURCE')
removeError(entity, ModelComponent, 'LOADING_ERROR')
asset.scene.animations = asset.animations
asset.scene.userData.src = model.src
asset.scene.userData.sceneID = getModelSceneID(entity)
asset.scene.userData.type === 'glb' && delete asset.scene.userData.type
modelComponent.scene.set(asset.scene)
const sceneObj = getComponent(entity, GroupComponent)[0] as Scene

sceneObj.userData.src = model.src
sceneObj.userData.sceneID = getModelSceneID(entity)
//sceneObj.userData.type === 'glb' && delete asset.scene.userData.type
modelComponent.scene.set(sceneObj)
}, [modelComponent.asset])

// update scene
Expand All @@ -256,7 +226,7 @@ function ModelReactor() {
})
else removeComponent(entity, SceneAssetPendingTagComponent)

const loadedJsonHierarchy = parseGLTFModel(entity)
const loadedJsonHierarchy = parseGLTFModel(entity, asset.scene as Scene)
const uuid = getModelSceneID(entity)

SceneState.loadScene(uuid, {
Expand All @@ -274,6 +244,9 @@ function ModelReactor() {
return () => {
clearMaterials(src)
getMutableState(SceneState).scenes[uuid].set(none)
// for(const child of scene.children) {
// removeEntity(child.entity)
// }
}
}, [modelComponent.scene])

Expand Down

0 comments on commit ec91819

Please sign in to comment.