mbt-3d 0.3.1 → 0.3.3
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/dist/index.d.ts +158 -18
- package/dist/mbt-3d.cjs +1 -1
- package/dist/mbt-3d.cjs.map +1 -1
- package/dist/mbt-3d.js +613 -514
- package/dist/mbt-3d.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,22 @@ import { JSX as JSX_2 } from 'react/jsx-runtime';
|
|
|
3
3
|
import { RefAttributes } from 'react';
|
|
4
4
|
import * as THREE from 'three';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Ambient light configuration - uniform background lighting (no shadows)
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* { type: 'ambient', intensity: 0.3, color: '#ffffff' }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
declare interface AmbientLightConfig {
|
|
15
|
+
type: 'ambient';
|
|
16
|
+
/** Light intensity. Default: 0.5 */
|
|
17
|
+
intensity?: number;
|
|
18
|
+
/** Light color. Default: '#ffffff' */
|
|
19
|
+
color?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
6
22
|
/**
|
|
7
23
|
* AnimatedModel - 3D model with animation support and bone attachment capability
|
|
8
24
|
*
|
|
@@ -181,6 +197,18 @@ export declare interface AnimatedModelProps extends Omit<ModelProps, 'onLoad'> {
|
|
|
181
197
|
onLoad?: (info: AnimatedModelInfo) => void;
|
|
182
198
|
}
|
|
183
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Base light configuration with common properties
|
|
202
|
+
*/
|
|
203
|
+
declare interface BaseLightConfig {
|
|
204
|
+
/** Light type */
|
|
205
|
+
type: LightType;
|
|
206
|
+
/** Light color as hex string. Default: '#ffffff' */
|
|
207
|
+
color?: string;
|
|
208
|
+
/** Light intensity. Default varies by light type */
|
|
209
|
+
intensity?: number;
|
|
210
|
+
}
|
|
211
|
+
|
|
184
212
|
/**
|
|
185
213
|
* BoneAttachment - Attach models to bones of an AnimatedModel parent
|
|
186
214
|
*
|
|
@@ -235,6 +263,52 @@ export declare interface BoneAttachmentProps {
|
|
|
235
263
|
scale?: number | [number, number, number];
|
|
236
264
|
}
|
|
237
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Directional light configuration - parallel rays (like sunlight)
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```tsx
|
|
271
|
+
* { type: 'directional', position: [10, 20, 10], intensity: 40, castShadow: true }
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
declare interface DirectionalLightConfig extends BaseLightConfig {
|
|
275
|
+
type: 'directional';
|
|
276
|
+
/** Light position [x, y, z]. Default: [10, 20, 10] */
|
|
277
|
+
position?: [number, number, number];
|
|
278
|
+
/** Enable shadow casting. Default: true */
|
|
279
|
+
castShadow?: boolean;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Hemisphere light configuration - soft sky/ground lighting (no shadows)
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```tsx
|
|
287
|
+
* { type: 'hemisphere', skyColor: '#87CEEB', groundColor: '#362312', intensity: 0.5 }
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
declare interface HemisphereLightConfig {
|
|
291
|
+
type: 'hemisphere';
|
|
292
|
+
/** Sky color. Default: '#ffffff' */
|
|
293
|
+
skyColor?: string;
|
|
294
|
+
/** Ground color. Default: '#444444' */
|
|
295
|
+
groundColor?: string;
|
|
296
|
+
/** Light intensity. Default: 0.5 */
|
|
297
|
+
intensity?: number;
|
|
298
|
+
/** Light position [x, y, z]. Default: [0, 10, 0] */
|
|
299
|
+
position?: [number, number, number];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Union type for all light configurations
|
|
304
|
+
*/
|
|
305
|
+
declare type LightConfigUnion = SpotLightConfig | PointLightConfig | DirectionalLightConfig | HemisphereLightConfig | AmbientLightConfig;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Light types supported by Scene3D component
|
|
309
|
+
*/
|
|
310
|
+
declare type LightType = 'spot' | 'point' | 'directional' | 'hemisphere' | 'ambient';
|
|
311
|
+
|
|
238
312
|
export declare type MaterialTextures = MaterialTextures_2;
|
|
239
313
|
|
|
240
314
|
/**
|
|
@@ -472,6 +546,26 @@ export declare interface MorphableModelProps extends ModelProps {
|
|
|
472
546
|
onMorphTargetsFound?: (names: string[]) => void;
|
|
473
547
|
}
|
|
474
548
|
|
|
549
|
+
/**
|
|
550
|
+
* Point light configuration - omnidirectional light (like a light bulb)
|
|
551
|
+
*
|
|
552
|
+
* @example
|
|
553
|
+
* ```tsx
|
|
554
|
+
* { type: 'point', position: [0, 5, 0], intensity: 20, color: '#ffaa00' }
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
declare interface PointLightConfig extends BaseLightConfig {
|
|
558
|
+
type: 'point';
|
|
559
|
+
/** Light position [x, y, z]. Default: [0, 5, 0] */
|
|
560
|
+
position?: [number, number, number];
|
|
561
|
+
/** Light distance. Default: 0 (infinite) */
|
|
562
|
+
distance?: number;
|
|
563
|
+
/** Light decay. Default: 2 */
|
|
564
|
+
decay?: number;
|
|
565
|
+
/** Enable shadow casting. Default: false */
|
|
566
|
+
castShadow?: boolean;
|
|
567
|
+
}
|
|
568
|
+
|
|
475
569
|
export declare function preloadModel(url: string): void;
|
|
476
570
|
|
|
477
571
|
/**
|
|
@@ -480,7 +574,7 @@ export declare function preloadModel(url: string): void;
|
|
|
480
574
|
* @remarks
|
|
481
575
|
* This component wraps React Three Fiber's Canvas and provides:
|
|
482
576
|
* - OrbitControls for camera rotation (preserves state between model changes)
|
|
483
|
-
* - Configurable
|
|
577
|
+
* - Configurable multi-light system (spot, point, directional, hemisphere, ambient)
|
|
484
578
|
* - Optional background (image URL or hex color like "#1a1a2e")
|
|
485
579
|
* - Optional contact shadows under models
|
|
486
580
|
* - Shadow support
|
|
@@ -502,11 +596,7 @@ export declare function preloadModel(url: string): void;
|
|
|
502
596
|
* @param controls.autoRotateSpeed - Auto-rotation speed. Default: `2`
|
|
503
597
|
* @param background - Background: image URL (e.g., `"/bg.jpg"`) or hex color (e.g., `"#1a1a2e"`)
|
|
504
598
|
* @param shadows - Enable shadow rendering. Default: `true`
|
|
505
|
-
* @param
|
|
506
|
-
* @param spotLight - Spot light configuration object. Example: `{ position: [5, 10, 5], intensity: 50 }`
|
|
507
|
-
* @param spotLight.position - Light position as [x, y, z]. Example: `[5, 10, 5]`. Default: `[5, 10, 5]`
|
|
508
|
-
* @param spotLight.intensity - Light intensity. Example: `50`. Default: `50`
|
|
509
|
-
* @param spotLight.castShadow - Enable shadow casting. Default: `true`
|
|
599
|
+
* @param lights - Array of light configurations. Supports spot, point, directional, hemisphere, and ambient lights. Default: `[{ type: 'ambient', intensity: 0.5 }, { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true }]`
|
|
510
600
|
* @param contactShadows - Contact shadows configuration. Can be `true` for default settings or object with custom settings. Example: `{ position: [0, -1, 0], opacity: 0.5, blur: 2 }`
|
|
511
601
|
* @param contactShadows.position - Shadow position as [x, y, z]. Example: `[0, -1, 0]`. Default: `[0, -1, 0]`
|
|
512
602
|
* @param contactShadows.opacity - Shadow opacity (0-1). Example: `0.5`. Default: `0.5`
|
|
@@ -515,6 +605,7 @@ export declare function preloadModel(url: string): void;
|
|
|
515
605
|
* @param className - Container CSS class name
|
|
516
606
|
*
|
|
517
607
|
* @example
|
|
608
|
+
* Basic setup with default lighting:
|
|
518
609
|
* ```tsx
|
|
519
610
|
* <Scene3D
|
|
520
611
|
* camera={{ position: [0, 2, 5], fov: 45 }}
|
|
@@ -525,8 +616,38 @@ export declare function preloadModel(url: string): void;
|
|
|
525
616
|
* <AnimatedModel url="/model.glb" position={[0, -1, 0]} />
|
|
526
617
|
* </Scene3D>
|
|
527
618
|
* ```
|
|
619
|
+
*
|
|
620
|
+
* @example
|
|
621
|
+
* Multi-light setup for better illumination:
|
|
622
|
+
* ```tsx
|
|
623
|
+
* <Scene3D
|
|
624
|
+
* camera={{ position: [0, 2, 5], fov: 45 }}
|
|
625
|
+
* lights={[
|
|
626
|
+
* { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true },
|
|
627
|
+
* { type: 'spot', position: [-5, 10, -5], intensity: 30, castShadow: false },
|
|
628
|
+
* { type: 'point', position: [0, 5, 0], intensity: 20 },
|
|
629
|
+
* { type: 'ambient', intensity: 0.3 }
|
|
630
|
+
* ]}
|
|
631
|
+
* >
|
|
632
|
+
* <AnimatedModel url="/model.glb" position={[0, -1, 0]} />
|
|
633
|
+
* </Scene3D>
|
|
634
|
+
* ```
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* Using different light types:
|
|
638
|
+
* ```tsx
|
|
639
|
+
* <Scene3D
|
|
640
|
+
* lights={[
|
|
641
|
+
* { type: 'directional', position: [10, 20, 10], intensity: 40, castShadow: true },
|
|
642
|
+
* { type: 'hemisphere', skyColor: '#87CEEB', groundColor: '#362312', intensity: 0.5 },
|
|
643
|
+
* { type: 'ambient', intensity: 0.2 }
|
|
644
|
+
* ]}
|
|
645
|
+
* >
|
|
646
|
+
* <Model url="/model.glb" />
|
|
647
|
+
* </Scene3D>
|
|
648
|
+
* ```
|
|
528
649
|
*/
|
|
529
|
-
export declare function Scene3D({ children, camera, controls, background, shadows,
|
|
650
|
+
export declare function Scene3D({ children, camera, controls, background, shadows, lights, contactShadows, style, className, }: Scene3DProps): JSX_2.Element;
|
|
530
651
|
|
|
531
652
|
/**
|
|
532
653
|
* Props for Scene3D component
|
|
@@ -538,6 +659,10 @@ export declare function Scene3D({ children, camera, controls, background, shadow
|
|
|
538
659
|
* controls={{ enablePan: false, minDistance: 2 }}
|
|
539
660
|
* background="#1a1a2e"
|
|
540
661
|
* shadows
|
|
662
|
+
* lights={[
|
|
663
|
+
* { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true },
|
|
664
|
+
* { type: 'ambient', intensity: 0.3 }
|
|
665
|
+
* ]}
|
|
541
666
|
* >
|
|
542
667
|
* {children}
|
|
543
668
|
* </Scene3D>
|
|
@@ -580,17 +705,8 @@ export declare interface Scene3DProps {
|
|
|
580
705
|
background?: string;
|
|
581
706
|
/** Enable shadow rendering. Default: true */
|
|
582
707
|
shadows?: boolean;
|
|
583
|
-
/**
|
|
584
|
-
|
|
585
|
-
/** Spot light configuration */
|
|
586
|
-
spotLight?: {
|
|
587
|
-
/** Light position [x, y, z]. Default: [5, 10, 5] */
|
|
588
|
-
position?: [number, number, number];
|
|
589
|
-
/** Light intensity. Default: 50 */
|
|
590
|
-
intensity?: number;
|
|
591
|
-
/** Enable shadow casting. Default: true */
|
|
592
|
-
castShadow?: boolean;
|
|
593
|
-
};
|
|
708
|
+
/** Array of light configurations for multi-light setup */
|
|
709
|
+
lights?: LightConfigUnion[];
|
|
594
710
|
/** Contact shadows configuration (ground shadows under models) */
|
|
595
711
|
contactShadows?: boolean | {
|
|
596
712
|
/** Shadow position [x, y, z]. Default: [0, -1, 0] */
|
|
@@ -606,6 +722,30 @@ export declare interface Scene3DProps {
|
|
|
606
722
|
className?: string;
|
|
607
723
|
}
|
|
608
724
|
|
|
725
|
+
/**
|
|
726
|
+
* Spot light configuration - focused light in a cone (like a flashlight)
|
|
727
|
+
*
|
|
728
|
+
* @example
|
|
729
|
+
* ```tsx
|
|
730
|
+
* { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true }
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
733
|
+
declare interface SpotLightConfig extends BaseLightConfig {
|
|
734
|
+
type: 'spot';
|
|
735
|
+
/** Light position [x, y, z]. Default: [5, 10, 5] */
|
|
736
|
+
position?: [number, number, number];
|
|
737
|
+
/** Enable shadow casting. Default: true */
|
|
738
|
+
castShadow?: boolean;
|
|
739
|
+
/** Cone angle in radians. Default: Math.PI / 6 */
|
|
740
|
+
angle?: number;
|
|
741
|
+
/** Penumbra (soft edges) 0-1. Default: 0.5 */
|
|
742
|
+
penumbra?: number;
|
|
743
|
+
/** Light decay. Default: 2 */
|
|
744
|
+
decay?: number;
|
|
745
|
+
/** Light distance. Default: 0 (infinite) */
|
|
746
|
+
distance?: number;
|
|
747
|
+
}
|
|
748
|
+
|
|
609
749
|
export declare function useAnimationController(animations: THREE.AnimationClip[], scene: THREE.Object3D, options?: UseAnimationControllerOptions): {
|
|
610
750
|
playAnimation: (name: string, opts?: {
|
|
611
751
|
loop?: boolean;
|
package/dist/mbt-3d.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react"),D=require("@react-three/drei"),se=require("three"),ne=require("three/examples/jsm/utils/SkeletonUtils.js"),_=require("@react-three/fiber"),oe=require("three/examples/jsm/loaders/KTX2Loader.js"),R=require("react/jsx-runtime");function Q(a){const s=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const n in a)if(n!=="default"){const o=Object.getOwnPropertyDescriptor(a,n);Object.defineProperty(s,n,o.get?o:{enumerable:!0,get:()=>a[n]})}}return s.default=a,Object.freeze(s)}const C=Q(se),Y=Q(ne);function ie({position:a,controlsConfig:s}){const{camera:n}=_.useThree(),o=e.useRef(null);return e.useEffect(()=>{a&&n&&(n.position.set(a[0],a[1],a[2]),n.updateProjectionMatrix(),o.current&&(o.current.target.set(0,0,0),o.current.update()))},[a,n]),R.jsx(D.OrbitControls,{ref:o,makeDefault:!0,enabled:s.enabled,enablePan:s.enablePan,enableZoom:s.enableZoom,enableRotate:s.enableRotate,minDistance:s.minDistance,maxDistance:s.maxDistance,minPolarAngle:s.minPolarAngle,maxPolarAngle:s.maxPolarAngle,autoRotate:s.autoRotate,autoRotateSpeed:s.autoRotateSpeed})}function ce({background:a}){const s=a==null?void 0:a.startsWith("#");return a?s?R.jsx("color",{attach:"background",args:[a]}):R.jsx(ue,{url:a}):null}function ue({url:a}){const s=D.useTexture(a);return e.useMemo(()=>{s.colorSpace=C.SRGBColorSpace},[s]),R.jsx("primitive",{attach:"background",object:s})}function le({children:a,camera:s={},controls:n={},background:o,shadows:d=!0,ambientIntensity:g=.5,spotLight:b={},contactShadows:y=!0,style:h,className:r}){const t={position:s.position||[0,2,5],fov:s.fov||45},c={enabled:n.enabled??!0,enablePan:n.enablePan??!0,enableZoom:n.enableZoom??!0,enableRotate:n.enableRotate??!0,minDistance:n.minDistance,maxDistance:n.maxDistance,minPolarAngle:n.minPolarAngle,maxPolarAngle:n.maxPolarAngle,autoRotate:n.autoRotate??!1,autoRotateSpeed:n.autoRotateSpeed??2},u={position:b.position||[5,10,5],intensity:b.intensity??50,castShadow:b.castShadow??!0},p=typeof y=="object"?{position:y.position||[0,-1,0],opacity:y.opacity??.5,blur:y.blur??2}:y?{position:[0,-1,0],opacity:.5,blur:2}:null;return R.jsx("div",{style:h,className:r,children:R.jsxs(_.Canvas,{shadows:d,camera:{position:t.position,fov:t.fov},style:{width:"100%",height:"100%"},children:[R.jsx(e.Suspense,{fallback:null,children:R.jsx(ce,{background:o})}),R.jsx("ambientLight",{intensity:g}),R.jsx("spotLight",{position:u.position,intensity:u.intensity,castShadow:u.castShadow}),R.jsx(e.Suspense,{fallback:null,children:a}),R.jsx(ie,{position:t.position,controlsConfig:c}),p&&R.jsx(D.ContactShadows,{position:p.position,opacity:p.opacity,blur:p.blur})]})})}function U(a,s){const n=e.useRef(new Map),o=e.useRef({}),d=e.useRef({});e.useEffect(()=>{s&&(o.current={...s})},[s]),e.useEffect(()=>{if(!a)return;const h=new Map;a.traverse(r=>{if(r.isMesh){const t=r;t.name&&h.set(t.name,t)}}),n.current=h},[a]),_.useFrame(()=>{const h=n.current;if(h.size===0)return;const r={...o.current,...d.current};for(const[t,c]of Object.entries(r)){const u=h.get(t);u&&u.visible!==c&&(u.visible=c)}});const g=e.useCallback((h,r)=>{d.current[h]=r;const t=n.current.get(h);t&&(t.visible=r)},[]),b=e.useCallback(()=>Array.from(n.current.keys()).sort(),[]),y=e.useCallback(()=>{const h={};return n.current.forEach((r,t)=>{h[t]=r.visible}),h},[]);return{setMeshVisibility:g,getMeshNames:b,getMeshVisibility:y}}function z(a,s){const n=e.useRef(new Map),o=e.useRef(new Map);e.useEffect(()=>{if(!a)return;const r=new Map;a.traverse(t=>{if(t.isMesh){const c=t;(Array.isArray(c.material)?c.material:[c.material]).forEach(p=>{p.name&&!r.has(p.name)&&r.set(p.name,p)})}}),n.current=r,s&&Object.entries(s).forEach(([t,c])=>{const u=r.get(t);if(u&&!Array.isArray(u)){const p=d(c);u.color&&u.color.copy(p),o.current.set(t,p)}})},[a,s]),_.useFrame(()=>{o.current.forEach((r,t)=>{const c=n.current.get(t);if(c&&!Array.isArray(c)){const u=c;u.color&&!u.color.equals(r)&&(u.color.copy(r),u.needsUpdate=!0)}})});const d=r=>typeof r=="string"?new C.Color(r):new C.Color(r[0],r[1],r[2]),g=e.useCallback((r,t)=>{const c=d(t);o.current.set(r,c);const u=n.current.get(r);if(u&&!Array.isArray(u)){const p=u;p.color&&(p.color.copy(c),p.needsUpdate=!0)}},[]),b=e.useCallback(()=>Array.from(n.current.keys()).sort(),[]),y=e.useCallback(r=>{const t=n.current.get(r);if(t&&!Array.isArray(t)){const c=t;if(c.color)return"#"+c.color.getHexString()}return null},[]),h=e.useCallback(()=>{const r={};return n.current.forEach((t,c)=>{if(!Array.isArray(t)){const u=t;u.color&&(r[c]="#"+u.color.getHexString())}}),r},[]);return{setMaterialColor:g,getMaterialNames:b,getMaterialColor:y,getAllMaterialColors:h}}function X(a,s){const{gl:n}=_.useThree(),o=e.useRef(new Map),d=e.useRef(new C.TextureLoader),g=e.useRef(null),b=e.useRef(new Map),y=e.useRef(new Set),h=e.useRef("");e.useEffect(()=>{if(!g.current)try{const l=typeof WebAssembly=="object"&&typeof WebAssembly.validate=="function";console.log("[useMaterialTexture] Browser features:"),console.log(` WebAssembly supported: ${l}`),console.log(` WebGL2: ${n.capabilities.isWebGL2}`);const i=new oe.KTX2Loader;i.setTranscoderPath("/basis/"),i.detectSupport(n),g.current=i,console.log("[useMaterialTexture] ✅ KTX2Loader initialized"),console.log("[useMaterialTexture] Transcoder path: /basis/"),fetch("/basis/basis_transcoder.wasm").then(f=>{f.ok?console.log("[useMaterialTexture] ✅ basis_transcoder.wasm is accessible"):console.error("[useMaterialTexture] ❌ basis_transcoder.wasm returned",f.status)}).catch(f=>{console.error("[useMaterialTexture] ❌ Failed to check basis_transcoder.wasm:",f)}),l||(console.warn("[useMaterialTexture] ⚠️ WebAssembly not supported! KTX2 will fallback to CPU decoding (slow)"),console.warn("[useMaterialTexture] ⚠️ Recommend using WebP instead of KTX2 for this browser"))}catch(l){console.error("[useMaterialTexture] ❌ Failed to initialize KTX2Loader:",l)}return()=>{g.current&&(g.current.dispose(),g.current=null)}},[n]),e.useEffect(()=>{if(!a)return;const l=new Map;a.traverse(i=>{if(i.isMesh){const f=i;(Array.isArray(f.material)?f.material:[f.material]).forEach(m=>{m.name&&!l.has(m.name)&&l.set(m.name,m)})}}),o.current=l},[a]);const r=e.useCallback(l=>l.toLowerCase().endsWith(".ktx2")?g.current?g.current:(console.warn("[useMaterialTexture] KTX2Loader not initialized, falling back to TextureLoader"),d.current):d.current,[]);e.useEffect(()=>{if(!s||!a)return;const l=o.current;if(l.size===0)return;const i=JSON.stringify(s);if(h.current===i){console.log("[useMaterialTexture] Textures unchanged, skipping reload");return}h.current=i;let f=!1;const A=new Map;Object.entries(s).forEach(([M,S])=>{A.set(M,typeof S=="string"?{map:S}:S)}),console.log("[useMaterialTexture] Starting texture load for",A.size,"materials");const m=[];A.forEach((M,S)=>{const O=l.get(S);if(!O||!O.isMeshStandardMaterial){console.warn(`[useMaterialTexture] Material "${S}" not found or not MeshStandardMaterial`);return}const x=O;x.map=null,x.normalMap=null,x.roughnessMap=null,x.metalnessMap=null,x.emissiveMap=null,x.emissive=new C.Color(0),x.emissiveIntensity=0,x.aoMap=null,x.needsUpdate=!0,Object.entries(M).forEach(([T,j])=>{if(!j)return;const E=`${S}_${T}_${j}`,v=b.current.get(E);if(v){console.log(`[useMaterialTexture] Using cached texture: ${S}.${T}`),f||t(x,T,v);return}if(y.current.has(E)){console.log(`[useMaterialTexture] Skipping already loading: ${S}.${T}`);return}m.push({materialName:S,textureType:T,url:j,material:x})})}),console.log(`[useMaterialTexture] Queued ${m.length} textures to load`);let w=0;const k=()=>{if(f||w>=m.length){console.log("[useMaterialTexture] All textures loaded");return}const M=m[w++],S=`${M.materialName}_${M.textureType}_${M.url}`;console.log(`[useMaterialTexture] Loading (${w}/${m.length}): ${M.materialName}.${M.textureType} from ${M.url}`),y.current.add(S);const O=r(M.url),x=M.url.toLowerCase().endsWith(".ktx2")?"KTX2Loader":"TextureLoader";console.log(`[useMaterialTexture] Using ${x} for ${M.url}`),O.load(M.url,T=>{var N,W,B,L,$,F;if(y.current.delete(S),f){console.log(`[useMaterialTexture] Disposed, cleaning up texture: ${M.materialName}.${M.textureType}`),T.dispose();return}const j=((N=T.image)==null?void 0:N.width)||((B=(W=T.source)==null?void 0:W.data)==null?void 0:B.width)||"unknown",E=((L=T.image)==null?void 0:L.height)||((F=($=T.source)==null?void 0:$.data)==null?void 0:F.height)||"unknown";console.log(`[useMaterialTexture] ✅ Loaded: ${M.materialName}.${M.textureType} (${j}x${E})`),T.colorSpace=M.textureType==="map"||M.textureType==="emissiveMap"?C.SRGBColorSpace:C.NoColorSpace,T.wrapS=C.RepeatWrapping,T.wrapT=C.RepeatWrapping,T.flipY=!1,b.current.set(S,T),t(M.material,M.textureType,T);const v=M.url.endsWith(".ktx2")?500:150;console.log(`[useMaterialTexture] Waiting ${v}ms before next texture...`),setTimeout(k,v)},T=>{if(T.lengthComputable){const j=Math.round(T.loaded/T.total*100);j%25===0&&console.log(`[useMaterialTexture] Progress ${M.materialName}.${M.textureType}: ${j}%`)}},T=>{y.current.delete(S),f||(console.error(`[useMaterialTexture] ❌ Failed to load ${M.materialName}.${M.textureType} from ${M.url}`),console.error("[useMaterialTexture] Error details:",T),console.error("[useMaterialTexture] Loader type:",x),M.url.endsWith(".ktx2")&&(console.error("[useMaterialTexture] KTX2 error - file may not be in Basis Universal format!"),console.error("[useMaterialTexture] Make sure files are created with: gltf-transform etc1s input.png output.ktx2"))),setTimeout(k,100)})};return k(),()=>{console.log("[useMaterialTexture] Cleanup: disposed"),f=!0}},[a,s,r]);const t=(l,i,f)=>{switch(i){case"map":l.map=f;break;case"normalMap":l.normalMap=f;break;case"roughnessMap":l.roughnessMap=f;break;case"metalnessMap":l.metalnessMap=f;break;case"emissiveMap":l.emissiveMap=f,l.emissive=new C.Color(16777215),l.emissiveIntensity=1;break;case"alphaMap":console.log(`[useMaterialTexture] Skipping alphaMap for "${l.name}" to prevent disappearing`);break;case"aoMap":l.aoMap=f;break}l.needsUpdate=!0},c=e.useCallback((l,i)=>{const f=typeof i=="string"?{map:i}:i,A=o.current.get(l);if(!A||!A.isMeshStandardMaterial){console.warn(`Material "${l}" not found or not MeshStandardMaterial`);return}const m=A;Object.entries(f).forEach(([w,k])=>{if(!k)return;const M=`${l}_${w}_${k}`,S=b.current.get(M);if(S){t(m,w,S);return}r(k).load(k,x=>{x.colorSpace=w==="map"||w==="emissiveMap"?C.SRGBColorSpace:C.NoColorSpace,x.wrapS=C.RepeatWrapping,x.wrapT=C.RepeatWrapping,b.current.set(M,x),t(m,w,x)},void 0,x=>{console.error(`Failed to load texture ${k}:`,x)})})},[r]),u=e.useCallback(()=>Array.from(o.current.keys()).sort(),[]),p=e.useCallback(l=>{const i=o.current.get(l);if(!i||!i.isMeshStandardMaterial)return;const f=i;f.map=null,f.normalMap=null,f.roughnessMap=null,f.metalnessMap=null,f.emissiveMap=null,f.alphaMap=null,f.aoMap=null,f.needsUpdate=!0},[]);return{setMaterialTextures:c,getMaterialNames:u,clearMaterialTextures:p}}function ee({url:a,position:s=[0,0,0],rotation:n=[0,0,0],scale:o=1,meshVisibility:d,materialColors:g,materialTextures:b,onLoad:y,onError:h}){const{scene:r}=D.useGLTF(a),t=e.useRef(y);t.current=y;const c=e.useMemo(()=>{const p=r.clone(),l=[],i=new Set,f=[];let A=0;return p.traverse(m=>{if(A++,m.type==="Bone"&&f.push(m.name),m.isMesh){const w=m;l.push(w.name),w.castShadow=!0,w.receiveShadow=!0,(Array.isArray(w.material)?w.material:[w.material]).forEach(M=>i.add(M.name))}}),setTimeout(()=>{var m;(m=t.current)==null||m.call(t,{meshes:l.sort(),materials:Array.from(i).sort(),bones:f.sort(),nodeCount:A})},0),p},[r]);U(c,d),z(c,g),X(c,b);const u=typeof o=="number"?[o,o,o]:o;return R.jsx("group",{position:s,rotation:n,scale:u,children:R.jsx("primitive",{object:c})})}ee.preload=a=>{D.useGLTF.preload(a)};function te(a,s,n){const{actions:o,names:d}=D.useAnimations(a,s),g=e.useRef(null),b=e.useRef(n==null?void 0:n.defaultAnimation);e.useEffect(()=>{if(d.length===0)return;const t=b.current;let c=d[0];if(t){const p=d.find(l=>l===t||l.includes(t));p&&(c=p)}const u=o[c];u&&(u.reset().fadeIn(.5).play(),g.current=u)},[o,d]);const y=e.useCallback((t,c)=>{const{loop:u=!1,crossFadeDuration:p=.2,restoreDefault:l=!0}=c||{};let i=o[t];if(!i){const A=Object.keys(o).find(m=>m.toLowerCase().includes(t.toLowerCase())||t.toLowerCase().includes(m.toLowerCase()));A&&(i=o[A])}if(!i){console.warn(`Animation "${t}" not found. Available: ${d.join(", ")}`);return}const f=g.current;if(!(f===i&&i.isRunning())&&(f&&f!==i&&f.fadeOut(p),i.reset(),i.fadeIn(p),i.setLoop(u?C.LoopRepeat:C.LoopOnce,u?1/0:1),i.clampWhenFinished=!u,i.play(),u||i.getMixer().update(0),g.current=i,l&&!u&&b.current)){const A=i.getMixer(),m=w=>{if(w.action===i){A.removeEventListener("finished",m);const k=o[b.current];k&&(i.fadeOut(p),k.reset().fadeIn(p).play(),g.current=k)}};A.addEventListener("finished",m)}},[o,d]),h=e.useCallback(()=>{var t;(t=g.current)==null||t.fadeOut(.2),g.current=null},[]),r=e.useCallback(()=>d,[d]);return{playAnimation:y,stopAnimation:h,getAnimationNames:r,actions:o}}function q(a,s){const n=e.useRef(s||{}),o=e.useRef([]),d=e.useRef([]);e.useEffect(()=>{const h=new Set,r=[];a.traverse(t=>{t instanceof C.Mesh&&t.morphTargetDictionary&&t.morphTargetInfluences&&(r.push(t),Object.keys(t.morphTargetDictionary).forEach(c=>{h.add(c)}))}),o.current=Array.from(h).sort(),d.current=r},[a]),_.useFrame(()=>{const h=n.current;d.current.forEach(r=>{!r.morphTargetDictionary||!r.morphTargetInfluences||Object.entries(h).forEach(([t,c])=>{const u=r.morphTargetDictionary[t];u!==void 0&&(r.morphTargetInfluences[u]=c)})})}),e.useEffect(()=>{s&&(n.current={...s})},[s]);const g=e.useCallback((h,r)=>{n.current[h]=Math.max(0,Math.min(1,r))},[]),b=e.useCallback(()=>o.current,[]),y=e.useCallback(()=>({...n.current}),[]);return{setMorphTarget:g,getMorphTargetNames:b,getMorphTargetValues:y}}const re=e.createContext(null);function fe(){const a=e.useContext(re);if(!a)throw new Error("BoneAttachment must be used within an AnimatedModel");return a}const V=e.forwardRef(({url:a,position:s=[0,0,0],rotation:n=[0,0,0],scale:o=1,defaultAnimation:d,morphTargets:g,meshVisibility:b,materialColors:y,materialTextures:h,onLoad:r,onError:t,children:c},u)=>{const p=e.useRef(null),l=e.useRef([]),i=e.useRef(r);i.current=r;const{scene:f,animations:A}=D.useGLTF(a),m=e.useMemo(()=>Y.clone(f),[f]),{playAnimation:w,stopAnimation:k,getAnimationNames:M}=te(A,m,{defaultAnimation:d}),{setMorphTarget:S}=q(m,g),{setMeshVisibility:O,getMeshNames:x}=U(m,b),{setMaterialColor:T,getMaterialNames:j,getMaterialColor:E}=z(m,y),{setMaterialTextures:v,clearMaterialTextures:N}=X(m,h);e.useEffect(()=>{if(!m)return;const L=setTimeout(()=>{var J;const $=[],F=[],I=new Set,H=new Set;let Z=0;m.traverse(G=>{if(Z++,G.type==="Bone"&&$.push(G.name),G.isMesh){const P=G;F.push(P.name),P.castShadow=!0,P.receiveShadow=!0,(Array.isArray(P.material)?P.material:[P.material]).forEach(K=>{I.add(K.name),K.shadowSide=C.DoubleSide}),P.morphTargetDictionary&&Object.keys(P.morphTargetDictionary).forEach(K=>{H.add(K)})}}),l.current=Array.from(H).sort(),(J=i.current)==null||J.call(i,{meshes:F.sort(),materials:Array.from(I).sort(),bones:$.sort(),nodeCount:Z,animations:A.map(G=>G.name),morphTargetNames:l.current})},0);return()=>clearTimeout(L)},[m,A]),e.useImperativeHandle(u,()=>({playAnimation:w,stopAnimation:k,getAnimationNames:M,getGroup:()=>p.current,setMorphTarget:S,getMorphTargetNames:()=>l.current,setMeshVisibility:O,getMeshNames:x,setMaterialColor:T,getMaterialNames:j,getMaterialColor:E,setMaterialTextures:v,clearMaterialTextures:N}));const W=e.useMemo(()=>({scene:m,getBone:L=>m.getObjectByName(L)||null}),[m]),B=typeof o=="number"?[o,o,o]:o;return R.jsx(re.Provider,{value:W,children:R.jsxs("group",{ref:p,position:s,rotation:n,scale:B,children:[R.jsx("primitive",{object:m}),c]})})});V.displayName="AnimatedModel";V.preload=a=>{D.useGLTF.preload(a)};const ae=e.forwardRef(({url:a,position:s=[0,0,0],rotation:n=[0,0,0],scale:o=1,morphTargets:d,meshVisibility:g,materialColors:b,materialTextures:y,onMorphTargetsFound:h,onLoad:r,onError:t},c)=>{const{scene:u}=D.useGLTF(a),p=e.useRef(r);p.current=r;const l=e.useRef(h);l.current=h;const i=e.useMemo(()=>u.clone(),[u]),{setMorphTarget:f,getMorphTargetNames:A,getMorphTargetValues:m}=q(i,d),{setMeshVisibility:w,getMeshNames:k}=U(i,g),{setMaterialColor:M,getMaterialNames:S,getMaterialColor:O}=z(i,b),{setMaterialTextures:x,clearMaterialTextures:T}=X(i,y);e.useEffect(()=>{var v;const E=A();E.length>0&&((v=l.current)==null||v.call(l,E))},[i,A]),e.useEffect(()=>{var B;if(!i)return;const E=[],v=new Set,N=[];let W=0;i.traverse(L=>{if(W++,L.type==="Bone"&&N.push(L.name),L.isMesh){const $=L;E.push($.name),$.castShadow=!0,$.receiveShadow=!0,(Array.isArray($.material)?$.material:[$.material]).forEach(I=>v.add(I.name))}}),(B=p.current)==null||B.call(p,{meshes:E.sort(),materials:Array.from(v).sort(),bones:N.sort(),nodeCount:W})},[i]),e.useImperativeHandle(c,()=>({setMorphTarget:f,getMorphTargetNames:A,getMorphTargetValues:m,setMeshVisibility:w,getMeshNames:k,setMaterialColor:M,getMaterialNames:S,getMaterialColor:O,setMaterialTextures:x,clearMaterialTextures:T}));const j=typeof o=="number"?[o,o,o]:o;return R.jsx("group",{position:s,rotation:n,scale:j,children:R.jsx("primitive",{object:i})})});ae.displayName="MorphableModel";function me({children:a,bone:s,position:n=[0,0,0],rotation:o=[0,0,0],scale:d=1}){const{getBone:g}=fe(),[b,y]=e.useState(null);if(e.useEffect(()=>{const r=g(s);r?y(r):console.warn(`Bone "${s}" not found in model`)},[s,g]),!b)return null;const h=typeof d=="number"?[d,d,d]:d;return _.createPortal(R.jsx("group",{position:n,rotation:o,scale:h,children:a}),b)}function pe(a,s){const{scene:n,animations:o}=D.useGLTF(a),d=e.useMemo(()=>Y.clone(n),[n]);return e.useEffect(()=>{var r;if(!d)return;const g=[],b=[],y=new Set;let h=0;d.traverse(t=>{if(h++,t.type==="Bone"&&g.push(t.name),t.isMesh){const c=t;b.push(c.name),c.castShadow=!0,c.receiveShadow=!0,(Array.isArray(c.material)?c.material:[c.material]).forEach(p=>{y.add(p.name),p.shadowSide=C.DoubleSide})}}),(r=s==null?void 0:s.onLoad)==null||r.call(s,{meshes:b.sort(),materials:Array.from(y).sort(),bones:g.sort(),nodeCount:h})},[d,s]),{scene:d,animations:o}}function de(a){D.useGLTF.preload(a)}exports.AnimatedModel=V;exports.BoneAttachment=me;exports.Model=ee;exports.MorphableModel=ae;exports.Scene3D=le;exports.preloadModel=de;exports.useAnimationController=te;exports.useClonedModel=pe;exports.useMaterialColor=z;exports.useMaterialTexture=X;exports.useMeshVisibility=U;exports.useMorphTargets=q;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react"),O=require("@react-three/drei"),oe=require("three"),ae=require("three/examples/jsm/utils/SkeletonUtils.js"),B=require("@react-three/fiber"),ne=require("three/examples/jsm/loaders/KTX2Loader.js"),w=require("react/jsx-runtime");function J(s){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const r in s)if(r!=="default"){const l=Object.getOwnPropertyDescriptor(s,r);Object.defineProperty(t,r,l.get?l:{enumerable:!0,get:()=>s[r]})}}return t.default=s,Object.freeze(t)}const E=J(oe),Q=J(ae);function le({position:s,controlsConfig:t}){const{camera:r}=B.useThree(),l=e.useRef(null);return e.useEffect(()=>{s&&r&&(r.position.set(s[0],s[1],s[2]),r.updateProjectionMatrix(),l.current&&(l.current.target.set(0,0,0),l.current.update()))},[s,r]),w.jsx(O.OrbitControls,{ref:l,makeDefault:!0,enabled:t.enabled,enablePan:t.enablePan,enableZoom:t.enableZoom,enableRotate:t.enableRotate,minDistance:t.minDistance,maxDistance:t.maxDistance,minPolarAngle:t.minPolarAngle,maxPolarAngle:t.maxPolarAngle,autoRotate:t.autoRotate,autoRotateSpeed:t.autoRotateSpeed})}function ie({background:s}){const t=s==null?void 0:s.startsWith("#");return s?t?w.jsx("color",{attach:"background",args:[s]}):w.jsx(ce,{url:s}):null}function ce({url:s}){const t=O.useTexture(s);return e.useMemo(()=>{t.colorSpace=E.SRGBColorSpace},[t]),w.jsx("primitive",{attach:"background",object:t})}function ue({config:s}){switch(s.type){case"spot":{const{position:t=[5,10,5],intensity:r=50,castShadow:l=!0,angle:p=Math.PI/6,penumbra:g=.5,decay:T=2,distance:S=0,color:h="#ffffff"}=s;return w.jsx("spotLight",{position:t,intensity:r,castShadow:l,angle:p,penumbra:g,decay:T,distance:S,color:h})}case"point":{const{position:t=[0,5,0],intensity:r=20,color:l="#ffffff",distance:p=0,decay:g=2,castShadow:T=!1}=s;return w.jsx("pointLight",{position:t,intensity:r,color:l,distance:p,decay:g,castShadow:T})}case"directional":{const{position:t=[10,20,10],intensity:r=40,color:l="#ffffff",castShadow:p=!0}=s;return w.jsx("directionalLight",{position:t,intensity:r,color:l,castShadow:p})}case"hemisphere":{const{skyColor:t="#ffffff",groundColor:r="#444444",intensity:l=.5,position:p=[0,10,0]}=s,g=e.useMemo(()=>new E.Color(t),[t]),T=e.useMemo(()=>new E.Color(r),[r]);return w.jsx("hemisphereLight",{args:[g,T,l],position:p})}case"ambient":{const{intensity:t=.5,color:r="#ffffff"}=s;return w.jsx("ambientLight",{intensity:t,color:r})}default:return null}}function pe({children:s,camera:t={},controls:r={},background:l,shadows:p=!0,lights:g=[{type:"ambient",intensity:.5},{type:"spot",position:[5,10,5],intensity:50,castShadow:!0}],contactShadows:T=!0,style:S,className:h}){const o={position:t.position||[0,2,5],fov:t.fov||45},a={enabled:r.enabled??!0,enablePan:r.enablePan??!0,enableZoom:r.enableZoom??!0,enableRotate:r.enableRotate??!0,minDistance:r.minDistance,maxDistance:r.maxDistance,minPolarAngle:r.minPolarAngle,maxPolarAngle:r.maxPolarAngle,autoRotate:r.autoRotate??!1,autoRotateSpeed:r.autoRotateSpeed??2},c=typeof T=="object"?{position:T.position||[0,-1,0],opacity:T.opacity??.5,blur:T.blur??2}:T?{position:[0,-1,0],opacity:.5,blur:2}:null;return w.jsx("div",{style:S,className:h,children:w.jsxs(B.Canvas,{shadows:p,camera:{position:o.position,fov:o.fov},style:{width:"100%",height:"100%"},children:[w.jsx(e.Suspense,{fallback:null,children:w.jsx(ie,{background:l})}),g.map((m,b)=>w.jsx(ue,{config:m},`${m.type}-${b}`)),w.jsx(e.Suspense,{fallback:null,children:s}),w.jsx(le,{position:o.position,controlsConfig:a}),c&&w.jsx(O.ContactShadows,{position:c.position,opacity:c.opacity,blur:c.blur})]})})}function G(s,t){const r=e.useRef(new Map),l=e.useRef({}),p=e.useRef({});e.useEffect(()=>{t&&(l.current={...t})},[t]),e.useEffect(()=>{if(!s)return;const h=new Map;s.traverse(o=>{if(o.isMesh){const a=o;a.name&&h.set(a.name,a)}}),r.current=h},[s]),B.useFrame(()=>{const h=r.current;if(h.size===0)return;const o={...l.current,...p.current};for(const[a,c]of Object.entries(o)){const m=h.get(a);m&&m.visible!==c&&(m.visible=c)}});const g=e.useCallback((h,o)=>{p.current[h]=o;const a=r.current.get(h);a&&(a.visible=o)},[]),T=e.useCallback(()=>Array.from(r.current.keys()).sort(),[]),S=e.useCallback(()=>{const h={};return r.current.forEach((o,a)=>{h[a]=o.visible}),h},[]);return{setMeshVisibility:g,getMeshNames:T,getMeshVisibility:S}}function K(s,t){const r=e.useRef(new Map),l=e.useRef(new Map);e.useEffect(()=>{if(!s)return;const o=new Map;s.traverse(a=>{if(a.isMesh){const c=a;(Array.isArray(c.material)?c.material:[c.material]).forEach(b=>{b.name&&!o.has(b.name)&&o.set(b.name,b)})}}),r.current=o,t&&Object.entries(t).forEach(([a,c])=>{const m=o.get(a);if(m&&!Array.isArray(m)){const b=p(c);m.color&&m.color.copy(b),l.current.set(a,b)}})},[s,t]),B.useFrame(()=>{l.current.forEach((o,a)=>{const c=r.current.get(a);if(c&&!Array.isArray(c)){const m=c;m.color&&!m.color.equals(o)&&(m.color.copy(o),m.needsUpdate=!0)}})});const p=o=>typeof o=="string"?new E.Color(o):new E.Color(o[0],o[1],o[2]),g=e.useCallback((o,a)=>{const c=p(a);l.current.set(o,c);const m=r.current.get(o);if(m&&!Array.isArray(m)){const b=m;b.color&&(b.color.copy(c),b.needsUpdate=!0)}},[]),T=e.useCallback(()=>Array.from(r.current.keys()).sort(),[]),S=e.useCallback(o=>{const a=r.current.get(o);if(a&&!Array.isArray(a)){const c=a;if(c.color)return"#"+c.color.getHexString()}return null},[]),h=e.useCallback(()=>{const o={};return r.current.forEach((a,c)=>{if(!Array.isArray(a)){const m=a;m.color&&(o[c]="#"+m.color.getHexString())}}),o},[]);return{setMaterialColor:g,getMaterialNames:T,getMaterialColor:S,getAllMaterialColors:h}}function U(s,t){const{gl:r}=B.useThree(),l=e.useRef(new Map),p=e.useRef(new E.TextureLoader),g=e.useRef(null),T=e.useRef(new Map),S=e.useRef(new Set),h=e.useRef("");e.useEffect(()=>{if(!g.current)try{const n=typeof WebAssembly=="object"&&typeof WebAssembly.validate=="function";console.log("[useMaterialTexture] Browser features:"),console.log(` WebAssembly supported: ${n}`),console.log(` WebGL2: ${r.capabilities.isWebGL2}`);const i=new ne.KTX2Loader;i.setTranscoderPath("/basis/"),i.detectSupport(r),g.current=i,console.log("[useMaterialTexture] ✅ KTX2Loader initialized"),console.log("[useMaterialTexture] Transcoder path: /basis/"),fetch("/basis/basis_transcoder.wasm").then(f=>{f.ok?console.log("[useMaterialTexture] ✅ basis_transcoder.wasm is accessible"):console.error("[useMaterialTexture] ❌ basis_transcoder.wasm returned",f.status)}).catch(f=>{console.error("[useMaterialTexture] ❌ Failed to check basis_transcoder.wasm:",f)}),n||(console.warn("[useMaterialTexture] ⚠️ WebAssembly not supported! KTX2 will fallback to CPU decoding (slow)"),console.warn("[useMaterialTexture] ⚠️ Recommend using WebP instead of KTX2 for this browser"))}catch(n){console.error("[useMaterialTexture] ❌ Failed to initialize KTX2Loader:",n)}return()=>{g.current&&(g.current.dispose(),g.current=null)}},[r]),e.useEffect(()=>{if(!s)return;const n=new Map;s.traverse(i=>{if(i.isMesh){const f=i;(Array.isArray(f.material)?f.material:[f.material]).forEach(d=>{d.name&&!n.has(d.name)&&n.set(d.name,d)})}}),l.current=n},[s]);const o=e.useCallback(n=>n.toLowerCase().endsWith(".ktx2")?g.current?g.current:(console.warn("[useMaterialTexture] KTX2Loader not initialized, falling back to TextureLoader"),p.current):p.current,[]);e.useEffect(()=>{if(!t||!s)return;const n=l.current;if(n.size===0)return;const i=JSON.stringify(t);if(h.current===i){console.log("[useMaterialTexture] Textures unchanged, skipping reload");return}h.current=i;let f=!1;const x=new Map;Object.entries(t).forEach(([M,y])=>{x.set(M,typeof y=="string"?{map:y}:y)}),console.log("[useMaterialTexture] Starting texture load for",x.size,"materials");const d=[];x.forEach((M,y)=>{var A,k;const D=n.get(y);if(!D||!D.isMeshStandardMaterial){console.warn(`[useMaterialTexture] Material "${y}" not found or not MeshStandardMaterial`);return}const u=D;console.log(`[useMaterialTexture] 📋 Material "${y}" BEFORE reset:`),console.log(` - map: ${u.map?"EXISTS":"null"} ${u.map?`(uuid: ${u.map.uuid})`:""}`),console.log(` - normalMap: ${u.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${u.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${u.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${u.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${u.aoMap?"EXISTS":"null"}`),console.log(` - color: ${(A=u.color)==null?void 0:A.getHexString()}`),console.log(` - emissive: ${(k=u.emissive)==null?void 0:k.getHexString()}`),console.log(` - material uuid: ${u.uuid}`),u.map&&(console.log(`[useMaterialTexture] 🗑️ Disposing old map (uuid: ${u.map.uuid})`),u.map.dispose()),u.normalMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old normalMap"),u.normalMap.dispose()),u.roughnessMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old roughnessMap"),u.roughnessMap.dispose()),u.metalnessMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old metalnessMap"),u.metalnessMap.dispose()),u.emissiveMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old emissiveMap"),u.emissiveMap.dispose()),u.aoMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old aoMap"),u.aoMap.dispose()),u.map=null,u.normalMap=null,u.roughnessMap=null,u.metalnessMap=null,u.emissiveMap=null,u.emissive=new E.Color(0),u.emissiveIntensity=0,u.aoMap=null,u.needsUpdate=!0,console.log(`[useMaterialTexture] ✅ Material "${y}" AFTER reset: all maps cleared and disposed`),Object.entries(M).forEach(([$,C])=>{if(!C)return;const j=`${y}_${$}_${C}`,X=T.current.get(j);if(X){console.log(`[useMaterialTexture] Using cached texture: ${y}.${$}`),f||a(u,$,X);return}if(S.current.has(j)){console.log(`[useMaterialTexture] Skipping already loading: ${y}.${$}`);return}d.push({materialName:y,textureType:$,url:C,material:u})})}),console.log(`[useMaterialTexture] Queued ${d.length} textures to load`);let v=0;const R=()=>{if(f||v>=d.length){console.log("[useMaterialTexture] ✅ All textures loaded"),console.log("[useMaterialTexture] 📊 FINAL material states:"),n.forEach((A,k)=>{var C,j;const $=A;console.log(` Material "${k}":`),console.log(` - map: ${$.map?"EXISTS":"null"} ${$.map?`(colorSpace: ${$.map.colorSpace})`:""}`),console.log(` - normalMap: ${$.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${$.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${$.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${$.emissiveMap?"EXISTS":"null"}`),console.log(` - color: ${(C=$.color)==null?void 0:C.getHexString()}`),console.log(` - emissive: ${(j=$.emissive)==null?void 0:j.getHexString()}`),console.log(` - emissiveIntensity: ${$.emissiveIntensity}`),console.log(` - roughness: ${$.roughness}`),console.log(` - metalness: ${$.metalness}`)});return}const M=d[v++],y=`${M.materialName}_${M.textureType}_${M.url}`;console.log(`[useMaterialTexture] Loading (${v}/${d.length}): ${M.materialName}.${M.textureType} from ${M.url}`),S.current.add(y);const D=o(M.url),u=M.url.toLowerCase().endsWith(".ktx2")?"KTX2Loader":"TextureLoader";console.log(`[useMaterialTexture] Using ${u} for ${M.url}`),D.load(M.url,A=>{var j,X,P,I,L,W;if(S.current.delete(y),f){console.log(`[useMaterialTexture] Disposed, cleaning up texture: ${M.materialName}.${M.textureType}`),A.dispose();return}const k=((j=A.image)==null?void 0:j.width)||((P=(X=A.source)==null?void 0:X.data)==null?void 0:P.width)||"unknown",$=((I=A.image)==null?void 0:I.height)||((W=(L=A.source)==null?void 0:L.data)==null?void 0:W.height)||"unknown";console.log(`[useMaterialTexture] ✅ Loaded: ${M.materialName}.${M.textureType} (${k}x${$})`),A.colorSpace=M.textureType==="map"||M.textureType==="emissiveMap"?E.SRGBColorSpace:E.NoColorSpace,A.wrapS=E.RepeatWrapping,A.wrapT=E.RepeatWrapping,A.flipY=!1,T.current.set(y,A),a(M.material,M.textureType,A);const C=M.url.endsWith(".ktx2")?500:15056;console.log(`[useMaterialTexture] Waiting111111 ${C}ms before next texture...`),setTimeout(R,0)},A=>{if(A.lengthComputable){const k=Math.round(A.loaded/A.total*100);k%25===0&&console.log(`[useMaterialTexture] Progress ${M.materialName}.${M.textureType}: ${k}%`)}},A=>{S.current.delete(y),f||(console.error(`[useMaterialTexture] ❌ Failed to load ${M.materialName}.${M.textureType} from ${M.url}`),console.error("[useMaterialTexture] Error details:",A),console.error("[useMaterialTexture] Loader type:",u),M.url.endsWith(".ktx2")&&(console.error("[useMaterialTexture] KTX2 error - file may not be in Basis Universal format!"),console.error("[useMaterialTexture] Make sure files are created with: gltf-transform etc1s input.png output.ktx2"))),setTimeout(R,100)})};return R(),()=>{console.log("[useMaterialTexture] Cleanup: disposed"),f=!0}},[s,t,o]);const a=(n,i,f)=>{var x,d;switch(console.log(`[useMaterialTexture] 🎨 Applying texture: ${n.name}.${i} (texture uuid: ${f.uuid})`),i){case"map":n.map=f;break;case"normalMap":n.normalMap=f;break;case"roughnessMap":n.roughnessMap=f;break;case"metalnessMap":n.metalnessMap=f;break;case"emissiveMap":n.emissiveMap=f,n.emissive=new E.Color(16777215),n.emissiveIntensity=1;break;case"alphaMap":console.log(`[useMaterialTexture] Skipping alphaMap for "${n.name}" to prevent disappearing`);break;case"aoMap":n.aoMap=f;break}n.needsUpdate=!0,console.log(`[useMaterialTexture] ✅ Applied ${i} to ${n.name}, needsUpdate=true`),console.log(`[useMaterialTexture] 📊 Material "${n.name}" FINAL state:`),console.log(` - map: ${n.map?"EXISTS":"null"} ${n.map?`(uuid: ${n.map.uuid}, colorSpace: ${n.map.colorSpace})`:""}`),console.log(` - normalMap: ${n.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${n.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${n.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${n.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${n.aoMap?"EXISTS":"null"}`),console.log(` - color: ${(x=n.color)==null?void 0:x.getHexString()}`),console.log(` - emissive: ${(d=n.emissive)==null?void 0:d.getHexString()}`),console.log(` - emissiveIntensity: ${n.emissiveIntensity}`),console.log(` - roughness: ${n.roughness}`),console.log(` - metalness: ${n.metalness}`)},c=e.useCallback((n,i)=>{const f=typeof i=="string"?{map:i}:i,x=l.current.get(n);if(!x||!x.isMeshStandardMaterial){console.warn(`Material "${n}" not found or not MeshStandardMaterial`);return}const d=x;Object.entries(f).forEach(([v,R])=>{if(!R)return;const M=`${n}_${v}_${R}`,y=T.current.get(M);if(y){a(d,v,y);return}o(R).load(R,u=>{u.colorSpace=v==="map"||v==="emissiveMap"?E.SRGBColorSpace:E.NoColorSpace,u.wrapS=E.RepeatWrapping,u.wrapT=E.RepeatWrapping,T.current.set(M,u),a(d,v,u)},void 0,u=>{console.error(`Failed to load texture ${R}:`,u)})})},[o]),m=e.useCallback(()=>Array.from(l.current.keys()).sort(),[]),b=e.useCallback(n=>{const i=l.current.get(n);if(!i||!i.isMeshStandardMaterial)return;const f=i;f.map=null,f.normalMap=null,f.roughnessMap=null,f.metalnessMap=null,f.emissiveMap=null,f.alphaMap=null,f.aoMap=null,f.needsUpdate=!0},[]);return{setMaterialTextures:c,getMaterialNames:m,clearMaterialTextures:b}}function ee({url:s,position:t=[0,0,0],rotation:r=[0,0,0],scale:l=1,meshVisibility:p,materialColors:g,materialTextures:T,onLoad:S,onError:h}){const{scene:o}=O.useGLTF(s),a=e.useRef(S);a.current=S;const c=e.useMemo(()=>{const b=o.clone();console.log("[Model] 🔍 Scene clone created, checking materials...");const n=[],i=new Set,f=[];let x=0;return b.traverse(d=>{if(x++,d.type==="Bone"&&f.push(d.name),d.isMesh){const v=d;n.push(v.name),v.castShadow=!0,v.receiveShadow=!0,(Array.isArray(v.material)?v.material:[v.material]).forEach(M=>{i.add(M.name),console.log(`[Model] 📦 Material found: "${M.name}" (uuid: ${M.uuid})`);const y=M;console.log(` - Has map: ${y.map?"YES":"NO"}`),console.log(` - Has normalMap: ${y.normalMap?"YES":"NO"}`),console.log(` - Has roughnessMap: ${y.roughnessMap?"YES":"NO"}`),console.log(` - Has metalnessMap: ${y.metalnessMap?"YES":"NO"}`)})}}),console.log(`[Model] 📊 Clone summary: ${n.length} meshes, ${i.size} materials`),setTimeout(()=>{var d;(d=a.current)==null||d.call(a,{meshes:n.sort(),materials:Array.from(i).sort(),bones:f.sort(),nodeCount:x})},0),b},[o]);G(c,p),K(c,g),U(c,T);const m=typeof l=="number"?[l,l,l]:l;return w.jsx("group",{position:t,rotation:r,scale:m,children:w.jsx("primitive",{object:c})})}ee.preload=s=>{O.useGLTF.preload(s)};function te(s,t,r){const{actions:l,names:p}=O.useAnimations(s,t),g=e.useRef(null),T=e.useRef(r==null?void 0:r.defaultAnimation);e.useEffect(()=>{if(p.length===0)return;const a=T.current;let c=p[0];if(a){const b=p.find(n=>n===a||n.includes(a));b&&(c=b)}const m=l[c];m&&(m.reset().fadeIn(.5).play(),g.current=m)},[l,p]);const S=e.useCallback((a,c)=>{const{loop:m=!1,crossFadeDuration:b=.2,restoreDefault:n=!0}=c||{};let i=l[a];if(!i){const x=Object.keys(l).find(d=>d.toLowerCase().includes(a.toLowerCase())||a.toLowerCase().includes(d.toLowerCase()));x&&(i=l[x])}if(!i){console.warn(`Animation "${a}" not found. Available: ${p.join(", ")}`);return}const f=g.current;if(!(f===i&&i.isRunning())&&(f&&f!==i&&f.fadeOut(b),i.reset(),i.fadeIn(b),i.setLoop(m?E.LoopRepeat:E.LoopOnce,m?1/0:1),i.clampWhenFinished=!m,i.play(),m||i.getMixer().update(0),g.current=i,n&&!m&&T.current)){const x=i.getMixer(),d=v=>{if(v.action===i){x.removeEventListener("finished",d);const R=l[T.current];R&&(i.fadeOut(b),R.reset().fadeIn(b).play(),g.current=R)}};x.addEventListener("finished",d)}},[l,p]),h=e.useCallback(()=>{var a;(a=g.current)==null||a.fadeOut(.2),g.current=null},[]),o=e.useCallback(()=>p,[p]);return{playAnimation:S,stopAnimation:h,getAnimationNames:o,actions:l}}function z(s,t){const r=e.useRef(t||{}),l=e.useRef([]),p=e.useRef([]);e.useEffect(()=>{const h=new Set,o=[];s.traverse(a=>{a instanceof E.Mesh&&a.morphTargetDictionary&&a.morphTargetInfluences&&(o.push(a),Object.keys(a.morphTargetDictionary).forEach(c=>{h.add(c)}))}),l.current=Array.from(h).sort(),p.current=o},[s]),B.useFrame(()=>{const h=r.current;p.current.forEach(o=>{!o.morphTargetDictionary||!o.morphTargetInfluences||Object.entries(h).forEach(([a,c])=>{const m=o.morphTargetDictionary[a];m!==void 0&&(o.morphTargetInfluences[m]=c)})})}),e.useEffect(()=>{t&&(r.current={...t})},[t]);const g=e.useCallback((h,o)=>{r.current[h]=Math.max(0,Math.min(1,o))},[]),T=e.useCallback(()=>l.current,[]),S=e.useCallback(()=>({...r.current}),[]);return{setMorphTarget:g,getMorphTargetNames:T,getMorphTargetValues:S}}const re=e.createContext(null);function me(){const s=e.useContext(re);if(!s)throw new Error("BoneAttachment must be used within an AnimatedModel");return s}const q=e.forwardRef(({url:s,position:t=[0,0,0],rotation:r=[0,0,0],scale:l=1,defaultAnimation:p,morphTargets:g,meshVisibility:T,materialColors:S,materialTextures:h,onLoad:o,onError:a,children:c},m)=>{const b=e.useRef(null),n=e.useRef([]),i=e.useRef(o);i.current=o;const{scene:f,animations:x}=O.useGLTF(s),d=e.useMemo(()=>Q.clone(f),[f]),{playAnimation:v,stopAnimation:R,getAnimationNames:M}=te(x,d,{defaultAnimation:p}),{setMorphTarget:y}=z(d,g),{setMeshVisibility:D,getMeshNames:u}=G(d,T),{setMaterialColor:A,getMaterialNames:k,getMaterialColor:$}=K(d,S),{setMaterialTextures:C,clearMaterialTextures:j}=U(d,h);e.useEffect(()=>{if(!d)return;const I=setTimeout(()=>{var Z;const L=[],W=[],_=new Set,V=new Set;let Y=0;d.traverse(F=>{if(Y++,F.type==="Bone"&&L.push(F.name),F.isMesh){const N=F;W.push(N.name),N.castShadow=!0,N.receiveShadow=!0,(Array.isArray(N.material)?N.material:[N.material]).forEach(H=>{_.add(H.name),H.shadowSide=E.DoubleSide}),N.morphTargetDictionary&&Object.keys(N.morphTargetDictionary).forEach(H=>{V.add(H)})}}),n.current=Array.from(V).sort(),(Z=i.current)==null||Z.call(i,{meshes:W.sort(),materials:Array.from(_).sort(),bones:L.sort(),nodeCount:Y,animations:x.map(F=>F.name),morphTargetNames:n.current})},0);return()=>clearTimeout(I)},[d,x]),e.useImperativeHandle(m,()=>({playAnimation:v,stopAnimation:R,getAnimationNames:M,getGroup:()=>b.current,setMorphTarget:y,getMorphTargetNames:()=>n.current,setMeshVisibility:D,getMeshNames:u,setMaterialColor:A,getMaterialNames:k,getMaterialColor:$,setMaterialTextures:C,clearMaterialTextures:j}));const X=e.useMemo(()=>({scene:d,getBone:I=>d.getObjectByName(I)||null}),[d]),P=typeof l=="number"?[l,l,l]:l;return w.jsx(re.Provider,{value:X,children:w.jsxs("group",{ref:b,position:t,rotation:r,scale:P,children:[w.jsx("primitive",{object:d}),c]})})});q.displayName="AnimatedModel";q.preload=s=>{O.useGLTF.preload(s)};const se=e.forwardRef(({url:s,position:t=[0,0,0],rotation:r=[0,0,0],scale:l=1,morphTargets:p,meshVisibility:g,materialColors:T,materialTextures:S,onMorphTargetsFound:h,onLoad:o,onError:a},c)=>{const{scene:m}=O.useGLTF(s),b=e.useRef(o);b.current=o;const n=e.useRef(h);n.current=h;const i=e.useMemo(()=>m.clone(),[m]),{setMorphTarget:f,getMorphTargetNames:x,getMorphTargetValues:d}=z(i,p),{setMeshVisibility:v,getMeshNames:R}=G(i,g),{setMaterialColor:M,getMaterialNames:y,getMaterialColor:D}=K(i,T),{setMaterialTextures:u,clearMaterialTextures:A}=U(i,S);e.useEffect(()=>{var C;const $=x();$.length>0&&((C=n.current)==null||C.call(n,$))},[i,x]),e.useEffect(()=>{var P;if(!i)return;const $=[],C=new Set,j=[];let X=0;i.traverse(I=>{if(X++,I.type==="Bone"&&j.push(I.name),I.isMesh){const L=I;$.push(L.name),L.castShadow=!0,L.receiveShadow=!0,(Array.isArray(L.material)?L.material:[L.material]).forEach(_=>C.add(_.name))}}),(P=b.current)==null||P.call(b,{meshes:$.sort(),materials:Array.from(C).sort(),bones:j.sort(),nodeCount:X})},[i]),e.useImperativeHandle(c,()=>({setMorphTarget:f,getMorphTargetNames:x,getMorphTargetValues:d,setMeshVisibility:v,getMeshNames:R,setMaterialColor:M,getMaterialNames:y,getMaterialColor:D,setMaterialTextures:u,clearMaterialTextures:A}));const k=typeof l=="number"?[l,l,l]:l;return w.jsx("group",{position:t,rotation:r,scale:k,children:w.jsx("primitive",{object:i})})});se.displayName="MorphableModel";function fe({children:s,bone:t,position:r=[0,0,0],rotation:l=[0,0,0],scale:p=1}){const{getBone:g}=me(),[T,S]=e.useState(null);if(e.useEffect(()=>{const o=g(t);o?S(o):console.warn(`Bone "${t}" not found in model`)},[t,g]),!T)return null;const h=typeof p=="number"?[p,p,p]:p;return B.createPortal(w.jsx("group",{position:r,rotation:l,scale:h,children:s}),T)}function de(s,t){const{scene:r,animations:l}=O.useGLTF(s),p=e.useMemo(()=>Q.clone(r),[r]);return e.useEffect(()=>{var o;if(!p)return;const g=[],T=[],S=new Set;let h=0;p.traverse(a=>{if(h++,a.type==="Bone"&&g.push(a.name),a.isMesh){const c=a;T.push(c.name),c.castShadow=!0,c.receiveShadow=!0,(Array.isArray(c.material)?c.material:[c.material]).forEach(b=>{S.add(b.name),b.shadowSide=E.DoubleSide})}}),(o=t==null?void 0:t.onLoad)==null||o.call(t,{meshes:T.sort(),materials:Array.from(S).sort(),bones:g.sort(),nodeCount:h})},[p,t]),{scene:p,animations:l}}function Me(s){O.useGLTF.preload(s)}exports.AnimatedModel=q;exports.BoneAttachment=fe;exports.Model=ee;exports.MorphableModel=se;exports.Scene3D=pe;exports.preloadModel=Me;exports.useAnimationController=te;exports.useClonedModel=de;exports.useMaterialColor=K;exports.useMaterialTexture=U;exports.useMeshVisibility=G;exports.useMorphTargets=z;
|
|
2
2
|
//# sourceMappingURL=mbt-3d.cjs.map
|