@mml-io/3d-web-client-core 0.0.0-experimental-1f6e4fb-20250728 → 0.0.0-experimental-7b195ca-20250729

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.
@@ -1,4 +1,4 @@
1
- import { Color, SkinnedMesh, Object3D } from "three";
1
+ import { Color, Object3D } from "three";
2
2
  import { ColorPartName } from "../CharacterModel";
3
3
  import { InstancedMesh2 } from "./vendor/";
4
4
  export type ColorSamplingOptions = {
@@ -9,6 +9,6 @@ export type ColorSamplingOptions = {
9
9
  };
10
10
  debug?: boolean;
11
11
  };
12
- export declare function captureCharacterColors(characterMesh: SkinnedMesh, options: ColorSamplingOptions): Map<ColorPartName, Color>;
12
+ export declare function captureCharacterColors(characterMesh: Object3D, options: ColorSamplingOptions): Map<ColorPartName, Color>;
13
13
  export declare function captureCharacterColorsFromObject3D(object3D: Object3D, options: ColorSamplingOptions): Map<ColorPartName, Color>;
14
14
  export declare function updateDebugTextureCanvas(instancedMesh: InstancedMesh2): void;
package/build/index.js CHANGED
@@ -1407,7 +1407,7 @@ import {
1407
1407
  Group,
1408
1408
  LoopRepeat,
1409
1409
  Mesh,
1410
- SkinnedMesh as SkinnedMesh3,
1410
+ SkinnedMesh as SkinnedMesh2,
1411
1411
  Vector3 as Vector33
1412
1412
  } from "three";
1413
1413
 
@@ -1721,155 +1721,13 @@ import {
1721
1721
  Color as Color2,
1722
1722
  OrthographicCamera,
1723
1723
  Scene,
1724
- SkinnedMesh as SkinnedMesh2,
1724
+ SkinnedMesh,
1725
1725
  Vector2,
1726
1726
  Vector3 as Vector32,
1727
1727
  WebGLRenderer,
1728
1728
  WebGLRenderTarget
1729
1729
  } from "three";
1730
1730
  import * as SkeletonUtils from "three/examples/jsm/utils/SkeletonUtils.js";
