ginipick commited on
Commit
3aff1e6
ยท
verified ยท
1 Parent(s): 30b09aa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -210
app.py CHANGED
@@ -4,8 +4,6 @@ import glob
4
  import json
5
  import numpy as np
6
  import trimesh
7
- import argparse
8
- from scipy.spatial.transform import Rotation
9
  from PIL import Image, ImageDraw
10
  import math
11
  import trimesh.transformations as tf
@@ -19,101 +17,37 @@ import spaces
19
  LOG_PATH = './results/demo'
20
  os.makedirs(LOG_PATH, exist_ok=True)
21
 
22
- def create_simple_rotation_animation(input_glb_path, output_glb_path, num_frames=30):
23
- """
24
- ์›๋ณธ GLB ํŒŒ์ผ์— ํšŒ์ „ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•œ ์ƒˆ๋กœ์šด GLB ํŒŒ์ผ ์ƒ์„ฑ
25
- """
26
- try:
27
- # GLB ํŒŒ์ผ ๋กœ๋“œ
28
- scene = trimesh.load(input_glb_path)
29
-
30
- if isinstance(scene, trimesh.Scene):
31
- # ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ (์ฒซ ๋ฒˆ์งธ ํ”„๋ ˆ์ž„๋งŒ ์‚ฌ์šฉ)
32
- angle = math.pi / 4 # 45๋„ ํšŒ์ „
33
-
34
- # ์”ฌ์˜ ๋ชจ๋“  ๋ฉ”์‹œ์— ํšŒ์ „ ์ ์šฉ
35
- for node_name, transform, geometry_name in scene.graph.nodes_geometry:
36
- # ์›๋ณธ ์œ„์น˜ ๋ฐฑ์—…
37
- original_transform = scene.graph[node_name][0]
38
-
39
- # ํšŒ์ „ ๋ณ€ํ™˜ ๊ณ„์‚ฐ
40
- rotation = tf.rotation_matrix(angle, [0, 1, 0])
41
-
42
- # ์ƒˆ ๋ณ€ํ™˜ = ์›๋ณธ ๋ณ€ํ™˜ * ํšŒ์ „ ๋ณ€ํ™˜
43
- new_transform = np.dot(original_transform, rotation)
44
-
45
- # ๋ณ€ํ™˜ ์ ์šฉ
46
- scene.graph[node_name] = new_transform
47
-
48
- # ํšŒ์ „๋œ GLB ์ €์žฅ
49
- scene.export(output_glb_path)
50
- print(f"Saved animated GLB to {output_glb_path}")
51
- return output_glb_path
52
-
53
- elif isinstance(scene, trimesh.Trimesh):
54
- # ๋‹จ์ผ ๋ฉ”์‹œ์ธ ๊ฒฝ์šฐ
55
- new_scene = trimesh.Scene()
56
-
57
- # ๋ฉ”์‹œ์— ํšŒ์ „ ์ ์šฉ
58
- angle = math.pi / 4 # 45๋„ ํšŒ์ „
59
- rotation = tf.rotation_matrix(angle, [0, 1, 0])
60
- scene.apply_transform(rotation)
61
-
62
- # ํšŒ์ „๋œ ๋ฉ”์‹œ๋ฅผ ์”ฌ์— ์ถ”๊ฐ€
63
- new_scene.add_geometry(scene)
64
-
65
- # ์”ฌ์„ GLB๋กœ ์ €์žฅ
66
- new_scene.export(output_glb_path)
67
- print(f"Saved animated GLB to {output_glb_path}")
68
- return output_glb_path
69
-
70
- else:
71
- print(f"Unsupported format: {type(scene)}")
72
- return None
73
-
74
- except Exception as e:
75
- print(f"Error creating animation: {str(e)}")
76
- return None
77
-
78
  def create_textual_animation_gif(output_path, model_name, animation_type, duration=3.0, fps=30):
79
- """ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์˜ ๊ฐ„๋‹จํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ GIF ์ƒ์„ฑ - ๋ Œ๋”๋ง ์‹คํŒจ ์‹œ ๋Œ€์ฒด์šฉ"""
80
  try:
81
- # ๊ฐ„๋‹จํ•œ ํ”„๋ ˆ์ž„ ์‹œํ€€์Šค ์ƒ์„ฑ
82
  frames = []
