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

New GLTF ECS Loader #10904

Draft
wants to merge 54 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
f3ceb7c
gltf loader 2.0 can load geometries
HexaField Jul 27, 2024
e6d4e0e
license
HexaField Jul 27, 2024
a09f2d5
can load binary buffers, draco and quantized primitives
HexaField Jul 27, 2024
ac91fe3
license
HexaField Jul 27, 2024
7ee8111
basic material support
HexaField Jul 28, 2024
08e1d80
add kmu extension
HexaField Jul 29, 2024
2ff5e1c
Merge branch 'dev' into gltf-loader-2.0
HexaField Jul 29, 2024
cfd35ed
Merge branch 'dev' into gltf-loader-2.0
HexaField Jul 31, 2024
c9ae4c4
load material definitions separate to instances
HexaField Jul 31, 2024
248af55
turn functions into hooks
HexaField Aug 1, 2024
fafc991
fix texture loading
HexaField Aug 1, 2024
cf734f8
Merge branch 'dev' into gltf-loader-2.0
HexaField Aug 1, 2024
9121c48
move and simplify reactors for material components
HexaField Aug 1, 2024
e28ab8f
Merge branch 'dev' into gltf-loader-2.0
HexaField Aug 1, 2024
0990662
fixes
HexaField Aug 2, 2024
dcfe4ce
needs update upon value change
HexaField Aug 2, 2024
6f8439f
needs update upon value change
HexaField Aug 2, 2024
81d6ce2
Merge branch 'dev' into gltf-loader-2.0
HexaField Aug 3, 2024
0b4f3fa
support material extensions
HexaField Aug 4, 2024
53dc834
license
HexaField Aug 4, 2024
625dda0
bug fix
HexaField Aug 4, 2024
1e55e94
add punctual lights extension
HexaField Aug 4, 2024
358a046
license
HexaField Aug 4, 2024
4d4f64c
add camera
HexaField Aug 4, 2024
3344596
fix draco
HexaField Aug 4, 2024
0df162f
clean up
HexaField Aug 4, 2024
8c86f05
fix quantized accessor and support KHR_TEXTURE_TRANSFORM
HexaField Aug 4, 2024
f074919
add KHR_texture_basisu support
HexaField Aug 4, 2024
1287037
support mesh opt extension, prototype better API for extensions
HexaField Aug 6, 2024
ac7d471
license
HexaField Aug 6, 2024
9926fc5
add EXT_mesh_gpu_instancing component
HexaField Aug 7, 2024
28fd15d
bug fix
HexaField Aug 7, 2024
e92eda5
refactor primitive loading, add skins and bones
HexaField Aug 9, 2024
9f972fe
Merge branch 'dev' into gltf-loader-2.0
HexaField Aug 9, 2024
f1b7307
add animation support
HexaField Aug 9, 2024
36a7a0c
Merge branch 'dev' into gltf-loader-2.0
HexaField Aug 10, 2024
9e2c611
add morph target support
HexaField Aug 11, 2024
1326793
bug fixes, add old specular gloss and lightmap extensions
HexaField Aug 12, 2024
59cecb9
initial support for EE_material
HexaField Aug 13, 2024
b246074
console logs
HexaField Aug 13, 2024
dccc85f
assign texture bug fixes
HexaField Aug 13, 2024
9cb9977
Support nested GLTFComponent loading, bug fixes with materials and mu…
HexaField Aug 14, 2024
f867d8f
working on loading avatars
HexaField Aug 14, 2024
8e42916
wip fix avatar retargeting
AidanCaruso Aug 14, 2024
2c51a39
conditional flip only if vrm 0
AidanCaruso Aug 14, 2024
d5d735e
cleanup
AidanCaruso Aug 14, 2024
8da8f45
wip set loaded avatar world matrices to identity and flip
AidanCaruso Aug 14, 2024
0e35c95
add back skeleton helper, move skinned mesh and bone components to sp…
HexaField Aug 15, 2024
ef0e1f6
material bug fix
HexaField Aug 15, 2024
3e60296
Replace some usages of ModelComponent with GLTFComponent, and start t…
HexaField Aug 15, 2024
8b6ed07
license
HexaField Aug 15, 2024
5a674d6
fix regression with avatar animation track binding
HexaField Aug 16, 2024
a80ec60
ready player me almost works
AidanCaruso Aug 16, 2024
3f94954
fix world matrix calculations in tpose enforcement function
AidanCaruso Aug 17, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
import { useTexture } from '@etherealengine/engine/src/assets/functions/resourceLoaderHooks'
import { GLTFDocumentState } from '@etherealengine/engine/src/gltf/GLTFDocumentState'
import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent'
import { getModelSceneID } from '@etherealengine/engine/src/scene/functions/loaders/ModelFunctions'
import { NO_PROXY, defineState, getMutableState, useHookstate } from '@etherealengine/hyperflux'
import { DirectionalLightComponent, TransformComponent } from '@etherealengine/spatial'
import { CameraComponent } from '@etherealengine/spatial/src/camera/components/CameraComponent'
Expand All @@ -66,6 +65,7 @@ import React, { useEffect } from 'react'
import { Color, Euler, Material, MathUtils, Matrix4, Mesh, Quaternion, Sphere, SphereGeometry, Vector3 } from 'three'