1731
-
1732
- // src/character/instancing/CharacterInstancingUtils.ts
1733
- import { BufferAttribute, SkinnedMesh } from "three";
1734
- import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
1735
- function mergeSkinnedMeshes(skinnedMeshes, debug) {
1736
- const geometries = [];
1737
- const materials = [];
1738
- const skeleton = skinnedMeshes[0].skeleton;
1739
- for (const skinnedMesh of skinnedMeshes) {
1740
- const geometry = skinnedMesh.geometry.clone();
1741
- const materialIndex = materials.length;
1742
- if (Array.isArray(skinnedMesh.material)) {
1743
- materials.push(...skinnedMesh.material);
1744
- for (let i = 0; i < skinnedMesh.material.length; i++) {
1745
- geometry.addGroup(
1746
- 0,
1747
- geometry.index ? geometry.index.count : geometry.attributes.position.count,
1748
- materialIndex + i
1749
- );
1750
- }
1751
- } else {
1752
- materials.push(skinnedMesh.material);
1753
- geometry.addGroup(
1754
- 0,
1755
- geometry.index ? geometry.index.count : geometry.attributes.position.count,
1756
- materialIndex
1757
- );
1758
- }
1759
- geometries.push(geometry);
1760
- }
1761
- const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries, true);
1762
- if (!mergedGeometry) {
1763
- throw new Error("Failed to merge geometries");
1764
- }
1765
- const mergedMesh = new SkinnedMesh(mergedGeometry, materials);
1766
- mergedMesh.skeleton = skeleton;
1767
- mergedMesh.bindMatrix.copy(skinnedMeshes[0].bindMatrix);
1768
- mergedMesh.bindMatrixInverse.copy(skinnedMeshes[0].bindMatrixInverse);
1769
- mergedMesh.bind(skeleton, mergedMesh.bindMatrix);
1770
- if (debug) {
1771
- console.log(`Merged into single mesh with ${materials.length} materials`);
1772
- }
1773
- addVertexColorsToGeometry(mergedGeometry, materials, debug);
1774
- return mergedMesh;
1775
- }
1776
- function validateAndCleanSkeleton(skinnedMesh) {
1777
- const skeleton = skinnedMesh.skeleton;
1778
- const nullBoneIndices = [];
1779
- for (let i = 0; i < skeleton.bones.length; i++) {
1780
- if (!skeleton.bones[i]) {
1781
- nullBoneIndices.push(i);
1782
- }
1783
- }
1784
- if (nullBoneIndices.length > 0) {
1785
- skeleton.bones = skeleton.bones.filter((bone) => bone !== null && bone !== void 0);
1786
- skeleton.update();
1787
- }
1788
- }
1789
- function addVertexColorsToGeometry(geometry, materials, debug) {
1790
- const positionAttribute = geometry.getAttribute("position");
1791
- if (!positionAttribute) {
1792
- console.error("No position attribute found in geometry");
1793
- return;
1794
- }
1795
- const vertexCount = positionAttribute.count;
1796
- if (debug) {
1797
- console.log(`Geometry has ${vertexCount} vertices`);
1798
- }
1799
- const colors = new Float32Array(vertexCount * 3);
1800
- for (let i = 0; i < vertexCount; i++) {
1801
- colors[i * 3] = 1;
1802
- colors[i * 3 + 1] = 1;
1803
- colors[i * 3 + 2] = 1;
1804
- }
1805
- const materialColorCodes = {
1806
- // bin material IDs to be replaced by the final colors on the GPU
1807
- hair: [0, 0, 0],
1808
- shirt_short: [0, 0, 1],
1809
- shirt_long: [0, 1, 0],
1810
- pants_short: [0, 1, 1],
1811
- pants_long: [1, 0, 0],
1812
- shoes: [1, 0, 1],
1813
- skin: [1, 1, 0],
1814
- lips: [1, 1, 1],
1815
- eyes_black: [0.5, 0, 0],
1816
- eyes_white: [0, 0.5, 0]
1817
- };
1818
- if (debug) {
1819
- console.log("Geometry groups:", geometry.groups);
1820
- console.log(
1821
- "Materials:",
1822
- materials.map((m) => m.name)
1823
- );
1824
- }
1825
- if (geometry.groups && geometry.groups.length > 0) {
1826
- geometry.groups.forEach((group, groupIndex) => {
1827
- const material = materials[group.materialIndex || groupIndex];
1828
- const materialName = (material == null ? void 0 : material.name) || `material_${groupIndex}`;
1829
- if (debug) {
1830
- console.log(
1831
- `Processing group ${groupIndex}: material "${materialName}", start: ${group.start}, count: ${group.count}`
1832
- );
1833
- }
1834
- const materialColor = materialColorCodes[materialName] || [
1835
- 1,
1836
- 1,
1837
- 1
1838
- ];
1839
- if (debug) {
1840
- console.log(
1841
- `Using ID color [${materialColor.join(", ")}] for material "${materialName}" (${materialColor[0] === 1 && materialColor[1] === 1 && materialColor[2] === 0 ? "YELLOW=SKIN" : materialColor[0] === 0 && materialColor[1] === 0 && materialColor[2] === 1 ? "BLUE=SHIRT" : "OTHER"})`
1842
- );
1843
- }
1844
- const indexAttribute = geometry.getIndex();
1845
- if (indexAttribute) {
1846
- for (let i = group.start; i < group.start + group.count; i++) {
1847
- const vertexIndex = indexAttribute.getX(i);
1848
- colors[vertexIndex * 3] = materialColor[0];
1849
- colors[vertexIndex * 3 + 1] = materialColor[1];
1850
- colors[vertexIndex * 3 + 2] = materialColor[2];
1851
- }
1852
- } else {
1853
- const startVertex = group.start / 3;
1854
- const vertexCount2 = group.count / 3;
1855
- for (let i = 0; i < vertexCount2; i++) {
1856
- const vertexIndex = startVertex + i;
1857
- colors[vertexIndex * 3] = materialColor[0];
1858
- colors[vertexIndex * 3 + 1] = materialColor[1];
1859
- colors[vertexIndex * 3 + 2] = materialColor[2];
1860
- }
1861
- }
1862
- });
1863
- } else {
1864
- console.warn("No geometry groups found, using single material coloring");
1865
- }
1866
- geometry.setAttribute("color", new BufferAttribute(colors, 3));
1867
- if (debug) {
1868
- console.log(`Added per-material vertex colors to ${vertexCount} vertices`);
1869
- }
1870
- }
1871
-
1872
- // src/character/instancing/CharacterColourSamplingUtils.ts
1873
1731
  function listAllBoneNames(obj) {
1874
1732
  const boneNames = [];
1875
1733
  if (!obj) {
@@ -2020,26 +1878,14 @@ function captureCharacterColorsFromObject3D(object3D, options) {
2020
1878
  clone3.scale.set(1, 1, 1);
2021
1879
  const skinnedMeshes = [];
2022
1880
  clone3.traverse((child) => {
2023
- if (child instanceof SkinnedMesh2 || child.isSkinnedMesh) {
2024
- skinnedMeshes.push(child);
1881
+ if (child instanceof SkinnedMesh || child.isSkinnedMesh) {
1882
+ const skinnedMesh = child;
1883
+ skinnedMesh.skeleton.pose();
1884
+ skinnedMesh.skeleton.update();
1885
+ skinnedMesh.updateMatrixWorld(true);
2025
1886
  }
2026
1887
  });
2027
- if (skinnedMeshes.length === 0) {
2028
- console.warn("No SkinnedMesh objects found in Object3D hierarchy");
2029
- return /* @__PURE__ */ new Map();
2030
- }
2031
- let skinnedMesh;
2032
- if (skinnedMeshes.length === 1) {
2033
- skinnedMesh = skinnedMeshes[0];
2034
- } else {
2035
- skinnedMesh = mergeSkinnedMeshes(skinnedMeshes);
2036
- }
2037
- const skeleton = skinnedMesh.skeleton;
2038
- skeleton.pose();
2039
- skeleton.update();
2040
- skinnedMesh.updateMatrixWorld(true);
2041
- validateAndCleanSkeleton(skinnedMesh);
2042
- return captureCharacterColors(skinnedMesh, options);
1888
+ return captureCharacterColors(object3D, options);
2043
1889
  }
2044
1890
  function findBoneCenter(bone) {
2045
1891
  const boneStart = new Vector32();
@@ -2054,9 +1900,20 @@ function findBoneCenter(bone) {
2054
1900
  }
2055
1901
  function getBoneRegionsForColorSampling(characterMesh, camera, renderSize, circularSamplingRadius, topDownSamplingSize, debug) {
2056
1902
  const regions = [];
1903
+ let firstSkinnedMesh = null;
1904
+ characterMesh.traverse((child) => {
1905
+ if (!firstSkinnedMesh && (child instanceof SkinnedMesh || child.isSkinnedMesh)) {
1906
+ firstSkinnedMesh = child;
1907
+ }
1908
+ });
1909
+ if (!firstSkinnedMesh) {
1910
+ console.warn("No SkinnedMesh objects found in Object3D hierarchy");
1911
+ return regions;
1912
+ }
1913
+ const skinnedMesh = firstSkinnedMesh;
2057
1914
  if (debug) {
2058
1915
  console.log("Available bones:");
2059
- console.table(listAllBoneNames(characterMesh));
1916
+ console.table(listAllBoneNames(skinnedMesh));
2060
1917
  }
2061
1918
  const boneTargets = [
2062
1919
  { name: "Face/Chin", boneName: "neck_02" },
@@ -2075,7 +1932,7 @@ function getBoneRegionsForColorSampling(characterMesh, camera, renderSize, circu
2075
1932
  ];
2076
1933
  const screenPos = new Vector32();
2077
1934
  for (const target of boneTargets) {
2078
- const bone = characterMesh.skeleton.bones.find(
1935
+ const bone = skinnedMesh.skeleton.bones.find(
2079
1936
  (child) => child.name === target.boneName
2080
1937
  );
2081
1938
  if (bone) {
@@ -2669,7 +2526,7 @@ var CharacterModel = class {
2669
2526
  this.animationMixer = null;
2670
2527
  }
2671
2528
  (_a = this.mesh) == null ? void 0 : _a.traverse((child) => {
2672
- if (child instanceof SkinnedMesh3 || child.isSkinnedMesh) {
2529
+ if (child instanceof SkinnedMesh2 || child.isSkinnedMesh) {
2673
2530
  const asSkinnedMesh = child;
2674
2531
  if (asSkinnedMesh.geometry) {
2675
2532
  asSkinnedMesh.geometry.dispose();
@@ -3391,6 +3248,146 @@ function getTrackTypeFromName(trackName) {
3391
3248
  return NumberKeyframeTrack;
3392
3249
  }
3393
3250
 
3251
+ // src/character/instancing/CharacterInstancingUtils.ts
3252
+ import { BufferAttribute, SkinnedMesh as SkinnedMesh3 } from "three";
3253
+ import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
3254
+ function mergeSkinnedMeshes(skinnedMeshes, debug) {
3255
+ const geometries = [];
3256
+ const materials = [];
3257
+ const skeleton = skinnedMeshes[0].skeleton;
3258
+ for (const skinnedMesh of skinnedMeshes) {
3259
+ const geometry = skinnedMesh.geometry.clone();
3260
+ const materialIndex = materials.length;
3261
+ if (Array.isArray(skinnedMesh.material)) {
3262
+ materials.push(...skinnedMesh.material);
3263
+ for (let i = 0; i < skinnedMesh.material.length; i++) {
3264
+ geometry.addGroup(
3265
+ 0,
3266
+ geometry.index ? geometry.index.count : geometry.attributes.position.count,
3267
+ materialIndex + i
3268
+ );
3269
+ }
3270
+ } else {
3271
+ materials.push(skinnedMesh.material);
3272
+ geometry.addGroup(
3273
+ 0,
3274
+ geometry.index ? geometry.index.count : geometry.attributes.position.count,
3275
+ materialIndex
3276
+ );
3277
+ }
3278
+ geometries.push(geometry);
3279
+ }
3280
+ const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries, true);
3281
+ if (!mergedGeometry) {
3282
+ throw new Error("Failed to merge geometries");
3283
+ }
3284
+ const mergedMesh = new SkinnedMesh3(mergedGeometry, materials);
3285
+ mergedMesh.skeleton = skeleton;
3286
+ mergedMesh.bindMatrix.copy(skinnedMeshes[0].bindMatrix);
3287
+ mergedMesh.bindMatrixInverse.copy(skinnedMeshes[0].bindMatrixInverse);
3288
+ mergedMesh.bind(skeleton, mergedMesh.bindMatrix);
3289
+ if (debug) {
3290
+ console.log(`Merged into single mesh with ${materials.length} materials`);
3291
+ }
3292
+ addVertexColorsToGeometry(mergedGeometry, materials, debug);
3293
+ return mergedMesh;
3294
+ }
3295
+ function validateAndCleanSkeleton(skinnedMesh) {
3296
+ const skeleton = skinnedMesh.skeleton;
3297
+ const nullBoneIndices = [];
3298
+ for (let i = 0; i < skeleton.bones.length; i++) {
3299
+ if (!skeleton.bones[i]) {
3300
+ nullBoneIndices.push(i);
3301
+ }
3302
+ }
3303
+ if (nullBoneIndices.length > 0) {
3304
+ skeleton.bones = skeleton.bones.filter((bone) => bone !== null && bone !== void 0);
3305
+ skeleton.update();
3306
+ }
3307
+ }
3308
+ function addVertexColorsToGeometry(geometry, materials, debug) {
3309
+ const positionAttribute = geometry.getAttribute("position");
3310
+ if (!positionAttribute) {
3311
+ console.error("No position attribute found in geometry");
3312
+ return;
3313
+ }
3314
+ const vertexCount = positionAttribute.count;
3315
+ if (debug) {
3316
+ console.log(`Geometry has ${vertexCount} vertices`);
3317
+ }
3318
+ const colors = new Float32Array(vertexCount * 3);
3319
+ for (let i = 0; i < vertexCount; i++) {
3320
+ colors[i * 3] = 1;
3321
+ colors[i * 3 + 1] = 1;
3322
+ colors[i * 3 + 2] = 1;
3323
+ }
3324
+ const materialColorCodes = {
3325
+ // bin material IDs to be replaced by the final colors on the GPU
3326
+ hair: [0, 0, 0],
3327
+ shirt_short: [0, 0, 1],
3328
+ shirt_long: [0, 1, 0],
3329
+ pants_short: [0, 1, 1],
3330
+ pants_long: [1, 0, 0],
3331
+ shoes: [1, 0, 1],
3332
+ skin: [1, 1, 0],
3333
+ lips: [1, 1, 1],
3334
+ eyes_black: [0.5, 0, 0],
3335
+ eyes_white: [0, 0.5, 0]
3336
+ };
3337
+ if (debug) {
3338
+ console.log("Geometry groups:", geometry.groups);
3339
+ console.log(
3340
+ "Materials:",
3341
+ materials.map((m) => m.name)
3342
+ );
3343
+ }
3344
+ if (geometry.groups && geometry.groups.length > 0) {
3345
+ geometry.groups.forEach((group, groupIndex) => {
3346
+ const material = materials[group.materialIndex || groupIndex];
3347
+ const materialName = (material == null ? void 0 : material.name) || `material_${groupIndex}`;
3348
+ if (debug) {
3349
+ console.log(
3350
+ `Processing group ${groupIndex}: material "${materialName}", start: ${group.start}, count: ${group.count}`
3351
+ );
3352
+ }
3353
+ const materialColor = materialColorCodes[materialName] || [
3354
+ 1,
3355
+ 1,
3356
+ 1
3357
+ ];
3358
+ if (debug) {
3359
+ console.log(
3360
+ `Using ID color [${materialColor.join(", ")}] for material "${materialName}" (${materialColor[0] === 1 && materialColor[1] === 1 && materialColor[2] === 0 ? "YELLOW=SKIN" : materialColor[0] === 0 && materialColor[1] === 0 && materialColor[2] === 1 ? "BLUE=SHIRT" : "OTHER"})`
3361
+ );
3362
+ }
3363
+ const indexAttribute = geometry.getIndex();
3364
+ if (indexAttribute) {
3365
+ for (let i = group.start; i < group.start + group.count; i++) {
3366
+ const vertexIndex = indexAttribute.getX(i);
3367
+ colors[vertexIndex * 3] = materialColor[0];
3368
+ colors[vertexIndex * 3 + 1] = materialColor[1];
3369
+ colors[vertexIndex * 3 + 2] = materialColor[2];
3370
+ }
3371
+ } else {
3372
+ const startVertex = group.start / 3;
3373
+ const vertexCount2 = group.count / 3;
3374
+ for (let i = 0; i < vertexCount2; i++) {
3375
+ const vertexIndex = startVertex + i;
3376
+ colors[vertexIndex * 3] = materialColor[0];
3377
+ colors[vertexIndex * 3 + 1] = materialColor[1];
3378
+ colors[vertexIndex * 3 + 2] = materialColor[2];
3379
+ }
3380
+ }
3381
+ });
3382
+ } else {
3383
+ console.warn("No geometry groups found, using single material coloring");
3384
+ }
3385
+ geometry.setAttribute("color", new BufferAttribute(colors, 3));
3386
+ if (debug) {
3387
+ console.log(`Added per-material vertex colors to ${vertexCount} vertices`);
3388
+ }
3389
+ }
3390
+
3394
3391
  // src/character/instancing/vendor/core/InstancedEntity.ts
3395
3392
  import {
3396
3393
  Euler,