1
1
// Script to ensure the 3D model loader is initialized correctly
2
- // Enhanced with support for custom avatar URLs and separate animation files
2
+ // Enhanced with support for GLB and FBX models with separate animation files
3
3
4
4
let pandaModelLocation = 'assets/pandaFBX/panda.fbx' ;
5
- //let pandaModelLocation = 'assets/levelsFBX/levels.fbx';
6
5
let animationFiles = {
7
6
'idle' : 'assets/pandaFBX/lookBehind.fbx' ,
8
7
'jump' : 'assets/pandaFBX/jump.fbx' ,
@@ -15,19 +14,25 @@ let animationFiles = {
15
14
'walkingBackward' : 'assets/pandaFBX/walkingBackward.fbx' ,
16
15
} ;
17
16
let pandaModelScale = 2.4 ;
17
+ let glbModelScale = 2.0 ; // Default scale for GLB models
18
18
19
19
// Function to parse URL parameters
20
20
function getUrlParameters ( ) {
21
21
const params = new URLSearchParams ( window . location . search ) ;
22
- console . log ( "Url params: " + params ) ;
22
+ console . log ( "Url params: " + params ) ;
23
23
return {
24
24
avatarUrl : params . get ( 'avatar_url' ) ,
25
25
username : params . get ( 'username' ) ,
26
26
portal : params . get ( 'portal' ) ,
27
27
} ;
28
28
}
29
29
30
- // Function to create the red panda player with FBX support and animations
30
+ // Function to determine if a URL is a GLB file
31
+ function isGlbFile ( url ) {
32
+ return url && url . toLowerCase ( ) . endsWith ( '.glb' ) ;
33
+ }
34
+
35
+ // Function to create the player with support for both GLB and FBX models
31
36
function createRedPandaPlayer ( ) {
32
37
const playerGroup = new THREE . Group ( ) ;
33
38
@@ -36,20 +41,7 @@ function createRedPandaPlayer() {
36
41
return playerGroup ;
37
42
}
38
43
39
- // Use FBXLoader instead of GLTFLoader
40
- const loader = THREE . FBXLoader ? new THREE . FBXLoader ( ) : null ;
41
-
42
- if ( ! loader ) {
43
- console . error ( 'FBXLoader not available, using fallback panda' ) ;
44
- const fallbackPanda = createBlockPanda ( ) ;
45
- playerGroup . add ( fallbackPanda ) ;
46
- if ( window . setPandaModel ) {
47
- window . setPandaModel ( fallbackPanda , [ ] ) ;
48
- }
49
- return playerGroup ;
50
- }
51
-
52
- // Placeholder remains the same
44
+ // Create placeholder while loading
53
45
const placeholderGeometry = new THREE . BoxGeometry ( 0.5 , 0.5 , 0.5 ) ;
54
46
const placeholderMaterial = new THREE . MeshStandardMaterial ( {
55
47
color : 0xff9966 ,
@@ -61,7 +53,92 @@ function createRedPandaPlayer() {
61
53
playerGroup . add ( placeholder ) ;
62
54
63
55
const params = getUrlParameters ( ) ;
64
- const modelUrl = params . avatarUrl || pandaModelLocation ;
56
+ const avatarUrl = params . avatarUrl ;
57
+
58
+ // Determine which loader to use based on avatar URL
59
+ if ( avatarUrl && isGlbFile ( avatarUrl ) ) {
60
+ // Use GLTFLoader for GLB files
61
+ loadGlbModel ( avatarUrl , playerGroup , placeholder ) ;
62
+ } else {
63
+ // Use FBXLoader for FBX files (or fallback)
64
+ loadFbxModel ( avatarUrl || pandaModelLocation , playerGroup , placeholder ) ;
65
+ }
66
+
67
+ return playerGroup ;
68
+ }
69
+
70
+ // Function to load GLB model using GLTFLoader
71
+ function loadGlbModel ( modelUrl , playerGroup , placeholder ) {
72
+ // Check if GLTFLoader is available
73
+ if ( ! THREE . GLTFLoader ) {
74
+ console . error ( 'GLTFLoader not available, falling back to FBX' ) ;
75
+ loadFbxModel ( pandaModelLocation , playerGroup , placeholder ) ;
76
+ return ;
77
+ }
78
+
79
+ const loader = new THREE . GLTFLoader ( ) ;
80
+ console . log ( `Loading GLB model: ${ modelUrl } ` ) ;
81
+
82
+ loader . load (
83
+ modelUrl ,
84
+ ( gltf ) => {
85
+ console . log ( 'GLB model loaded successfully:' , modelUrl ) ;
86
+
87
+ const model = gltf . scene ;
88
+ let animations = gltf . animations || [ ] ;
89
+
90
+ // Apply scale to the model
91
+ model . scale . set ( glbModelScale , glbModelScale , glbModelScale ) ;
92
+
93
+ // Center the model
94
+ const box = new THREE . Box3 ( ) . setFromObject ( model ) ;
95
+ const center = box . getCenter ( new THREE . Vector3 ( ) ) ;
96
+ model . position . sub ( center ) ;
97
+ const size = box . getSize ( new THREE . Vector3 ( ) ) ;
98
+ model . position . y += size . y / 2 ;
99
+
100
+ // Apply shadows
101
+ model . traverse ( ( node ) => {
102
+ if ( node . isMesh ) {
103
+ node . castShadow = true ;
104
+ node . receiveShadow = true ;
105
+ }
106
+ } ) ;
107
+
108
+ playerGroup . add ( model ) ;
109
+ playerGroup . remove ( placeholder ) ;
110
+
111
+ // Set the model in the game with its animations
112
+ if ( window . setPandaModel ) {
113
+ window . setPandaModel ( model , animations ) ;
114
+ }
115
+ } ,
116
+ ( xhr ) => {
117
+ console . log ( `Loading GLB model: ${ ( xhr . loaded / xhr . total * 100 ) } % loaded` ) ;
118
+ } ,
119
+ ( error ) => {
120
+ console . error ( 'Error loading GLB model:' , error ) ;
121
+ console . log ( 'GLB model failed, falling back to FBX model' ) ;
122
+ loadFbxModel ( pandaModelLocation , playerGroup , placeholder ) ;
123
+ }
124
+ ) ;
125
+ }
126
+
127
+ // Function to load FBX model using FBXLoader
128
+ function loadFbxModel ( modelUrl , playerGroup , placeholder ) {
129
+ // Check if FBXLoader is available
130
+ if ( ! THREE . FBXLoader ) {
131
+ console . error ( 'FBXLoader not available, using fallback panda' ) ;
132
+ const fallbackPanda = createBlockPanda ( ) ;
133
+ playerGroup . add ( fallbackPanda ) ;
134
+ playerGroup . remove ( placeholder ) ;
135
+ if ( window . setPandaModel ) {
136
+ window . setPandaModel ( fallbackPanda , [ ] ) ;
137
+ }
138
+ return ;
139
+ }
140
+
141
+ const loader = new THREE . FBXLoader ( ) ;
65
142
console . log ( `Loading FBX model: ${ modelUrl } ` ) ;
66
143
67
144
// Load main character model
@@ -73,9 +150,9 @@ function createRedPandaPlayer() {
73
150
const model = fbx ;
74
151
let animations = fbx . animations || [ ] ;
75
152
76
- // Scale adjustment remains similar
77
-
78
- let modelScale = params . avatarUrl ? 1.5 : pandaModelScale ; // Adjust as needed for your FBX
153
+ // Scale adjustment
154
+ const isCustomModel = modelUrl !== pandaModelLocation ;
155
+ let modelScale = isCustomModel ? 1.5 : pandaModelScale ;
79
156
model . scale . set ( modelScale , modelScale , modelScale ) ;
80
157
81
158
// Center the model
@@ -103,50 +180,17 @@ function createRedPandaPlayer() {
103
180
} ) ;
104
181
} ,
105
182
( xhr ) => {
106
- console . log ( `Loading model: ${ ( xhr . loaded / xhr . total * 100 ) } % loaded` ) ;
183
+ console . log ( `Loading FBX model: ${ ( xhr . loaded / xhr . total * 100 ) } % loaded` ) ;
107
184
} ,
108
185
( error ) => {
109
186
console . error ( 'Error loading FBX model:' , error ) ;
110
- // Fallback logic
111
- if ( params . avatarUrl ) {
112
- console . log ( 'Custom model failed, trying default...' ) ;
113
- loader . load (
114
- pandaModelLocation ,
115
- ( fbx ) => {
116
- const model = fbx ;
117
- model . scale . set ( pandaModelScale , pandaModelScale , pandaModelScale ) ;
118
- const box = new THREE . Box3 ( ) . setFromObject ( model ) ;
119
- const center = box . getCenter ( new THREE . Vector3 ( ) ) ;
120
- model . position . sub ( center ) ;
121
- const size = box . getSize ( new THREE . Vector3 ( ) ) ;
122
- model . position . y += size . y / 2 ;
123
- model . traverse ( ( node ) => {
124
- if ( node . isMesh ) {
125
- node . castShadow = true ;
126
- node . receiveShadow = true ;
127
- }
128
- } ) ;
129
- playerGroup . add ( model ) ;
130
- playerGroup . remove ( placeholder ) ;
131
-
132
- // Load animations for default model
133
- loadAnimations ( model , fbx . animations || [ ] , ( combinedAnimations ) => {
134
- if ( window . setPandaModel ) {
135
- window . setPandaModel ( model , combinedAnimations ) ;
136
- }
137
- } ) ;
138
- } ,
139
- null ,
140
- ( secondError ) => {
141
- console . error ( 'Default FBX failed:' , secondError ) ;
142
- fallbackToBlockPanda ( ) ;
143
- }
144
- ) ;
145
- } else {
146
- fallbackToBlockPanda ( ) ;
147
- }
148
187
149
- function fallbackToBlockPanda ( ) {
188
+ // If the custom model failed, try the default
189
+ if ( modelUrl !== pandaModelLocation ) {
190
+ console . log ( 'Custom FBX model failed, trying default panda...' ) ;
191
+ loadFbxModel ( pandaModelLocation , playerGroup , placeholder ) ;
192
+ } else {
193
+ // If even the default model fails, use block panda
150
194
console . log ( 'Falling back to block-based panda' ) ;
151
195
const fallbackPanda = createBlockPanda ( ) ;
152
196
playerGroup . add ( fallbackPanda ) ;
@@ -157,8 +201,6 @@ function createRedPandaPlayer() {
157
201
}
158
202
}
159
203
) ;
160
-
161
- return playerGroup ;
162
204
}
163
205
164
206
// Function to load animation files and combine them with the model
@@ -251,4 +293,5 @@ function createBlockPanda() {
251
293
return pandaGroup ;
252
294
}
253
295
296
+ // Execute on script load
254
297
let urlParamsReceived = getUrlParameters ( ) ;
0 commit comments