83
  num_frames = int(duration * fps)
84
- if num_frames > 60: # ๋„ˆ๋ฌด ๋งŽ์€ ํ”„๋ ˆ์ž„์€ ํšจ์œจ์ ์ด์ง€ ์•Š์Œ
85
  num_frames = 60
86
 
87
  for i in range(num_frames):
88
- t = i / (num_frames - 1) # 0~1 ๋ฒ”์œ„
89
- angle = t * 360 # ์ „์ฒด ํšŒ์ „
90
 
91
- # ์ƒˆ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
92
  img = Image.new('RGB', (640, 480), color=(240, 240, 240))
93
  draw = ImageDraw.Draw(img)
94
 
95
- # ์ •๋ณด ํ…์ŠคํŠธ
96
  draw.text((50, 50), f"Model: {os.path.basename(model_name)}", fill=(0, 0, 0))
97
  draw.text((50, 100), f"Animation Type: {animation_type}", fill=(0, 0, 0))
98
  draw.text((50, 150), f"Frame: {i+1}/{num_frames}", fill=(0, 0, 0))
99
 
100
- # ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ ํ˜•์— ๋”ฐ๋ฅธ ์‹œ๊ฐ์  ํšจ๊ณผ
101
  center_x, center_y = 320, 240
102
  if animation_type == 'rotate':
103
- # ํšŒ์ „ํ•˜๋Š” ์‚ฌ๊ฐํ˜•
104
  radius = 100
105
  x = center_x + radius * math.cos(math.radians(angle))
106
  y = center_y + radius * math.sin(math.radians(angle))
107
  draw.rectangle((x-40, y-40, x+40, y+40), outline=(0, 0, 0), fill=(255, 0, 0))
108
-
109
  elif animation_type == 'float':
110
- # ์œ„์•„๋ž˜๋กœ ์›€์ง์ด๋Š” ์›
111
  offset_y = 50 * math.sin(2 * math.pi * t)
112
  draw.ellipse((center_x-50, center_y-50+offset_y, center_x+50, center_y+50+offset_y),
113
- outline=(0, 0, 0), fill=(0, 0, 255))
114
-
115
- elif animation_type == 'explode' or animation_type == 'assemble':
116
- # ๋ฐ”๊นฅ์ชฝ/์•ˆ์ชฝ์œผ๋กœ ์›€์ง์ด๋Š” ์—ฌ๋Ÿฌ ๋„ํ˜•
117
  scale = t if animation_type == 'explode' else 1 - t
118
  for j in range(8):
119
  angle_j = j * 45
