ginipick commited on
Commit
30b09aa
Β·
verified Β·
1 Parent(s): a285b9c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +197 -13
app.py CHANGED
@@ -19,6 +19,62 @@ import spaces
19
  LOG_PATH = './results/demo'
20
  os.makedirs(LOG_PATH, exist_ok=True)
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  def create_textual_animation_gif(output_path, model_name, animation_type, duration=3.0, fps=30):
23
  """ν…μŠ€νŠΈ 기반의 κ°„λ‹¨ν•œ μ• λ‹ˆλ©”μ΄μ…˜ GIF 생성 - λ Œλ”λ§ μ‹€νŒ¨ μ‹œ λŒ€μ²΄μš©"""
24
  try:
@@ -107,13 +163,152 @@ def create_textual_animation_gif(output_path, model_name, animation_type, durati
107
  print(f"Error creating textual animation: {str(e)}")
108
  return None
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  @spaces.GPU
111
  def process_3d_model(input_3d, animation_type, animation_duration, fps):
112
  """Process a 3D model and apply animation"""
113
  print(f"Processing: {input_3d} with animation type: {animation_type}")
114
 
115
  try:
116
- # ν…μŠ€νŠΈ 기반 μ• λ‹ˆλ©”μ΄μ…˜ GIF 생성 (λ Œλ”λ§ μ‹€νŒ¨λ₯Ό μš°λ €ν•˜μ—¬ 항상 생성)
 
 
 
 
 
 
 
 
117
  base_filename = os.path.basename(input_3d).rsplit('.', 1)[0]
118
  text_gif_path = os.path.join(LOG_PATH, f'text_animated_{base_filename}.gif')
119
  animated_gif_path = create_textual_animation_gif(
@@ -124,18 +319,7 @@ def process_3d_model(input_3d, animation_type, animation_duration, fps):
124
  fps
125
  )
126
 
127
- # 원본 GLB 파일 볡사
128
- copy_glb_path = os.path.join(LOG_PATH, f'copy_{base_filename}.glb')
129
- import shutil
130
- try:
131
- shutil.copy(input_3d, copy_glb_path)
132
- animated_glb_path = copy_glb_path
133
- print(f"Copied original GLB to {copy_glb_path}")
134
- except Exception as e:
135
- print(f"Error copying GLB: {e}")
136
- animated_glb_path = input_3d
137
-
138
- # 메타데이터 생성
139
  metadata = {
140
  "animation_type": animation_type,
141
  "duration": animation_duration,
 
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:
 
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):
299
  """Process a 3D model and apply animation"""
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(
 
319
  fps
320
  )
321
 
322
+ # 3. 메타데이터 생성
 
 
 
 
 
 
 
 
 
 
 
323
  metadata = {
324
  "animation_type": animation_type,
325
  "duration": animation_duration,