tosijs-3d 0.11.5 → 0.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -2
- package/changelog/v0.11.6.md +37 -0
- package/dist/b3d-biped.d.ts +8 -0
- package/dist/b3d-biped.d.ts.map +1 -1
- package/dist/b3d-biped.js +207 -69
- package/dist/b3d-biped.js.map +1 -1
- package/dist/b3d-launcher.d.ts.map +1 -1
- package/dist/b3d-launcher.js +3 -0
- package/dist/b3d-launcher.js.map +1 -1
- package/dist/b3d-utils.d.ts +5 -0
- package/dist/b3d-utils.d.ts.map +1 -1
- package/dist/b3d-utils.js +19 -13
- package/dist/b3d-utils.js.map +1 -1
- package/dist/bar-menu.d.ts +5 -0
- package/dist/bar-menu.d.ts.map +1 -1
- package/dist/bar-menu.js +55 -3
- package/dist/bar-menu.js.map +1 -1
- package/dist/character-builder.d.ts.map +1 -1
- package/dist/character-builder.js +631 -655
- package/dist/character-builder.js.map +1 -1
- package/dist/character-file.d.ts +72 -0
- package/dist/character-file.d.ts.map +1 -0
- package/dist/character-file.js +212 -0
- package/dist/character-file.js.map +1 -0
- package/dist/character-store.d.ts +29 -0
- package/dist/character-store.d.ts.map +1 -0
- package/dist/character-store.js +191 -0
- package/dist/character-store.js.map +1 -0
- package/dist/character.d.ts +126 -0
- package/dist/character.d.ts.map +1 -0
- package/dist/character.js +1210 -0
- package/dist/character.js.map +1 -0
- package/dist/choose-file.d.ts +12 -0
- package/dist/choose-file.d.ts.map +1 -0
- package/dist/choose-file.js +31 -0
- package/dist/choose-file.js.map +1 -0
- package/dist/cloth-shading.d.ts +17 -13
- package/dist/cloth-shading.d.ts.map +1 -1
- package/dist/cloth-shading.js +37 -58
- package/dist/cloth-shading.js.map +1 -1
- package/dist/effect-tool.d.ts.map +1 -1
- package/dist/effect-tool.js +1 -10
- package/dist/effect-tool.js.map +1 -1
- package/dist/fabrics.d.ts +14 -0
- package/dist/fabrics.d.ts.map +1 -0
- package/dist/fabrics.js +63 -0
- package/dist/fabrics.js.map +1 -0
- package/dist/garment-cut.d.ts.map +1 -1
- package/dist/garment-cut.js +8 -6
- package/dist/garment-cut.js.map +1 -1
- package/dist/garment-file.d.ts +7 -2
- package/dist/garment-file.d.ts.map +1 -1
- package/dist/garment-file.js +4 -1
- package/dist/garment-file.js.map +1 -1
- package/dist/human-face.d.ts +9 -0
- package/dist/human-face.d.ts.map +1 -1
- package/dist/human-face.js +70 -0
- package/dist/human-face.js.map +1 -1
- package/dist/human-proxy.d.ts.map +1 -1
- package/dist/human-proxy.js +7 -0
- package/dist/human-proxy.js.map +1 -1
- package/dist/human-rig.d.ts +31 -1
- package/dist/human-rig.d.ts.map +1 -1
- package/dist/human-rig.js +65 -1
- package/dist/human-rig.js.map +1 -1
- package/dist/icon-data.d.ts +8 -0
- package/dist/icon-data.d.ts.map +1 -1
- package/dist/icon-data.js +8 -0
- package/dist/icon-data.js.map +1 -1
- package/dist/index.d.ts +23 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/material-apply.d.ts +8 -0
- package/dist/material-apply.d.ts.map +1 -0
- package/dist/material-apply.js +60 -0
- package/dist/material-apply.js.map +1 -0
- package/dist/material-picker.d.ts +32 -0
- package/dist/material-picker.d.ts.map +1 -0
- package/dist/material-picker.js +445 -0
- package/dist/material-picker.js.map +1 -0
- package/dist/material-preview.d.ts +10 -0
- package/dist/material-preview.d.ts.map +1 -0
- package/dist/material-preview.js +130 -0
- package/dist/material-preview.js.map +1 -0
- package/dist/material-recipe.d.ts +113 -0
- package/dist/material-recipe.d.ts.map +1 -0
- package/dist/material-recipe.js +407 -0
- package/dist/material-recipe.js.map +1 -0
- package/dist/playground.d.ts.map +1 -1
- package/dist/playground.js +65 -13
- package/dist/playground.js.map +1 -1
- package/dist/retarget.d.ts.map +1 -1
- package/dist/retarget.js +126 -1
- package/dist/retarget.js.map +1 -1
- package/dist/rig-build.d.ts +76 -1
- package/dist/rig-build.d.ts.map +1 -1
- package/dist/rig-build.js +509 -3
- package/dist/rig-build.js.map +1 -1
- package/dist/rig-fit.d.ts +18 -0
- package/dist/rig-fit.d.ts.map +1 -1
- package/dist/rig-fit.js +283 -39
- package/dist/rig-fit.js.map +1 -1
- package/dist/rig-recipe.d.ts +7 -0
- package/dist/rig-recipe.d.ts.map +1 -1
- package/dist/rig-recipe.js +21 -0
- package/dist/rig-recipe.js.map +1 -1
- package/dist/rig-tool.d.ts +37 -0
- package/dist/rig-tool.d.ts.map +1 -1
- package/dist/rig-tool.js +799 -270
- package/dist/rig-tool.js.map +1 -1
- package/dist/rigged-body.d.ts +129 -0
- package/dist/rigged-body.d.ts.map +1 -0
- package/dist/rigged-body.js +311 -0
- package/dist/rigged-body.js.map +1 -0
- package/dist/svg-icons.d.ts +6 -1
- package/dist/svg-icons.d.ts.map +1 -1
- package/dist/svg-icons.js +23 -2
- package/dist/svg-icons.js.map +1 -1
- package/dist/tailor-tool.d.ts +63 -0
- package/dist/tailor-tool.d.ts.map +1 -0
- package/dist/tailor-tool.js +357 -0
- package/dist/tailor-tool.js.map +1 -0
- package/dist/widgets3d.d.ts.map +1 -1
- package/dist/widgets3d.js +15 -0
- package/dist/widgets3d.js.map +1 -1
- package/package.json +1 -1
- package/static/attributes.json +48 -0
- package/static/attributes.txt +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -12,13 +12,14 @@ Upgrading across a minor? Start with [Migration](/Migration/).
|
|
|
12
12
|
|
|
13
13
|
## Unreleased
|
|
14
14
|
|
|
15
|
-
## 0.11.
|
|
15
|
+
## 0.11.6
|
|
16
16
|
|
|
17
|
-
The latest release. The character
|
|
17
|
+
The latest release. The character leaves the builder: any body (MakeHuman's, Blender's, Quaternius' or your own mesh) rigged, dressed and tailored the same way; a character file that carries its body; `makeCharacter`, and `<tosi-b3d-biped character>` to walk it in a game; a material picker. [Read 0.11.6](/v0.11.6/).
|
|
18
18
|
|
|
19
19
|
## Every version
|
|
20
20
|
|
|
21
21
|
<!-- toc -->
|
|
22
|
+
- [0.11.6](/v0.11.6/)
|
|
22
23
|
- [0.11.5](/v0.11.5/)
|
|
23
24
|
- [0.11.4](/v0.11.4/)
|
|
24
25
|
- [0.11.3](/v0.11.3/)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# 0.11.6
|
|
2
|
+
|
|
3
|
+
<!--{ "parent": "CHANGELOG", "order": 9988994 }-->
|
|
4
|
+
|
|
5
|
+
The character leaves the builder. Any body (MakeHuman's, Blender's, Quaternius', or a mesh of your own) is rigged, dressed and tailored the same way; a character is a file that carries its body, `makeCharacter` builds it anywhere, and `<tosi-b3d-biped character>` walks it in a game. The biped playground plays as a character you saved. Materials get a picker of their own.
|
|
6
|
+
|
|
7
|
+
Size: barrel (min, packages external) 1430.1 KB raw / 493.3 KB gz, +5.74% on 0.11.5 (rigged bodies, characters, the tailor and rig tools as tools, the material picker).
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`RiggedBody`** (rigged-body): one shape for a character's body whoever made it: the rest mesh, UAL's joints, skin weights, regions, and how it was made. Three producers: `bodyFromMarkers` (any mesh plus eight markers, guessed if absent), `humanBodyMaker(pack)` (MakeHuman's sliders) and `loadSkinnedBody` (a file already skinned to UAL's skeleton, as Quaternius' characters are, taken with its own joints and weights). `buildBody` makes a Babylon skeleton from any of them; `autoRig` and `loadRigTriangles` (rig-build) are the whole path in two calls. A body from a file carries its `uvs`, `colors` and `surfaces` (its materials), and its eyeballs (`body.eyes`, objects named as eyes), which take the iris dial and the gaze.
|
|
12
|
+
- **`lidBlink(positions, eye)`**: a blink made from a body's shape, for bodies with eyeballs and no blink targets (Blender's Human Base Meshes). Bodies rigged from markers blink with it.
|
|
13
|
+
- **`makeCharacter(scene, assets, { settings, garments, gaze })`** (character): the character builder's character from its settings, outside the builder. `set(changes)` applies only what changed; `skeleton`, `recipe` and `groundFor(clip)` are what playing clips on it needs. `loadCharacterAssets` loads MakeHuman's pack and the hair once per scene.
|
|
14
|
+
- **Character files** (character-file): a character as one versioned JSON document: every setting, each slot's look and material, the tailor's outlines, its own garments and its body (`bodies`: a URL, or the file itself) embedded, so a file is whole on another machine. `readCharacter` reads it against the page's defaults (unknown settings listed in `warnings`, missing ones defaulted, older versions migrated, newer refused).
|
|
15
|
+
- **`<tosi-b3d-biped character="…json">`** (or `characterDoc`): a biped made from a character file, with the clips its states name retargeted onto it (UAL1 by default), so `ualAnimationStates()` drives it. MakeHuman is imported only when a biped has a character.
|
|
16
|
+
- **`characterStore()`** (character-store): the characters this browser keeps (IndexedDB), shared by the builder and any page. A mesh or garment shared by several saves is stored once. The biped playground's settings panel has a **character** menu: the mannequin or any saved character, swapped in where the hero stands.
|
|
17
|
+
- **`mountTailorTool(b3d, { body, built, handleDone })`** (tailor-tool): the tailor as a tool, cutting a garment from any `RiggedBody`. Garments cut or imported on a mesh's body are bound to that body. `mountRigTool` takes `handleDone` / `handleCancel` and a host `panel`, and hands back `{ recipe, body }`.
|
|
18
|
+
- **The rig tool's markers are on the body**, dragged onto the joints they place; every joint can be moved by hand (kept in the recipe as `binding.joints`), and a tail has markers at its base and tip.
|
|
19
|
+
- **`materialPicker3d`** (material-picker): a material as one row, edited in a popup with rendered previews. `material-recipe` is the data (`{ type, inputs }`, schema, validator, collections such as the fabrics), `applyMaterial` puts it on a Babylon material. The character builder's garments use it.
|
|
20
|
+
- `barMenu` options take an `icon`; when every option has one the menu is a row of icon buttons. A new icon kind, `stroked filled`. Icons: `svgIcons.biped`, the rig and the tailor's scissors.
|
|
21
|
+
- `chooseFile(accept)`: the file picker as a promise, which keeps its input in the page until it answers.
|
|
22
|
+
- An [Acknowledgements](/acknowledgements/) page: every source used, with its licence.
|
|
23
|
+
|
|
24
|
+
## Changed
|
|
25
|
+
|
|
26
|
+
- The character builder has a body **source**: MakeHuman's, Blender's realistic Human Base Meshes, Quaternius' superheroes, or a GLB/glTF you open. A body from a file wears its own materials (each "as made" or "skin"), gets clothes and the Tailor, and its rig recipe is saved with the character. Characters save and restore (autosaved as you work, named saves beside it, JSON export and import).
|
|
27
|
+
- Feet and toes take the clip's turn by heading only, so feet stand flat on bodies whose ankle sits higher or lower than UAL's.
|
|
28
|
+
- The rig tool grounds a clip on the body's soles, so a body whose legs differ from the mannequin's no longer floats or sinks.
|
|
29
|
+
|
|
30
|
+
## Fixed
|
|
31
|
+
|
|
32
|
+
- Every file picker (the builder, the rig tool, the effect tool) delivers the file picked; a detached input could lose it, silently on Safari.
|
|
33
|
+
- The builder's Blender and Quaternius bodies load on a page that sets the asset base after import.
|
|
34
|
+
- Auto-rig on A-posed bodies: shoulders, elbows, wrists, hands and feet are found on the body.
|
|
35
|
+
- Turning a tail on brings its spring; its tip starts at the end of the mesh.
|
|
36
|
+
- Cloth eased onto a coarse body stays on its skin.
|
|
37
|
+
- A `b3d-launcher` moved to another holder shows its model, not the placeholder box.
|
package/dist/b3d-biped.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export declare class B3dBiped extends B3dControllable {
|
|
|
52
52
|
blendSeconds: number;
|
|
53
53
|
static initAttributes: {
|
|
54
54
|
url: string;
|
|
55
|
+
character: string;
|
|
56
|
+
animations: string;
|
|
55
57
|
skin: string;
|
|
56
58
|
scale: number;
|
|
57
59
|
player: boolean;
|
|
@@ -702,7 +704,13 @@ export declare class B3dBiped extends B3dControllable {
|
|
|
702
704
|
equip(boneName: string, url: string): void;
|
|
703
705
|
/** Remove whatever is equipped on a bone. */
|
|
704
706
|
unequip(boneName: string): void;
|
|
707
|
+
/** A character file, parsed: set it to make the character without a fetch. */
|
|
708
|
+
characterDoc: unknown;
|
|
709
|
+
/** The character made (a `SceneCharacter`, see character.ts), when it was made from one. */
|
|
710
|
+
figure: any;
|
|
705
711
|
sceneReady(owner: B3d, scene: BABYLON.Scene): void;
|
|
712
|
+
private _loadCharacter;
|
|
713
|
+
private _modelReady;
|
|
706
714
|
sceneDispose(): void;
|
|
707
715
|
render(): void;
|
|
708
716
|
}
|
package/dist/b3d-biped.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"b3d-biped.d.ts","sourceRoot":"","sources":["../src/b3d-biped.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"b3d-biped.d.ts","sourceRoot":"","sources":["../src/b3d-biped.ts"],"names":[],"mappings":"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"}
|
package/dist/b3d-biped.js
CHANGED
|
@@ -180,6 +180,8 @@ animation is doing with that hand.
|
|
|
180
180
|
| Attribute | Default | Description |
|
|
181
181
|
|-----------|---------|-------------|
|
|
182
182
|
| `url` | `''` | GLB model URL |
|
|
183
|
+
| `character` | `''` | A character file's URL (the [character builder](/character-builder/)'s **export JSON**), in place of `url`: the character is made from it ([character](/character/)) and UAL's clips are retargeted onto it, so use `ualAnimationStates()`. A mesh body comes from where the file says (its URL, or the mesh itself when it was opened from disk); a file that says neither falls back to MakeHuman's. Set `characterDoc` (the parsed file) instead to skip the fetch |
|
|
184
|
+
| `animations` | UAL1 | Where a `character`'s clips come from: a GLB whose clips have UAL's names and skeleton |
|
|
183
185
|
| `skin` | `''` | Optional albedo texture URL applied to the `skin` material (reskin) |
|
|
184
186
|
| `scale` | `1` | Uniform scale applied to the loaded model |
|
|
185
187
|
| `animation` | `''` | Current animation state name |
|
|
@@ -469,11 +471,29 @@ const LOCAL_FORWARD = new BABYLON.Vector3(0, 0, 1);
|
|
|
469
471
|
const _fwdScratch = new BABYLON.Vector3();
|
|
470
472
|
/** Scratch for the derived right axis, same reason. */
|
|
471
473
|
const _rightScratch = new BABYLON.Vector3();
|
|
474
|
+
/*
|
|
475
|
+
MakeHuman's pack and the hair library, once per scene however many
|
|
476
|
+
characters it has.
|
|
477
|
+
*/
|
|
478
|
+
const characterAssets = new WeakMap();
|
|
479
|
+
function sharedAssets(scene, load) {
|
|
480
|
+
let p = characterAssets.get(scene);
|
|
481
|
+
if (p == null) {
|
|
482
|
+
p = load();
|
|
483
|
+
characterAssets.set(scene, p);
|
|
484
|
+
}
|
|
485
|
+
return p;
|
|
486
|
+
}
|
|
472
487
|
export class B3dBiped extends B3dControllable {
|
|
473
488
|
static preferredTagName = 'tosi-b3d-biped';
|
|
474
489
|
static initAttributes = {
|
|
475
490
|
...B3dControllable.initAttributes,
|
|
476
491
|
url: '',
|
|
492
|
+
// A character file's URL (the character builder's export): the character
|
|
493
|
+
// is made from it, and UAL's clips (from `animations`) are retargeted onto it.
|
|
494
|
+
character: '',
|
|
495
|
+
// Where a character's clips come from: a GLB of UAL-named clips.
|
|
496
|
+
animations: '',
|
|
477
497
|
// Optional skin texture URL applied to the model's `skin` material. Kenney
|
|
478
498
|
// characters ship textureless with one `skin` material + separate skin PNGs,
|
|
479
499
|
// so reskinning is just swapping this albedo texture.
|
|
@@ -3280,9 +3300,18 @@ export class B3dBiped extends B3dControllable {
|
|
|
3280
3300
|
this._equipped.delete(boneName);
|
|
3281
3301
|
}
|
|
3282
3302
|
}
|
|
3303
|
+
/** A character file, parsed: set it to make the character without a fetch. */
|
|
3304
|
+
characterDoc = null;
|
|
3305
|
+
/** The character made (a `SceneCharacter`, see character.ts), when it was made from one. */
|
|
3306
|
+
figure = null;
|
|
3283
3307
|
sceneReady(owner, scene) {
|
|
3284
3308
|
super.sceneReady(owner, scene);
|
|
3285
3309
|
const attrs = this;
|
|
3310
|
+
if ((attrs.character !== '' || this.characterDoc != null) &&
|
|
3311
|
+
!this.entries) {
|
|
3312
|
+
this._loadCharacter(owner, scene).catch((e) => console.warn('<tosi-b3d-biped>: could not make the character', e));
|
|
3313
|
+
return;
|
|
3314
|
+
}
|
|
3286
3315
|
if (attrs.url !== '' && !this.entries) {
|
|
3287
3316
|
this.loadAssetContainer(scene, attrs.url, (container) => {
|
|
3288
3317
|
this._eased.clear();
|
|
@@ -3292,78 +3321,180 @@ export class B3dBiped extends B3dControllable {
|
|
|
3292
3321
|
if (this.entries.rootNodes.length !== 1) {
|
|
3293
3322
|
throw new Error('<tosi-b3d-biped> expects a container with exactly one root node');
|
|
3294
3323
|
}
|
|
3295
|
-
|
|
3296
|
-
.map((node) => node.getChildMeshes())
|
|
3297
|
-
.flat();
|
|
3298
|
-
this.mesh = this.entries.rootNodes[0];
|
|
3299
|
-
if (attrs.scale !== 1)
|
|
3300
|
-
this.mesh.scaling.setAll(attrs.scale);
|
|
3301
|
-
// Derive eye height from the model (after scaling, so it's the real size) so first-person sits at the head, not
|
|
3302
|
-
// the origin (the feet). ~0.93 of total height ≈ eye level. Used as a
|
|
3303
|
-
// fallback when there's no head node to anchor to.
|
|
3304
|
-
const bounds = this.mesh.getHierarchyBoundingVectors();
|
|
3305
|
-
const height = bounds.max.y - bounds.min.y;
|
|
3306
|
-
this.eyeHeight = height * 0.93;
|
|
3307
|
-
this.chaseHeight = height * 1.5;
|
|
3308
|
-
this.chaseDistance = height * 2.0;
|
|
3309
|
-
// Find the head BONE node (e.g. `mixamorig:Head`) so first-person anchors
|
|
3310
|
-
// to the actual animated head — which moves forward when walking and down
|
|
3311
|
-
// when crouching. Exclude meshes so we get the animated joint, not the
|
|
3312
|
-
// (static) `head` mesh node.
|
|
3313
|
-
this.headNode =
|
|
3314
|
-
this.mesh
|
|
3315
|
-
.getChildTransformNodes(false)
|
|
3316
|
-
.find((n) => /head/i.test(n.name) && !(n instanceof BABYLON.AbstractMesh)) ?? null;
|
|
3317
|
-
/*
|
|
3318
|
-
THE COLLISION BODY STARTS A STEP ABOVE THE FEET.
|
|
3319
|
-
|
|
3320
|
-
Its bottom used to sit exactly ON the feet, which was survivable only
|
|
3321
|
-
because the old ground check left the biped floating somewhere in a
|
|
3322
|
-
15 cm dead band — that float WAS the clearance. Snapping the feet onto
|
|
3323
|
-
the surface removed the float and, with it, the clearance: moving into
|
|
3324
|
-
rising ground embedded the ellipsoid in the slope, Babylon refused the
|
|
3325
|
-
move, and you stopped dead. Tonio: "you can get stuck on sloped
|
|
3326
|
-
surfaces."
|
|
3327
|
-
|
|
3328
|
-
Raising the offset by `STEP_OFFSET` is the standard fix (it is Unity's
|
|
3329
|
-
Step Offset): the capsule ignores anything lower than a step, so a slope
|
|
3330
|
-
rising under you is not an obstacle, and the ground probe puts the feet
|
|
3331
|
-
on the surface afterwards. A wall is still a wall — the capsule above
|
|
3332
|
-
the step height is unchanged.
|
|
3333
|
-
|
|
3334
|
-
Kept below `STEP_UP` (the probe's reach), so anything the body walks over
|
|
3335
|
-
is something the probe can then stand you on.
|
|
3336
|
-
*/
|
|
3337
|
-
this.mesh.ellipsoid = new BABYLON.Vector3(0.3, STAND_HALF, 0.3);
|
|
3338
|
-
this.mesh.ellipsoidOffset = new BABYLON.Vector3(0, STAND_HALF + STEP_OFFSET, 0);
|
|
3339
|
-
this.mesh.checkCollisions = true;
|
|
3340
|
-
owner.register({ meshes });
|
|
3341
|
-
// Skin materials that export as alphaMode MASK + base-color alpha 0 (an FBX
|
|
3342
|
-
// artifact) render the character fully invisible; they're opaque, so fix it
|
|
3343
|
-
// whether or not a `skin` is applied.
|
|
3344
|
-
for (const mm of meshes) {
|
|
3345
|
-
const mat = mm.material;
|
|
3346
|
-
if (mat instanceof BABYLON.PBRMaterial && /skin/i.test(mat.name)) {
|
|
3347
|
-
mat.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE;
|
|
3348
|
-
}
|
|
3349
|
-
}
|
|
3350
|
-
this.setAnimationState(attrs.initialState);
|
|
3351
|
-
if (attrs.skin)
|
|
3352
|
-
this.applySkin(attrs.skin);
|
|
3353
|
-
// If inputFocus wired input before GLB loaded, it may have been
|
|
3354
|
-
// cleared by a dispose/re-init cycle. Re-wire directly.
|
|
3355
|
-
if (attrs.player && this.inputProvider == null) {
|
|
3356
|
-
const focusManager = this.closest('tosi-b3d-input-focus');
|
|
3357
|
-
if (focusManager?.inputMappedProvider) {
|
|
3358
|
-
this.inputProvider = new CompositeInputProvider(focusManager.inputMappedProvider);
|
|
3359
|
-
}
|
|
3360
|
-
}
|
|
3361
|
-
this.lastUpdate = realNow();
|
|
3362
|
-
scene.registerBeforeRender(this._update);
|
|
3363
|
-
this.queueRender();
|
|
3324
|
+
this._modelReady(owner, scene);
|
|
3364
3325
|
});
|
|
3365
3326
|
}
|
|
3366
3327
|
}
|
|
3328
|
+
/*
|
|
3329
|
+
A CHARACTER IN PLACE OF A MODEL: made from its file (character.ts, loaded
|
|
3330
|
+
only here, so a biped without one does not carry MakeHuman), with the clips
|
|
3331
|
+
its states name retargeted onto its skeleton and named as they were. The
|
|
3332
|
+
result is shaped like a loaded model: one root node, its skeleton, its
|
|
3333
|
+
clips, so everything after is the same.
|
|
3334
|
+
*/
|
|
3335
|
+
async _loadCharacter(owner, scene) {
|
|
3336
|
+
const attrs = this;
|
|
3337
|
+
const [{ makeCharacter, loadCharacterAssets, DEFAULT_CHARACTER, CHARACTER_SOURCES, }, { readCharacter }, { readSkeleton, retargetClip }, { assetUrl },] = await Promise.all([
|
|
3338
|
+
import('./character.js'),
|
|
3339
|
+
import('./character-file.js'),
|
|
3340
|
+
import('./retarget-babylon.js'),
|
|
3341
|
+
import('./asset-url.js'),
|
|
3342
|
+
]);
|
|
3343
|
+
const doc = this.characterDoc ?? (await (await fetch(attrs.character)).text());
|
|
3344
|
+
const { character: c, warnings } = readCharacter(doc, {
|
|
3345
|
+
settings: DEFAULT_CHARACTER,
|
|
3346
|
+
});
|
|
3347
|
+
// The builder keeps its own settings in the file too (the clip, the
|
|
3348
|
+
// tailor's): those are expected, and skipped quietly.
|
|
3349
|
+
const changes = warnings.filter((w) => !/not a setting here/.test(w));
|
|
3350
|
+
if (changes.length)
|
|
3351
|
+
console.warn('<tosi-b3d-biped>: the character file, read with changes', changes);
|
|
3352
|
+
const settings = c.settings;
|
|
3353
|
+
// A mesh body comes from the page's sources, or from where the file says
|
|
3354
|
+
// (a URL, or the mesh itself inside the file).
|
|
3355
|
+
const sources = { ...CHARACTER_SOURCES };
|
|
3356
|
+
for (const [name, b] of Object.entries(c.bodies ?? {})) {
|
|
3357
|
+
if (name in sources)
|
|
3358
|
+
continue;
|
|
3359
|
+
const pick = b.pick != null ? { pick: b.pick } : {};
|
|
3360
|
+
if (b.file)
|
|
3361
|
+
sources[name] = {
|
|
3362
|
+
file: new File([b.file.bytes], b.file.name),
|
|
3363
|
+
...pick,
|
|
3364
|
+
};
|
|
3365
|
+
else if (b.url)
|
|
3366
|
+
sources[name] = { url: b.url, ...pick };
|
|
3367
|
+
}
|
|
3368
|
+
if (settings.source !== 'MakeHuman' && !(settings.source in sources)) {
|
|
3369
|
+
console.warn(`<tosi-b3d-biped>: the character file does not say where body ${settings.source} comes from; MakeHuman's shown`);
|
|
3370
|
+
settings.source = 'MakeHuman';
|
|
3371
|
+
}
|
|
3372
|
+
const assets = await sharedAssets(scene, () => loadCharacterAssets(scene));
|
|
3373
|
+
const ch = await makeCharacter(scene, assets, {
|
|
3374
|
+
settings,
|
|
3375
|
+
sources,
|
|
3376
|
+
cloth: c.cloth,
|
|
3377
|
+
garments: Object.values(c.garments),
|
|
3378
|
+
handleMeshes: (meshes) => owner.register({ meshes }),
|
|
3379
|
+
});
|
|
3380
|
+
await ch.ready();
|
|
3381
|
+
if (this.owner == null) {
|
|
3382
|
+
ch.dispose();
|
|
3383
|
+
return;
|
|
3384
|
+
}
|
|
3385
|
+
// The clips the states name, from the library, retargeted and named as they were.
|
|
3386
|
+
const library = await BABYLON.LoadAssetContainerAsync(attrs.animations || assetUrl('quaternius/UAL1_core.glb', 2), scene);
|
|
3387
|
+
library.addAllToScene();
|
|
3388
|
+
for (const g of library.animationGroups)
|
|
3389
|
+
g.stop();
|
|
3390
|
+
const libRoot = library.meshes.find((m) => m.name === '__root__') ??
|
|
3391
|
+
library.transformNodes[0];
|
|
3392
|
+
const from = readSkeleton(library.skeletons[0], libRoot);
|
|
3393
|
+
const wanted = new Set(this.animationStates.map((st) => st.animation ?? st.name));
|
|
3394
|
+
const clips = [];
|
|
3395
|
+
for (const g of library.animationGroups) {
|
|
3396
|
+
if (!wanted.has(g.name))
|
|
3397
|
+
continue;
|
|
3398
|
+
clips.push(retargetClip(g, from, ch.skeleton, {
|
|
3399
|
+
scene,
|
|
3400
|
+
name: g.name,
|
|
3401
|
+
armSpaceDeg: ch.recipe?.armSpaceDeg,
|
|
3402
|
+
}));
|
|
3403
|
+
}
|
|
3404
|
+
library.dispose();
|
|
3405
|
+
// The root the biped moves: the character stands on it, soles on y = 0.
|
|
3406
|
+
const root = new BABYLON.Mesh('biped-character', scene);
|
|
3407
|
+
ch.root.parent = root;
|
|
3408
|
+
ch.groundFor(clips.find((g) => g.name === 'Idle_Loop') ?? null);
|
|
3409
|
+
this.figure = ch;
|
|
3410
|
+
this._eased.clear();
|
|
3411
|
+
this.entries = {
|
|
3412
|
+
rootNodes: [root],
|
|
3413
|
+
skeletons: ch.shown ? [ch.shown.built.skeleton] : [],
|
|
3414
|
+
animationGroups: clips,
|
|
3415
|
+
dispose: () => {
|
|
3416
|
+
for (const g of clips)
|
|
3417
|
+
g.dispose();
|
|
3418
|
+
ch.dispose();
|
|
3419
|
+
root.dispose();
|
|
3420
|
+
},
|
|
3421
|
+
};
|
|
3422
|
+
this._modelReady(owner, scene);
|
|
3423
|
+
}
|
|
3424
|
+
_modelReady(owner, scene) {
|
|
3425
|
+
const attrs = this;
|
|
3426
|
+
if (this.entries == null)
|
|
3427
|
+
return;
|
|
3428
|
+
const meshes = this.entries.rootNodes
|
|
3429
|
+
.map((node) => node.getChildMeshes())
|
|
3430
|
+
.flat();
|
|
3431
|
+
this.mesh = this.entries.rootNodes[0];
|
|
3432
|
+
if (attrs.scale !== 1)
|
|
3433
|
+
this.mesh.scaling.setAll(attrs.scale);
|
|
3434
|
+
// Derive eye height from the model (after scaling, so it's the real size) so first-person sits at the head, not
|
|
3435
|
+
// the origin (the feet). ~0.93 of total height ≈ eye level. Used as a
|
|
3436
|
+
// fallback when there's no head node to anchor to.
|
|
3437
|
+
const bounds = this.mesh.getHierarchyBoundingVectors();
|
|
3438
|
+
const height = bounds.max.y - bounds.min.y;
|
|
3439
|
+
this.eyeHeight = height * 0.93;
|
|
3440
|
+
this.chaseHeight = height * 1.5;
|
|
3441
|
+
this.chaseDistance = height * 2.0;
|
|
3442
|
+
// Find the head BONE node (e.g. `mixamorig:Head`) so first-person anchors
|
|
3443
|
+
// to the actual animated head — which moves forward when walking and down
|
|
3444
|
+
// when crouching. Exclude meshes so we get the animated joint, not the
|
|
3445
|
+
// (static) `head` mesh node.
|
|
3446
|
+
this.headNode =
|
|
3447
|
+
this.mesh
|
|
3448
|
+
.getChildTransformNodes(false)
|
|
3449
|
+
.find((n) => /head/i.test(n.name) && !(n instanceof BABYLON.AbstractMesh)) ?? null;
|
|
3450
|
+
/*
|
|
3451
|
+
THE COLLISION BODY STARTS A STEP ABOVE THE FEET.
|
|
3452
|
+
|
|
3453
|
+
Its bottom used to sit exactly ON the feet, which was survivable only
|
|
3454
|
+
because the old ground check left the biped floating somewhere in a
|
|
3455
|
+
15 cm dead band — that float WAS the clearance. Snapping the feet onto
|
|
3456
|
+
the surface removed the float and, with it, the clearance: moving into
|
|
3457
|
+
rising ground embedded the ellipsoid in the slope, Babylon refused the
|
|
3458
|
+
move, and you stopped dead. Tonio: "you can get stuck on sloped
|
|
3459
|
+
surfaces."
|
|
3460
|
+
|
|
3461
|
+
Raising the offset by `STEP_OFFSET` is the standard fix (it is Unity's
|
|
3462
|
+
Step Offset): the capsule ignores anything lower than a step, so a slope
|
|
3463
|
+
rising under you is not an obstacle, and the ground probe puts the feet
|
|
3464
|
+
on the surface afterwards. A wall is still a wall — the capsule above
|
|
3465
|
+
the step height is unchanged.
|
|
3466
|
+
|
|
3467
|
+
Kept below `STEP_UP` (the probe's reach), so anything the body walks over
|
|
3468
|
+
is something the probe can then stand you on.
|
|
3469
|
+
*/
|
|
3470
|
+
this.mesh.ellipsoid = new BABYLON.Vector3(0.3, STAND_HALF, 0.3);
|
|
3471
|
+
this.mesh.ellipsoidOffset = new BABYLON.Vector3(0, STAND_HALF + STEP_OFFSET, 0);
|
|
3472
|
+
this.mesh.checkCollisions = true;
|
|
3473
|
+
owner.register({ meshes });
|
|
3474
|
+
// Skin materials that export as alphaMode MASK + base-color alpha 0 (an FBX
|
|
3475
|
+
// artifact) render the character fully invisible; they're opaque, so fix it
|
|
3476
|
+
// whether or not a `skin` is applied.
|
|
3477
|
+
for (const mm of meshes) {
|
|
3478
|
+
const mat = mm.material;
|
|
3479
|
+
if (mat instanceof BABYLON.PBRMaterial && /skin/i.test(mat.name)) {
|
|
3480
|
+
mat.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE;
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
this.setAnimationState(attrs.initialState);
|
|
3484
|
+
if (attrs.skin)
|
|
3485
|
+
this.applySkin(attrs.skin);
|
|
3486
|
+
// If inputFocus wired input before GLB loaded, it may have been
|
|
3487
|
+
// cleared by a dispose/re-init cycle. Re-wire directly.
|
|
3488
|
+
if (attrs.player && this.inputProvider == null) {
|
|
3489
|
+
const focusManager = this.closest('tosi-b3d-input-focus');
|
|
3490
|
+
if (focusManager?.inputMappedProvider) {
|
|
3491
|
+
this.inputProvider = new CompositeInputProvider(focusManager.inputMappedProvider);
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
this.lastUpdate = realNow();
|
|
3495
|
+
scene.registerBeforeRender(this._update);
|
|
3496
|
+
this.queueRender();
|
|
3497
|
+
}
|
|
3367
3498
|
sceneDispose() {
|
|
3368
3499
|
this._reticle?.dispose();
|
|
3369
3500
|
this._reticle = null;
|
|
@@ -3378,6 +3509,13 @@ export class B3dBiped extends B3dControllable {
|
|
|
3378
3509
|
this.fpvCamera = null;
|
|
3379
3510
|
}
|
|
3380
3511
|
this.hiddenBody = [];
|
|
3512
|
+
if (this.owner != null && this.entries && this.figure) {
|
|
3513
|
+
this.owner.scene.unregisterBeforeRender(this._update);
|
|
3514
|
+
this.entries.dispose();
|
|
3515
|
+
this.figure = null;
|
|
3516
|
+
this.entries = undefined;
|
|
3517
|
+
this._eased.clear();
|
|
3518
|
+
}
|
|
3381
3519
|
if (this.owner != null && this.entries) {
|
|
3382
3520
|
this.owner.scene.unregisterBeforeRender(this._update);
|
|
3383
3521
|
for (const node of this.entries.rootNodes) {
|