import config from '@etherealengine/common/src/config'
import { GLTFComponent } from '@etherealengine/engine/src/gltf/GLTFComponent'
import { ErrorComponent } from '@etherealengine/engine/src/scene/components/ErrorComponent'
import { ShadowComponent } from '@etherealengine/engine/src/scene/components/ShadowComponent'
import { useFind } from '@etherealengine/spatial/src/common/functions/FeathersHooks'
Expand Down Expand Up @@ -414,7 +414,7 @@ const ThumbnailJobReactor = () => {
const modelEntity = state.modelEntity.value
const lightEntity = state.lightEntity.value

const sceneID = getModelSceneID(modelEntity)
const sceneID = GLTFComponent.getInstanceID(modelEntity)
if (!sceneState.value[sceneID]) return

try {
Expand Down
2 changes: 1 addition & 1 deletion packages/client-core/src/media/webcam/WebcamInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { Entity } from '@etherealengine/ecs/src/Entity'
import { defineQuery } from '@etherealengine/ecs/src/QueryFunctions'
import { AvatarRigComponent } from '@etherealengine/engine/src/avatar/components/AvatarAnimationComponent'
import { AvatarComponent } from '@etherealengine/engine/src/avatar/components/AvatarComponent'
import { SkinnedMeshComponent } from '@etherealengine/engine/src/avatar/components/SkinnedMeshComponent'
import { AvatarNetworkAction } from '@etherealengine/engine/src/avatar/state/AvatarNetworkActions'
import { defineActionQueue, getMutableState } from '@etherealengine/hyperflux'
import { GroupComponent } from '@etherealengine/spatial/src/renderer/components/GroupComponent'
import { iterateEntityNode } from '@etherealengine/spatial/src/transform/components/EntityTree'

import { SkinnedMeshComponent } from '@etherealengine/spatial/src/renderer/components/SkinnedMeshComponent'
import { MediaStreamState } from '../../transports/MediaStreams'
import { WebcamInputComponent } from './WebcamInputComponent'

Expand Down
3 changes: 2 additions & 1 deletion packages/client-core/src/world/Location.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ const LocationPage = ({ online }: Props) => {
useLoadEngineWithScene()

useEffect(() => {
if (ready.value) logger.info({ event_name: 'enter_location' })
if (!ready.value) return
logger.info({ event_name: 'enter_location' })
return () => logger.info({ event_name: 'exit_location' })
}, [ready.value])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ import { getState } from '@etherealengine/hyperflux'
import { EntityTreeComponent } from '@etherealengine/spatial/src/transform/components/EntityTree'

import { UUIDComponent } from '@etherealengine/ecs'
import { GLTFComponent } from '@etherealengine/engine/src/gltf/GLTFComponent'
import { GLTFSnapshotState } from '@etherealengine/engine/src/gltf/GLTFState'
import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent'
import { getModelSceneID } from '@etherealengine/engine/src/scene/functions/loaders/ModelFunctions'
import { GLTF } from '@gltf-transform/core'
import { EditorState } from '../../services/EditorServices'

Expand Down Expand Up @@ -84,7 +84,7 @@ function buildHierarchyTree(
array.push(item)

if (hasComponent(entity, ModelComponent) && showModelChildren) {
const modelSceneID = getModelSceneID(entity)
const modelSceneID = GLTFComponent.getInstanceID(entity)
const snapshotState = getState(GLTFSnapshotState)
const snapshots = snapshotState[modelSceneID]
if (snapshots) {
Expand Down
6 changes: 3 additions & 3 deletions packages/editor/src/functions/sceneFunctions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import config from '@etherealengine/common/src/config'
import multiLogger from '@etherealengine/common/src/logger'
import { StaticResourceType, fileBrowserPath, staticResourcePath } from '@etherealengine/common/src/schema.type.module'
import { cleanString } from '@etherealengine/common/src/utils/cleanString'
import { EntityUUID, UUIDComponent, UndefinedEntity } from '@etherealengine/ecs'
import { getComponent, setComponent } from '@etherealengine/ecs/src/ComponentFunctions'
import { EntityUUID, UndefinedEntity } from '@etherealengine/ecs'
import { setComponent } from '@etherealengine/ecs/src/ComponentFunctions'
import { Engine } from '@etherealengine/ecs/src/Engine'
import { GLTFComponent } from '@etherealengine/engine/src/gltf/GLTFComponent'
import { GLTFDocumentState } from '@etherealengine/engine/src/gltf/GLTFDocumentState'
Expand Down Expand Up @@ -93,7 +93,7 @@ export const saveSceneGLTF = async (
if (signal.aborted) throw new Error(i18n.t('editor:errors.saveProjectAborted'))

const { rootEntity } = getState(EditorState)
const sourceID = `${getComponent(rootEntity, UUIDComponent)}-${getComponent(rootEntity, GLTFComponent).src}`
const sourceID = GLTFComponent.getInstanceID(rootEntity)

const sceneName = cleanString(sceneFile!.replace('.scene.json', '').replace('.gltf', ''))
const currentSceneDirectory = getState(EditorState).scenePath!.split('/').slice(0, -1).join('/')
Expand Down
3 changes: 1 addition & 2 deletions packages/editor/src/systems/ClickPlacementSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import { ModelComponent } from '@etherealengine/engine/src/scene/components/Mode
import { SourceComponent } from '@etherealengine/engine/src/scene/components/SourceComponent'
import { entityJSONToGLTFNode } from '@etherealengine/engine/src/scene/functions/GLTFConversion'
import { createSceneEntity } from '@etherealengine/engine/src/scene/functions/createSceneEntity'
import { getModelSceneID } from '@etherealengine/engine/src/scene/functions/loaders/ModelFunctions'
import { toEntityJson } from '@etherealengine/engine/src/scene/functions/serializeWorld'
import {
NO_PROXY,
Expand Down Expand Up @@ -173,7 +172,7 @@ const PlacementModelReactor = (props: { placementEntity: Entity }) => {

useEffect(() => {
if (!placementModel) return
const sceneID = getModelSceneID(props.placementEntity)
const sceneID = GLTFComponent.getInstanceID(props.placementEntity)
if (!sceneState.scenes[sceneID]) return
iterateEntityNode(props.placementEntity, (entity) => {
const mesh = getOptionalComponent(entity, MeshComponent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import { getComponent, setComponent } from '@etherealengine/ecs/src/ComponentFun
import { Entity, UndefinedEntity } from '@etherealengine/ecs/src/Entity'
import { EntityTreeComponent, iterateEntityNode } from '@etherealengine/spatial/src/transform/components/EntityTree'

import { GLTFComponent } from '../../../../gltf/GLTFComponent'
import { SourceComponent } from '../../../../scene/components/SourceComponent'
import { getModelSceneID } from '../../../../scene/functions/loaders/ModelFunctions'
import { GLTFExporterPlugin, GLTFWriter } from '../GLTFExporter'
import { ExporterExtension } from './ExporterExtension'

Expand All @@ -46,7 +46,7 @@ export default class SourceHandlerExtension extends ExporterExtension implements
//we allow saving of any object that has a source equal to or parent of the root's source
const validSrcs: Set<string> = new Set()
if (!this.writer.options.srcEntity) return
validSrcs.add(getModelSceneID(this.writer.options.srcEntity!))
validSrcs.add(GLTFComponent.getInstanceID(this.writer.options.srcEntity!))
const root = (Array.isArray(input) ? input[0] : input) as Object3D
let walker: Entity | null = root.entity
while (walker !== null) {
Expand Down
44 changes: 22 additions & 22 deletions packages/engine/src/assets/loaders/gltf/GLTFExtensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,28 @@ import { assignExtrasToUserData } from './GLTFLoaderFunctions'
import { GLTFParser } from './GLTFParser'

export const EXTENSIONS = {
KHR_BINARY_GLTF: 'KHR_binary_glTF',
KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',
KHR_MATERIALS_IOR: 'KHR_materials_ior',
KHR_MATERIALS_SHEEN: 'KHR_materials_sheen',
KHR_MATERIALS_SPECULAR: 'KHR_materials_specular',
KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',
KHR_MATERIALS_IRIDESCENCE: 'KHR_materials_iridescence',
KHR_MATERIALS_ANISOTROPY: 'KHR_materials_anisotropy',
KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
KHR_MATERIALS_VOLUME: 'KHR_materials_volume',
KHR_TEXTURE_BASISU: 'KHR_texture_basisu',
KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength',
EXT_MATERIALS_BUMP: 'EXT_materials_bump',
EXT_TEXTURE_WEBP: 'EXT_texture_webp',
EXT_TEXTURE_AVIF: 'EXT_texture_avif',
EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression',
EXT_MESH_GPU_INSTANCING: 'EXT_mesh_gpu_instancing',
EE_MATERIAL: 'EE_material'
KHR_BINARY_GLTF: 'KHR_binary_glTF' as const,
KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression' as const,
KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual' as const,
KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat' as const,
KHR_MATERIALS_IOR: 'KHR_materials_ior' as const,
KHR_MATERIALS_SHEEN: 'KHR_materials_sheen' as const,
KHR_MATERIALS_SPECULAR: 'KHR_materials_specular' as const,
KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission' as const,
KHR_MATERIALS_IRIDESCENCE: 'KHR_materials_iridescence' as const,
KHR_MATERIALS_ANISOTROPY: 'KHR_materials_anisotropy' as const,
KHR_MATERIALS_UNLIT: 'KHR_materials_unlit' as const,
KHR_MATERIALS_VOLUME: 'KHR_materials_volume' as const,
KHR_TEXTURE_BASISU: 'KHR_texture_basisu' as const,
KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform' as const,
KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization' as const,
KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength' as const,
EXT_MATERIALS_BUMP: 'EXT_materials_bump' as const,
EXT_TEXTURE_WEBP: 'EXT_texture_webp' as const,
EXT_TEXTURE_AVIF: 'EXT_texture_avif' as const,
EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression' as const,
EXT_MESH_GPU_INSTANCING: 'EXT_mesh_gpu_instancing' as const,
EE_MATERIAL: 'EE_material' as const
}

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/engine/src/assets/loaders/gltf/GLTFLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,12 @@ import {
} from './GLTFExtensions'
import { GLTFParser } from './GLTFParser'
import { KTX2Loader } from './KTX2Loader'
import { MeshoptDecoder } from './meshopt_decoder'

export class GLTFLoader extends Loader {
dracoLoader = null as null | DRACOLoader
ktx2Loader = null as null | KTX2Loader
meshoptDecoder = null
meshoptDecoder = null as null | MeshoptDecoder

pluginCallbacks = [] as any[]

Expand Down
13 changes: 8 additions & 5 deletions packages/engine/src/assets/loaders/gltf/GLTFParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ import {
} from './GLTFLoaderFunctions'
import { KTX2Loader } from './KTX2Loader'

function getImageURIMimeType(uri) {
export function getImageURIMimeType(uri) {
if (uri.search(/\.jpe?g($|\?)/i) > 0 || uri.search(/^data\:image\/jpeg/) === 0) return 'image/jpeg'
if (uri.search(/\.webp($|\?)/i) > 0 || uri.search(/^data\:image\/webp/) === 0) return 'image/webp'

Expand All @@ -123,10 +123,13 @@ declare module '@gltf-transform/core/dist/types/gltf.d.ts' {
}
}

type GLTFParserOptions = {
export type GLTFParserOptions = {
body: null | ArrayBuffer
documentID: string
document: GLTF.IGLTF
crossOrigin: 'anonymous' | string
ktx2Loader: KTX2Loader
manager: LoadingManager | any
manager: LoadingManager
meshoptDecoder: any
path: string
requestHeader: Record<string, any>
Expand Down Expand Up @@ -688,7 +691,7 @@ export class GLTFParser {

if (sourceDef.uri) {
const handler = options.manager.getHandler(sourceDef.uri)
if (handler !== null) loader = handler
if (handler !== null) loader = handler as any
}

return this.loadTextureImage(textureIndex, sourceIndex, loader)
Expand Down Expand Up @@ -1767,7 +1770,7 @@ export class GLTFParser {

/* GLTFREGISTRY */

class GLTFRegistry {
export class GLTFRegistry {
objects = {}

get(key) {
Expand Down
36 changes: 36 additions & 0 deletions packages/engine/src/assets/loaders/gltf/meshopt_decoder.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
CPAL-1.0 License

The contents of this file are subject to the Common Public Attribution License
Version 1.0. (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE.
The License is based on the Mozilla Public License Version 1.1, but Sections 14
and 15 have been added to cover use of software over a computer network and
provide for limited attribution for the Original Developer. In addition,
Exhibit A has been modified to be consistent with Exhibit B.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License.

The Original Code is Ethereal Engine.

The Original Developer is the Initial Developer. The Initial Developer of the
Original Code is the Ethereal Engine team.

All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023
Ethereal Engine. All Rights Reserved.
*/


export type MeshoptDecoder = {
supported: boolean;
ready: Promise<void>;
useWorkers: (numWorkers: number) => void;
decodeVertexBuffer: (buffer: ArrayBuffer, count: number, stride: number, filter: number) => ArrayBuffer;
decodeIndexBuffer: (buffer: ArrayBuffer, count: number, filter: number) => ArrayBuffer;
decodeIndexSequence: (buffer: ArrayBuffer, count: number, filter: number) => ArrayBuffer;
decodeGltfBuffer: (buffer: Uint8Array, count: number, stride: number, source: Uint8Array, mode: number, filter: number) => void;
decodeGltfBufferAsync?: (count: number, stride: number, source: Uint8Array, mode: number, filter: number) => Promise<{ buffer: ArrayBuffer }>;
}
Loading