Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickRyanMS committed Sep 25, 2024
2 parents d4725d1 + d0c5314 commit 7b9e554
Show file tree
Hide file tree
Showing 39 changed files with 671 additions and 278 deletions.
28 changes: 28 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "msedge",
"request": "launch",
"name": "Documentation (Edge)",
"url": "http://localhost:3000",
"preLaunchTask": "Dev"
},
{
"type": "chrome",
"request": "launch",
"name": "Documentation (Chrome)",
"url": "http://localhost:3000",
"preLaunchTask": "Dev"
}
],
"compounds": [
{
"name": "Default Launch",
"configurations": ["Documentation (Edge)"]
}
]
}
31 changes: 31 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Dev",
"type": "shell",
"command": "npm run dev",
"isBackground": true,
"runOptions": {
"instanceLimit": 1
},
"presentation": {
"group": "watch"
},
"problemMatcher": {
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": ".*Starting...",
},
"endsPattern": {
"regexp": ".*Ready in .*ms",
},
},
},
},
],
}
5 changes: 5 additions & 0 deletions configuration/structure.json
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,11 @@
"friendlyName": "Progressively Load .glTF Files",
"children": {},
"content": "features/featuresDeepDive/importers/glTF/progressiveglTFLoad"
},
"createExtensions": {
"friendlyName": "Create Your Own glTF Extensions",
"children": {},
"content": "features/featuresDeepDive/importers/glTF/createExtensions"
}
},
"content": "features/featuresDeepDive/importers/glTF"
Expand Down
4 changes: 2 additions & 2 deletions content/features/featuresDeepDive/importers.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ video-content:

The built in file type is `.babylon` and Babylon.js can load these without a plugin. All other file types require a plugin as described in this section.

Possible file types are gLTF, obj, stl
Possible file types are glTF, splat, obj, stl.

To help you with imported assets there is a manager for them.

**Note:** Since meshes you import can have a _rotationQuaternion_ set before applying a rotation set the _rotationQuaternion_ to _null
**Note:** Since meshes you import can have a `rotationQuaternion` set before applying a rotation set the `rotationQuaternion` to `null`.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ container.removeAllFromScene();

<Playground id="#5NFRVE#1" title="Asset Container Adding and Removing Assets" description="Simple Example of adding and removing asset container assets into your scene." image="/img/playgroundsAndNMEs/divingDeeperAssetContainer1.jpg"/>

This can be used to add/remove all objects in a scene without the need to exit WebVR. <Playground id="#JA1ND3#48" title="Asset Container Adding and Removing Assets in WebVR" description="Simple Example of adding and removing asset container assets into your WebVR scene." image="/img/playgroundsAndNMEs/divingDeeperAssetContainer2.jpg"/>
This can be used to add/remove all objects in a scene without the need to exit WebVR. <Playground id="#JA1ND3#1016" title="Asset Container Adding and Removing Assets in WebVR" description="Simple Example of adding and removing asset container assets into your WebVR scene." image="/img/playgroundsAndNMEs/divingDeeperAssetContainer2.jpg"/>

When creating assets manually the moveAllFromScene method can be used to move all assets currently in a scene into an AssetContainer and remove them from the scene for later use.

Expand Down Expand Up @@ -62,7 +62,7 @@ The return entries object will contain:
- skeletons: A list of all the skeletons created by the duplication process
- animationGroups: A list of all the animation groups created by the duplication process

<Playground id="#S7E00P" title="Instantiating Asset Container Assets" description="Simple Example of using asset containers as templates to duplicate assets in a scene." image="/img/playgroundsAndNMEs/divingDeeperAssetContainer3.jpg"/>
<Playground id="#S7E00P#439" title="Instantiating Asset Container Assets" description="Simple Example of using asset containers as templates to duplicate assets in a scene." image="/img/playgroundsAndNMEs/divingDeeperAssetContainer3.jpg"/>

You can also set two parameters to the call to `instantiateModelsToScene`:

Expand Down
110 changes: 85 additions & 25 deletions content/features/featuresDeepDive/importers/createImporters.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,97 @@ video-content:

By default, babylon.js comes with an importer for .babylon files.

You can also create your own importer by providing a specific object to the `BABYLON.SceneLoader.RegisterPlugin` function.
You can also create your own importer by providing a specific object to the `BABYLON.registerSceneLoaderPlugin` function.

This object must have three properties:
### Plugins

- A list of supported file extensions (`extensions`)
- An `importMesh` function to import specific meshes
- A `load` function to import complete scene
- A `loadAssets` function to import all babylon elements from the file but do not add them to the scene
A file importer should implement the `ISceneLoaderPluginAsync` interface.

Here is a sample importer object:
<Alert severity="warning" title="Warning" description="Avoid using ISceneLoaderPlugin as it is deprecated and has been replaced by ISceneLoaderPluginAsync" />

```javascript
BABYLON.SceneLoader.RegisterPlugin({
extensions: ".babylon",
importMesh: function (meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons) {
return true;
},
load: function (scene, data, rootUrl) {
return true;
An abbreviated example of a file importer (scene loader plugin) might look something like this:

```typescript
import { ISceneLoaderPluginAsync } from "@babylonjs/core/Loading/sceneLoader";

class MyCustomImporter implements ISceneLoaderPluginAsync {
public readonly name = "myCustomImporter";

public readonly extensions = ".myCustomExtension";

public async importMeshAsync(...) {
// Load specified meshes into the Scene
}

public async loadAsync(...) {
// Load all data into the Scene
}

public async loadAssetContainerAsync(...) {
// Load all data into an AssetContainer
}
}
```

A plugin instance can be passed to `BABYLON.registerSceneLoaderPlugin`, but plugin factories are more flexible and full featured, so we recommend using them to create your custom importers.

### Plugin Factories

When you register a plugin, you can register a plugin factory rather than a plugin instance. The factory must have a `createPlugin` function that returns an instance of the plugin. The factory is invoked each time a load function is called. The `pluginOptions` property of the loader options are also passed to the factory function. This makes it possible for your file importer to be configurable through options.

A plugin factory can return the plugin instance either synchronously or asynchronously. We recommend you dynamically import your plugin to avoid loading it until it is needed. For example:

```typescript
import { registerSceneLoaderPlugin } from "@babylonjs/core/Loading/sceneLoader";

registerSceneLoaderPlugin({
name: "myCustomImporter",
extensions: ".myCustomExtension",
createPlugin: async () => {
const { MyCustomImporter } = await import("./MyCustomImporter");
return new MyCustomImporter();
},
loadAssets(scene, data, rootUrl) {
const container = new AssetContainer(scene);
return container;
});
```

To expose options for your custom file importer, you should first augment the `SceneLoaderPluginOptions` interface to add options for your importer. For example, if the name of your importer is `myCustomImporter`, you would add the following to your code:

```typescript
type MyCustomImporterOptions = { option1?: string, option2?: number };

declare module "@babylonjs/core" {
export interface SceneLoaderPluginOptions {
myCustomImporter: MyCustomImporterOptions;
}
}
```

Then, when you register your file importer, you can access the options like this:

```typescript
import { registerSceneLoaderPlugin } from "@babylonjs/core/Loading/sceneLoader";

registerSceneLoaderPlugin({
name: "myCustomImporter",
extensions: ".myCustomExtension",
createPlugin: async (options) => {
const { MyCustomImporter } = await import("./MyCustomImporter");
return new MyCustomImporter(options["myCustomImporter"]);
},
});
```

- `meshesNames` is the names of meshes to import
- `scene` is the scene to load data into
- `data` is the string representation of the file to load
- `rootUrl` defines the root URL of your assets
- `meshes` is the list of imported meshes
- `particleSystems` is the list of imported particle systems
- `skeletons` is the list of imported skeletons
Note that in this example, you will need to modify the `MyCustomImporter` class to accept options (`MyCustomImporterOptions`) in its constructor.

Finally, these options can be passed into one of the scene loader functions like this:

```typescript
await loadAssetContainerAsync("path/to/model", scene, {
pluginOptions: {
myCustomImporter: {
option1: "hello world",
option2: 42,
},
},
});
```
25 changes: 17 additions & 8 deletions content/features/featuresDeepDive/importers/glTF.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,24 @@ This loader supports only glTF 1.0 and will fail to load glTF 2.0.
<script src="babylon.glTF1FileLoader.js"></script>
```

## NPM

When using the Babylon npm packages in your own build, it is preferable to register the glTF file importer via the top level dynamic loader registration function `registerBuiltInLoaders`. See [Loading Any File Type](/features/featuresDeepDive/importers/loadingFileTypes#npm) for more information.

If you want to import the glTF file importer statically (not recommended), you can do so via:

```javascript
import "@babylonjs/loaders/glTF/2.0";
```

You can read more about [NPM support](/setup/frameworkPackages/npmSupport)

## Loading the Scene

Use one of the static function on the `SceneLoader` to load a glTF asset.
Use one of scene loader functions to load a glTF asset.
See [Load from any file type](/features/featuresDeepDive/importers/loadingFileTypes).

See an example here: <Playground id="#WGZLGJ" title="Load a glTF Asset" description="Simple example showing how load a .glTF asset into your scene." image="/img/playgroundsAndNMEs/divingDeeperglTF1.jpg" isMain={true} category="Import"/>
See an example here: <Playground id="#WGZLGJ#10552" title="Load a glTF Asset" description="Simple example showing how load a .glTF asset into your scene." image="/img/playgroundsAndNMEs/divingDeeperglTF1.jpg" isMain={true} category="Import"/>

## API (Version 2)

Expand All @@ -84,7 +96,9 @@ See the available [properties and methods](/typedoc/classes/babylon.gltffileload

## Extensions

See the available [extensions](/typedoc/modules/babylon.gltf2.loader.extensions) from the API documentation.
See the built in [extensions](/typedoc/modules/babylon.gltf2.loader.extensions) from the API documentation.

You can also [create your own extensions](/features/featuresDeepDive/importers/glTF/createExtensions).

## API (Version 1)

Expand All @@ -105,8 +119,3 @@ Set this property to true in order to work with homogeneous coordinates, availab
```javascript
BABYLON.GLTFFileLoader.HomogeneousCoordinates = true;
```

## Extensions

[KHR_binary_glTF](https://github.com/KhronosGroup/glTF/tree/master/extensions/1.0/Khronos/KHR_binary_glTF)
[KHR_materials_common](https://github.com/KhronosGroup/glTF/tree/master/extensions/1.0/Khronos/KHR_materials_common)
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
title: Create glTF extensions
image:
description: Learn about creating new glTF loader extensions.
keywords: diving deeper, import, importing assets, asset, glTF, extensions
further-reading: ["https://babylonjs.medium.com/extending-the-gltf-loader-in-babylon-js-588e48fb692b"]
video-overview:
video-content:
---

## Introduction

The glTF format includes the concept of extensions. Usually glTF loader extensions map 1:1 with a corresponding glTF format extensions. However, it is possible to create custom glTF loader extensions are unrelated to glTF format extensions and simply perform some additional processing on the loaded glTF data.

The glTF loader includes support for many glTF format extensions through built-in glTF loader extensions. It is also possible to create your own glTF loader extensions.

## Extensions

Extensions are defined by implementing the `IGLTFLoaderExtension` interface (from `@babylonjs/loaders/glTF/2.0`). An abbreviated example would look something like this:

```typescript
import { IGLTFLoaderExtension } from "@babylonjs/loaders/glTF/2.0";

class MyCustomExtension implements IGLTFLoaderExtension {
public readonly name = "myCustomExtension";
public enabled = true;
public order = 100;

// Implement any of the optional functions, such as:
public loadSceneAsync(): Nullable<Promise<void>> {
// Modify the default behavior when loading scenes.
}
}
```

## Extension Factories

When you register a loader extension, you register an extension factory. The factory is a function that takes the glTF loader and returns an extension instance synchronously or asynchronously. This allows you to dynamically import your extension to avoid loading it until it is needed. A simple example might look something like this:

```typescript
import { registerGLTFExtension } from "@babylonjs/loaders/glTF/2.0";

registerGLTFExtension("myCustomExtension", true, async (loader) => {
const { MyCustomExtension } = await import("./MyCustomExtension");
return new MyCustomExtension(loader);
});
```

<Alert severity="info" title="glTF Format Extensions" description="The second parameter of registerGLTFExtension specifies whether the extension is associated with a glTF format extension. If it is, it will only be used when loading glTFs that use that extension. If it is not, it will be used when loading any glTF." />

## Extension Options

To expose options for your custom glTF loader extension, you should first augment the `GLTFLoaderExtensionOptions` interface to add options for your extension. For example:

```typescript
type MyCustomExtensionOptions = { option1?: string, option2?: number };

declare module "@babylonjs/loaders" {
export interface GLTFLoaderExtensionOptions {
myCustomExtension: MyCustomImporterOptions;
}
}
```

Then, when you register your extension, you can access the options like this:

```typescript
class MyCustomExtension implements IGLTFLoaderExtension {
constructor (loader: GLTFLoader) {
const options = loader.parent.extensionOptions["myCustomExtension"];
}
}
```

Finally, these options can be passed into one of the scene loader functions like this:

```typescript
await loadAssetContainerAsync("path/to/model", scene, {
pluginOptions: {
glTF: {
extensionOptions: {
myCustomExtension: {
option1: "hello world",
option2: 42,
},
},
},
},
});
```
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ These files can be used just like a standard _.babylon_ scene except that they w

You have to put the _.babylonmeshdata_ and _.babylongeometrydata_ files in the same folder as the _.incremental.babylon_ file.

You can find a demo of an incremental scene here: <Playground id="#JA1ND3#943" title="Incremental Loading Example" description="Simple Example of incremental loading assets." image="/img/playgroundsAndNMEs/divingDeeperIncrementalLoading1.jpg"/>
You can find a demo of an incremental scene here: <Playground id="#JA1ND3#1017" title="Incremental Loading Example" description="Simple Example of incremental loading assets." image="/img/playgroundsAndNMEs/divingDeeperIncrementalLoading1.jpg"/>

## Detailed Step by step

Expand Down Expand Up @@ -45,9 +45,8 @@ For users less experienced with command line tools, here's a more detailed step
8. And you're ready to load it into Babylon!

```javascript
BABYLON.SceneLoader.Append("src/", "my-scene.incremental.babylon", scene, function () {
console.log("My incremental file was loaded! WOHOO!");
});
await BABYLON.appendSceneAsync("src/my-scene.incremental.babylon", scene);
console.log("My incremental file was loaded! WOHOO!");
```

## Node.js based incremental file converter
Expand Down
6 changes: 4 additions & 2 deletions content/features/featuresDeepDive/importers/loadFromMemory.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ const assetUrl = URL.createObjectURL(assetBlob);
Then finally we load the asset into the scene from the url which points to the memory blob.

```javascript
await BABYLON.SceneLoader.AppendAsync(assetUrl, undefined, scene, undefined, ".glb");
await BABYLON.appendSceneAsync(assetUrl, scene, {
pluginExtension: ".glb"
});
```

It's important to note that the Babylon scene loader will use the correct loader based on the file extension of the asset you're trying to load. In this case, since we're loading binary data saved to memory, the scene loader needs to be explicitly told which loader to use. This is why the final argument in the AppendAsync method is ".glb".
It's important to note that the Babylon scene loader will use the correct loader based on the file extension of the asset you're trying to load. In this case, since we're loading binary data saved to memory, the scene loader needs to be explicitly told which loader to use. This is why the final argument in the `appendSceneAsync` method (the options object) specifies the `pluginExtension` as `".glb"`.
Loading

0 comments on commit 7b9e554

Please sign in to comment.