@@ -127,16 +61,12 @@ def create_textual_animation_gif(output_path, model_name, animation_type, durati
127
  draw.ellipse((x-20, y-20, x+20, y+20), outline=(0, 0, 0), fill=(0, 255, 0))
128
  else:
129
  draw.polygon([(x, y-20), (x+20, y+20), (x-20, y+20)], outline=(0, 0, 0), fill=(0, 0, 255))
130
-
131
  elif animation_type == 'pulse':
132
- # ํฌ๊ธฐ๊ฐ€ ๋ณ€ํ•˜๋Š” ์›
133
  scale = 0.5 + 0.5 * math.sin(2 * math.pi * t)
134
  radius = 100 * scale
135
  draw.ellipse((center_x-radius, center_y-radius, center_x+radius, center_y+radius),
136
  outline=(0, 0, 0), fill=(0, 255, 0))
137
-
138
  elif animation_type == 'swing':
139
- # ์ขŒ์šฐ๋กœ ์›€์ง์ด๋Š” ์‚ผ๊ฐํ˜•
140
  angle_offset = 30 * math.sin(2 * math.pi * t)
141
  points = [
142
  (center_x + 100 * math.cos(math.radians(angle_offset)), center_y - 80),
@@ -145,10 +75,8 @@ def create_textual_animation_gif(output_path, model_name, animation_type, durati
145
  ]
146
  draw.polygon(points, outline=(0, 0, 0), fill=(255, 165, 0))
147
 
148
- # ํ”„๋ ˆ์ž„ ์ถ”๊ฐ€
149
  frames.append(img)
150
 
151
- # GIF๋กœ ์ €์žฅ
152
  frames[0].save(
153
  output_path,
154
  save_all=True,
@@ -163,136 +91,66 @@ def create_textual_animation_gif(output_path, model_name, animation_type, durati
163
  print(f"Error creating textual animation: {str(e)}")
164
  return None
165
 
166
- def create_glb_with_animation(input_glb_path, animation_type, duration=3.0, fps=30):
167
- """
168
- ์—…๋กœ๋“œ๋œ GLB ํŒŒ์ผ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•œ ์ƒˆ๋กœ์šด GLB ํŒŒ์ผ ์ƒ์„ฑ
169
- """
170
  try:
171
- base_filename = os.path.basename(input_glb_path).rsplit('.', 1)[0]
172
- output_glb_path = os.path.join(LOG_PATH, f"animated_{base_filename}.glb")
173
 
174
- # ์›๋ณธ ๋ชจ๋ธ ๋กœ๋“œ
175
  scene = trimesh.load(input_glb_path)
176
- print(f"Loaded GLB: {type(scene)}")
 
 
 
 
177
 
178
- # ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ ํ˜•์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌ
179
  if animation_type == 'rotate':
180
- # ์‹œ๊ณ„๋ฐฉํ–ฅ 45๋„ ํšŒ์ „
181
- angle = math.pi / 4
182
- axis = [0, 1, 0] # Y์ถ• (์ˆ˜์ง์ถ•)
183
  elif animation_type == 'float':
184
- # ์ˆ˜์ง์œผ๋กœ ์›€์ง์ž„
185
- angle = 0
186
- axis = [0, 1, 0]
187
- # Y์ถ• ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™
188
- if isinstance(scene, trimesh.Scene):
189
- for node_name, transform, geometry_name in scene.graph.nodes_geometry:
190
- # ๊ฐ€๋ณ๊ฒŒ ์œ„๋กœ ์ด๋™
191
- translation = tf.translation_matrix([0, 0.2, 0])
192
- original_transform = scene.graph[node_name][0]
193
- new_transform = np.dot(original_transform, translation)
194
- scene.graph[node_name] = new_transform
195
- elif isinstance(scene, trimesh.Trimesh):
196
- translation = tf.translation_matrix([0, 0.2, 0])
197
- scene.apply_transform(translation)
198
- elif animation_type == 'explode':
199
- # ๊ฐ ๋ถ€๋ถ„์˜ ์ค‘์‹ฌ์—์„œ ์•ฝ๊ฐ„ ๋ฉ€์–ด์ง€๊ฒŒ
200
- angle = 0
201
- axis = [0, 1, 0]
202
- # ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๊ฒฝ์šฐ ์ค‘์‹ฌ์—์„œ ๋ฐ”๊นฅ์ชฝ์œผ๋กœ ์ด๋™
203
- if isinstance(scene, trimesh.Scene):
204
- # ์”ฌ์˜ ์ค‘์‹ฌ์  ๊ณ„์‚ฐ
205
- all_vertices = []
206
- for geometry_name, geometry in scene.geometry.items():
207
- if hasattr(geometry, 'vertices') and len(geometry.vertices) > 0:
208
- all_vertices.append(geometry.vertices)
209
-
210
- if all_vertices:
211
- all_points = np.vstack(all_vertices)
212
- center = np.mean(all_points, axis=0)
213
-
214
- for node_name, transform, geometry_name in scene.graph.nodes_geometry:
215
- # ๊ฐ ๋ถ€๋ถ„์˜ ์ค‘์‹ฌ์  ๊ณ„์‚ฐ
216
- geometry = scene.geometry[geometry_name]
217
- if hasattr(geometry, 'centroid'):
218
- part_center = geometry.centroid
219
- # ์ค‘์‹ฌ์—์„œ ๊ฐ์ฒด ๋ฐฉํ–ฅ ๊ณ„์‚ฐ
220
- direction = part_center - center
221
- if np.linalg.norm(direction) > 0.001:
222
- direction = direction / np.linalg.norm(direction)
223
- # ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™
224
- translation = tf.translation_matrix(direction * 0.2)
225
- original_transform = scene.graph[node_name][0]
226
- new_transform = np.dot(original_transform, translation)
227
- scene.graph[node_name] = new_transform
228
  elif animation_type == 'pulse':
229
- # ๋ชจ๋ธ์„ ์•ฝ๊ฐ„ ํ‚ค์›€
230
- scale_factor = 1.2
231
-
232
- if isinstance(scene, trimesh.Scene):
233
- # ์”ฌ์˜ ์ค‘์‹ฌ์  ๊ณ„์‚ฐ
234
- all_vertices = []
235
- for geometry_name, geometry in scene.geometry.items():
236
- if hasattr(geometry, 'vertices') and len(geometry.vertices) > 0:
237
- all_vertices.append(geometry.vertices)
238
-
239
- if all_vertices:
240
- all_points = np.vstack(all_vertices)
241
- center = np.mean(all_points, axis=0)
242
-
243
- for node_name, transform, geometry_name in scene.graph.nodes_geometry:
244
- # ์ค‘์‹ฌ ๊ธฐ์ค€ ์Šค์ผ€์ผ๋ง
245
- translate_to_center = tf.translation_matrix(-center)
246
- scale = np.eye(4)
247
- scale[:3, :3] *= scale_factor
248
- translate_back = tf.translation_matrix(center)
249
-
250
- # ๋ณ€ํ™˜ ์ ์šฉ
251
- original_transform = scene.graph[node_name][0]
252
- new_transform = np.dot(translate_back, np.dot(scale, np.dot(translate_to_center, original_transform)))
253
- scene.graph[node_name] = new_transform
254
- elif isinstance(scene, trimesh.Trimesh):
255
- # ๋ฉ”์‹œ ์ค‘์‹ฌ ๊ธฐ์ค€ ์Šค์ผ€์ผ๋ง
256
- center = scene.centroid
257
- translate_to_center = tf.translation_matrix(-center)
258
- scale = tf.scale_matrix(scale_factor)
259
- translate_back = tf.translation_matrix(center)
260
- scene.apply_transform(np.dot(translate_back, np.dot(scale, translate_to_center)))
261
- else:
262
- # ๊ธฐ๋ณธ์ ์œผ๋กœ ํšŒ์ „ ์ ์šฉ
263
- angle = math.pi / 4
264
- axis = [0, 1, 0]
265
 
266
- # ํšŒ์ „ ์ ์šฉ (float, explode, pulse ์•„๋‹Œ ๊ฒฝ์šฐ)
267
- if angle != 0:
268
- if isinstance(scene, trimesh.Scene):
269
- # ์”ฌ์˜ ๋ชจ๋“  ๋ถ€๋ถ„์— ํšŒ์ „ ์ ์šฉ
270
- for node_name, transform, geometry_name in scene.graph.nodes_geometry:
271
- rotation = tf.rotation_matrix(angle, axis)
272
- original_transform = scene.graph[node_name][0]
273
- new_transform = np.dot(original_transform, rotation)
274
- scene.graph[node_name] = new_transform
275
- elif isinstance(scene, trimesh.Trimesh):
276
- # ๋‹จ์ผ ๋ฉ”์‹œ์— ํšŒ์ „ ์ ์šฉ
277
- rotation = tf.rotation_matrix(angle, axis)
278
- scene.apply_transform(rotation)
279
 
280
- # ๊ฒฐ๊ณผ ์ €์žฅ
281
  scene.export(output_glb_path)
282
- print(f"Saved animated GLB to {output_glb_path}")
 
283
  return output_glb_path
 
284
  except Exception as e:
285
- print(f"Error creating animated GLB: {str(e)}")
 
286
  # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์›๋ณธ ํŒŒ์ผ ๋ณต์‚ฌ
287
  try:
288
  import shutil
289
- output_path = os.path.join(LOG_PATH, f"copy_{os.path.basename(input_glb_path)}")
290
- shutil.copy(input_glb_path, output_path)
291
- print(f"Copied original GLB to {output_path}")
292
- return output_path
293
  except Exception as copy_error:
294
  print(f"Error copying GLB: {copy_error}")
295
- return input_glb_path # ์›๋ณธ ๊ฒฝ๋กœ ๋ฐ˜ํ™˜
296
 
297
  @spaces.GPU
298
  def process_3d_model(input_3d, animation_type, animation_duration, fps):
@@ -300,19 +158,20 @@ def process_3d_model(input_3d, animation_type, animation_duration, fps):
300
  print(f"Processing: {input_3d} with animation type: {animation_type}")
301
 
302
  try:
303
- # 1. ์—…๋กœ๋“œ๋œ GLB ํŒŒ์ผ์— ์‹ค์ œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ
304
- animated_glb_path = create_glb_with_animation(
305
- input_3d,
306
- animation_type,
307
- animation_duration,
308
- fps
309
- )
310
-
311
- # 2. ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ GIF ์ƒ์„ฑ (๋ฐฑ์—…์šฉ)
312
  base_filename = os.path.basename(input_3d).rsplit('.', 1)[0]
313
- text_gif_path = os.path.join(LOG_PATH, f'text_animated_{base_filename}.gif')
314
- animated_gif_path = create_textual_animation_gif(
315
- text_gif_path,
 
 
 
 
 
 
 
 
 
316
  os.path.basename(input_3d),
317
  animation_type,
318
  animation_duration,
@@ -320,6 +179,7 @@ def process_3d_model(input_3d, animation_type, animation_duration, fps):
320
  )
321
 
322
  # 3. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ƒ์„ฑ
 
323
  metadata = {
324
  "animation_type": animation_type,
325
  "duration": animation_duration,
@@ -328,15 +188,28 @@ def process_3d_model(input_3d, animation_type, animation_duration, fps):
328
  "created_at": time.strftime("%Y-%m-%d %H:%M:%S")
329
  }
330
 
331
- json_path = os.path.join(LOG_PATH, f'metadata_{base_filename}.json')
332
  with open(json_path, 'w') as f:
333
  json.dump(metadata, f, indent=4)
334
-
335
- return animated_glb_path, animated_gif_path, json_path
 
 
336
  except Exception as e:
337
- error_msg = f"Error processing file: {str(e)}"
338
- print(error_msg)
339
- return error_msg, None, None
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค ์„ค์ •
342
  with gr.Blocks(title="GLB ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒ์„ฑ๊ธฐ") as demo:
 
4
  import json
5
  import numpy as np
6
  import trimesh
 
 
7
  from PIL import Image, ImageDraw
8
  import math
9
  import trimesh.transformations as tf
 
17
  LOG_PATH = './results/demo'
18
  os.makedirs(LOG_PATH, exist_ok=True)
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  def create_textual_animation_gif(output_path, model_name, animation_type, duration=3.0, fps=30):
21
+ """ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์˜ ๊ฐ„๋‹จํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ GIF ์ƒ์„ฑ"""
22
  try:
 
23
  frames = []
24
  num_frames = int(duration * fps)
25
+ if num_frames > 60:
26
  num_frames = 60
27
 
28
  for i in range(num_frames):
29
+ t = i / (num_frames - 1)
30
+ angle = t * 360
31
 
 
32
  img = Image.new('RGB', (640, 480), color=(240, 240, 240))
33
  draw = ImageDraw.Draw(img)
34
 
 
35
  draw.text((50, 50), f"Model: {os.path.basename(model_name)}", fill=(0, 0, 0))
36
  draw.text((50, 100), f"Animation Type: {animation_type}", fill=(0, 0, 0))
37
  draw.text((50, 150), f"Frame: {i+1}/{num_frames}", fill=(0, 0, 0))
38
 
39
+ # ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ ํ˜•๋ณ„ ์‹œ๊ฐํ™”
40
  center_x, center_y = 320, 240
41
  if animation_type == 'rotate':
 
42
  radius = 100
43
  x = center_x + radius * math.cos(math.radians(angle))
44
  y = center_y + radius * math.sin(math.radians(angle))
45
  draw.rectangle((x-40, y-40, x+40, y+40), outline=(0, 0, 0), fill=(255, 0, 0))
 
46
  elif animation_type == 'float':
 
47
  offset_y = 50 * math.sin(2 * math.pi * t)
48
  draw.ellipse((center_x-50, center_y-50+offset_y, center_x+50, center_y+50+offset_y),
49
+ outline=(0, 0, 0), fill=(0, 0, 255))
50
+ elif animation_type in ['explode', 'assemble']:
 
 
51
  scale = t if animation_type == 'explode' else 1 - t
52
  for j in range(8):
53
  angle_j = j * 45
 
61
  draw.ellipse((x-20, y-20, x+20, y+20), outline=(0, 0, 0), fill=(0, 255, 0))
62
  else:
63
  draw.polygon([(x, y-20), (x+20, y+20), (x-20, y+20)], outline=(0, 0, 0), fill=(0, 0, 255))
 
64
  elif animation_type == 'pulse':
 
65
  scale = 0.5 + 0.5 * math.sin(2 * math.pi * t)
66
  radius = 100 * scale
67
  draw.ellipse((center_x-radius, center_y-radius, center_x+radius, center_y+radius),
68
  outline=(0, 0, 0), fill=(0, 255, 0))
 
69
  elif animation_type == 'swing':
 
70
  angle_offset = 30 * math.sin(2 * math.pi * t)
71
  points = [
72
  (center_x + 100 * math.cos(math.radians(angle_offset)), center_y - 80),
 
75
  ]
76
  draw.polygon(points, outline=(0, 0, 0), fill=(255, 165, 0))
77
 
 
78
  frames.append(img)
79
 
 
80
  frames[0].save(
81
  output_path,
82
  save_all=True,
 
91
  print(f"Error creating textual animation: {str(e)}")
92
  return None
93
 
94
+ def modify_glb_file(input_glb_path, output_glb_path, animation_type='rotate'):
95
+ """์—…๋กœ๋“œ๋œ GLB ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ฃผ๋Š” ํ•จ์ˆ˜"""
 
 
96
  try:
97
+ # ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•: ์›๋ณธ ํŒŒ์ผ์„ ๊ทธ๋Œ€๋กœ ๋กœ๋“œํ•˜์—ฌ ๋‹จ์ผ ๋ณ€ํ™˜ ์ ์šฉ ํ›„ ์ €์žฅ
98
+ # ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ๋‚˜๋ˆ„์–ด ์ฒ˜๋ฆฌํ•˜์—ฌ ๊ฐ ๋‹จ๊ณ„์—์„œ ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ
99
 
100
+ print(f"Step 1: Loading GLB file '{input_glb_path}'")
101
  scene = trimesh.load(input_glb_path)
102
+ print(f"Loaded GLB file, type: {type(scene)}")
103
+
104
+ print(f"Step 2: Preparing transformation for animation type: {animation_type}")
105
+ # ๋‹จ์ˆœํ™”๋œ ๋ณ€ํ™˜ ์ค€๋น„ - ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ ํ˜•๋ณ„๋กœ ๋‹ค๋ฅธ ๋ณ€ํ™˜ ์ ์šฉ
106
+ transform = np.eye(4) # ๊ธฐ๋ณธ ํ•ญ๋“ฑ ๋ณ€ํ™˜ (์•„๋ฌด ๋ณ€ํ™” ์—†์Œ)
107
 
 
108
  if animation_type == 'rotate':
109
+ # Y์ถ• ๊ธฐ์ค€ 45๋„ ํšŒ์ „
110
+ transform = tf.rotation_matrix(math.pi/4, [0, 1, 0])
 
111
  elif animation_type == 'float':
112
+ # ์œ„๋กœ ์ด๋™
113
+ transform = tf.translation_matrix([0, 0.5, 0])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  elif animation_type == 'pulse':
115
+ # ํฌ๊ธฐ ํ™•๋Œ€
116
+ transform = tf.scale_matrix(1.2)
117
+ elif animation_type == 'explode':
118
+ # X์ถ• ๋ฐฉํ–ฅ์œผ๋กœ ์•ฝ๊ฐ„ ์ด๋™
119
+ transform = tf.translation_matrix([0.5, 0, 0])
120
+ elif animation_type == 'assemble':
121
+ # X์ถ• ๋ฐฉํ–ฅ์œผ๋กœ ์•ฝ๊ฐ„ ์ด๋™ (๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ)
122
+ transform = tf.translation_matrix([-0.5, 0, 0])
123
+ elif animation_type == 'swing':
124
+ # Z์ถ• ๊ธฐ์ค€ ์•ฝ๊ฐ„ ํšŒ์ „
125
+ transform = tf.rotation_matrix(math.pi/8, [0, 0, 1])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
+ print(f"Step 3: Applying transformation to scene")
128
+ if isinstance(scene, trimesh.Scene):
129
+ # Scene์ธ ๊ฒฝ์šฐ ์ง์ ‘ ๋ณ€ํ™˜ ์ ์šฉ
130
+ scene.apply_transform(transform)
131
+ print(f"Applied transform to scene")
132
+ else:
133
+ print(f"Scene is not trimesh.Scene, but {type(scene)}")
 
 
 
 
 
 
134
 
135
+ print(f"Step 4: Exporting modified scene to '{output_glb_path}'")
136
  scene.export(output_glb_path)
137
+ print(f"Successfully exported modified GLB to '{output_glb_path}'")
138
+
139
  return output_glb_path
140
+
141
  except Exception as e:
142
+ print(f"Error modifying GLB file: {str(e)}")
143
+
144
  # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์›๋ณธ ํŒŒ์ผ ๋ณต์‚ฌ
145
  try:
146
  import shutil
147
+ print(f"Copying original GLB file as fallback")
148
+ shutil.copy(input_glb_path, output_glb_path)
149
+ print(f"Successfully copied original GLB to '{output_glb_path}'")
150
+ return output_glb_path
151
  except Exception as copy_error:
152
  print(f"Error copying GLB: {copy_error}")
153
+ return input_glb_path # ์›๋ณธ ํŒŒ์ผ ๊ฒฝ๋กœ ๋ฐ˜ํ™˜
154
 
155
  @spaces.GPU
156
  def process_3d_model(input_3d, animation_type, animation_duration, fps):
 
158
  print(f"Processing: {input_3d} with animation type: {animation_type}")
159
 
160
  try:
161
+ # ํŒŒ์ผ๋ช… ์ค€๋น„
 
 
 
 
 
 
 
 
162
  base_filename = os.path.basename(input_3d).rsplit('.', 1)[0]
163
+ animated_glb_path = os.path.join(LOG_PATH, f'animated_{base_filename}.glb')
164
+ animated_gif_path = os.path.join(LOG_PATH, f'text_animated_{base_filename}.gif')
165
+ json_path = os.path.join(LOG_PATH, f'metadata_{base_filename}.json')
166
+
167
+ # 1. GLB ํŒŒ์ผ ์ˆ˜์ •
168
+ print(f"Modifying GLB file")
169
+ modified_glb = modify_glb_file(input_3d, animated_glb_path, animation_type)
170
+
171
+ # 2. ์• ๋‹ˆ๋ฉ”์ด์…˜ GIF ์ƒ์„ฑ (์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ํ•ญ์ƒ ์ƒ์„ฑ)
172
+ print(f"Creating animation GIF")
173
+ animated_gif = create_textual_animation_gif(
174
+ animated_gif_path,
175
  os.path.basename(input_3d),
176
  animation_type,
177
  animation_duration,
 
179
  )
180
 
181
  # 3. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ƒ์„ฑ
182
+ print(f"Creating metadata")
183
  metadata = {
184
  "animation_type": animation_type,
185
  "duration": animation_duration,
 
188
  "created_at": time.strftime("%Y-%m-%d %H:%M:%S")
189
  }
190
 
 
191
  with open(json_path, 'w') as f:
192
  json.dump(metadata, f, indent=4)
193
+
194
+ print(f"Processing complete, returning results")
195
+ return modified_glb, animated_gif, json_path
196
+
197
  except Exception as e:
198
+ print(f"Error in process_3d_model: {str(e)}")
199
+ # ์‹ฌ๊ฐํ•œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์›๋ณธ ํŒŒ์ผ๊ณผ ๊ธฐ๋ณธ GIF ๋ฐ˜ํ™˜
200
+ try:
201
+ base_filename = os.path.basename(input_3d).rsplit('.', 1)[0]
202
+ animated_gif_path = os.path.join(LOG_PATH, f'text_animated_{base_filename}.gif')
203
+ create_textual_animation_gif(
204
+ animated_gif_path,
205
+ os.path.basename(input_3d),
206
+ animation_type,
207
+ animation_duration,
208
+ fps
209
+ )
210
+ return input_3d, animated_gif_path, None
211
+ except:
212
+ return f"Error processing file: {str(e)}", None, None
213
 
214
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค ์„ค์ •
215
  with gr.Blocks(title="GLB ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒ์„ฑ๊ธฐ") as demo: