crevelop commited on
Commit
776e8a8
·
unverified ·
1 Parent(s): cae1d1d

Revert "add external GLB processor for bone renaming"

Browse files

This reverts commit 5a054025c45371ec5fc98c4a7fc1e8ca49a799bd.

Files changed (2) hide show
  1. app.py +3 -59
  2. src/inference/bone_renamer.py +0 -252
app.py CHANGED
@@ -2,7 +2,7 @@ import shutil
2
  import subprocess
3
  import time
4
  from pathlib import Path
5
- from typing import Tuple, Optional
6
 
7
  import gradio as gr
8
  import lightning as L
@@ -280,53 +280,14 @@ def merge_results_python(source_file: str, target_file: str, output_file: str) -
280
 
281
  return str(output_path.resolve())
282
 
283
- def rename_bones_post_processing(input_file: str, config_file: str = "configs/skeleton/mixamo.yaml") -> str:
284
- """
285
- Post-processing step to rename bones in GLB files.
286
-
287
- Args:
288
- input_file: Path to the input GLB file
289
- config_file: Path to the skeleton configuration file
290
-
291
- Returns:
292
- Path to the processed file (same as input if successful)
293
- """
294
- try:
295
- from src.inference.bone_renamer import rename_bones_in_glb
296
-
297
- # Only process GLB files
298
- if not str(input_file).lower().endswith('.glb'):
299
- print(f"Skipping bone renaming for non-GLB file: {input_file}")
300
- return input_file
301
-
302
- # Create output path (same directory, with _renamed suffix)
303
- input_path = Path(input_file)
304
- output_path = input_path.parent / f"{input_path.stem}_renamed{input_path.suffix}"
305
-
306
- # Rename bones
307
- success = rename_bones_in_glb(str(input_file), str(output_path), config_file)
308
-
309
- if success:
310
- print(f"Successfully renamed bones in {input_file} -> {output_path}")
311
- return str(output_path)
312
- else:
313
- print(f"Failed to rename bones in {input_file}, keeping original")
314
- return input_file
315
-
316
- except Exception as e:
317
- print(f"Warning: Bone renaming failed: {e}")
318
- print("Continuing with original file...")
319
- return input_file
320
-
321
  @spaces.GPU()
322
- def main(input_file: str, seed: int = 12345, bone_renaming: str = "none") -> Tuple[str, list]:
323
  """
324
  Run the rigging pipeline based on selected mode.
325
 
326
  Args:
327
  input_file: Path to the input 3D model file
328
  seed: Random seed for reproducible results
329
- bone_renaming: Bone renaming option ("none", "mixamo", "vroid")
330
 
331
  Returns:
332
  Tuple of (final_file_path, list_of_intermediate_files)
@@ -370,16 +331,6 @@ def main(input_file: str, seed: int = 12345, bone_renaming: str = "none") -> Tup
370
  run_inference_python(intermediate_skeleton_file, intermediate_skin_file, "skin")
371
  merge_results_python(intermediate_skin_file, input_file, final_skin_file)
372
 
373
- # Step 3: Apply bone renaming if requested (post-processing)
374
- if bone_renaming != "none":
375
- config_file = f"configs/skeleton/{bone_renaming}.yaml"
376
- if Path(config_file).exists():
377
- print(f"Applying {bone_renaming} bone renaming as post-processing...")
378
- final_skeleton_file = rename_bones_post_processing(str(final_skeleton_file), config_file)
379
- final_skin_file = rename_bones_post_processing(str(final_skin_file), config_file)
380
- else:
381
- print(f"Warning: Configuration file {config_file} not found. Skipping bone renaming.")
382
-
383
  final_file = str(final_skin_file)
384
  output_files = [str(final_skeleton_file), str(final_skin_file)]
385
 
@@ -420,13 +371,6 @@ def create_app():
420
  )
421
  random_btn = gr.Button("🔄 Random Seed", variant="secondary", scale=1)
422
 
423
- bone_renaming = gr.Dropdown(
424
- choices=["none", "mixamo", "vroid"],
425
- value="none",
426
- label="Bone Renaming",
427
- info="Choose bone naming convention (only works with GLB output, none = keep generic names)"
428
- )
429
-
430
  pipeline_btn = gr.Button("🎯 Start Processing", variant="primary", size="lg")
431
 
432
  with gr.Column():
@@ -440,7 +384,7 @@ def create_app():
440
 
441
  pipeline_btn.click(
442
  fn=main,
443
- inputs=[input_3d_model, seed, bone_renaming],
444
  outputs=[pipeline_skeleton_out, files_to_download]
445
  )
446
 
 
2
  import subprocess
3
  import time
4
  from pathlib import Path
5
+ from typing import Tuple
6
 
7
  import gradio as gr
8
  import lightning as L
 
280
 
281
  return str(output_path.resolve())
282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  @spaces.GPU()
284
+ def main(input_file: str, seed: int = 12345) -> Tuple[str, list]:
285
  """
286
  Run the rigging pipeline based on selected mode.
287
 
288
  Args:
289
  input_file: Path to the input 3D model file
290
  seed: Random seed for reproducible results
 
291
 
292
  Returns:
293
  Tuple of (final_file_path, list_of_intermediate_files)
 
331
  run_inference_python(intermediate_skeleton_file, intermediate_skin_file, "skin")
332
  merge_results_python(intermediate_skin_file, input_file, final_skin_file)
333
 
 
 
 
 
 
 
 
 
 
 
334
  final_file = str(final_skin_file)
335
  output_files = [str(final_skeleton_file), str(final_skin_file)]
336
 
 
371
  )
372
  random_btn = gr.Button("🔄 Random Seed", variant="secondary", scale=1)
373
 
 
 
 
 
 
 
 
374
  pipeline_btn = gr.Button("🎯 Start Processing", variant="primary", size="lg")
375
 
376
  with gr.Column():
 
384
 
385
  pipeline_btn.click(
386
  fn=main,
387
+ inputs=[input_3d_model, seed],
388
  outputs=[pipeline_skeleton_out, files_to_download]
389
  )
390
 
src/inference/bone_renamer.py DELETED
@@ -1,252 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Simple script to rename bones in GLB/GLTF files by directly manipulating the JSON structure.
4
- This approach doesn't require Blender or complex 3D libraries.
5
- """
6
-
7
- import json
8
- import yaml
9
- import gzip
10
- import struct
11
- from pathlib import Path
12
- import logging
13
- from typing import Dict, List, Optional
14
-
15
- # Set up logging
16
- logging.basicConfig(level=logging.INFO)
17
- logger = logging.getLogger(__name__)
18
-
19
- class GLBProcessor:
20
- def __init__(self, config_path: str = "configs/skeleton/mixamo.yaml"):
21
- """Initialize with skeleton configuration."""
22
- self.bone_names = self._load_bone_config(config_path)
23
-
24
- def _load_bone_config(self, config_path: str) -> List[str]:
25
- """Load bone names from configuration."""
26
- with open(config_path, 'r') as f:
27
- config = yaml.safe_load(f)
28
-
29
- bone_names = []
30
- parts_order = config.get('parts_order', [])
31
-
32
- for part in parts_order:
33
- if part in config.get('parts', {}):
34
- bone_names.extend(config['parts'][part])
35
-
36
- logger.info(f"Loaded {len(bone_names)} bone names from {config_path}")
37
- return bone_names
38
-
39
- def read_glb(self, filepath: str) -> tuple:
40
- """Read GLB file and return JSON and binary data."""
41
- with open(filepath, 'rb') as f:
42
- # Read GLB header
43
- magic = f.read(4)
44
- if magic != b'glTF':
45
- raise ValueError("Not a valid GLB file")
46
-
47
- version = struct.unpack('<I', f.read(4))[0]
48
- length = struct.unpack('<I', f.read(4))[0]
49
-
50
- # Read JSON chunk
51
- json_length = struct.unpack('<I', f.read(4))[0]
52
- json_type = f.read(4)
53
- if json_type != b'JSON':
54
- raise ValueError("Invalid JSON chunk")
55
-
56
- json_data = f.read(json_length)
57
- gltf_json = json.loads(json_data.decode('utf-8'))
58
-
59
- # Read binary chunk if present
60
- binary_data = None
61
- if f.tell() < length:
62
- binary_length = struct.unpack('<I', f.read(4))[0]
63
- binary_type = f.read(4)
64
- if binary_type == b'BIN\x00':
65
- binary_data = f.read(binary_length)
66
-
67
- return gltf_json, binary_data
68
-
69
- def write_glb(self, filepath: str, gltf_json: dict, binary_data: Optional[bytes] = None):
70
- """Write GLB file with JSON and binary data."""
71
- json_str = json.dumps(gltf_json, separators=(',', ':'))
72
- json_bytes = json_str.encode('utf-8')
73
-
74
- # Pad JSON to 4-byte boundary
75
- json_padding = (4 - (len(json_bytes) % 4)) % 4
76
- json_bytes += b' ' * json_padding
77
-
78
- # Calculate total length
79
- total_length = 12 + 8 + len(json_bytes) # header + JSON chunk header + JSON data
80
- if binary_data:
81
- binary_padding = (4 - (len(binary_data) % 4)) % 4
82
- binary_data += b'\x00' * binary_padding
83
- total_length += 8 + len(binary_data) # binary chunk header + binary data
84
-
85
- with open(filepath, 'wb') as f:
86
- # Write GLB header
87
- f.write(b'glTF')
88
- f.write(struct.pack('<I', 2)) # version 2
89
- f.write(struct.pack('<I', total_length))
90
-
91
- # Write JSON chunk
92
- f.write(struct.pack('<I', len(json_bytes)))
93
- f.write(b'JSON')
94
- f.write(json_bytes)
95
-
96
- # Write binary chunk if present
97
- if binary_data:
98
- f.write(struct.pack('<I', len(binary_data)))
99
- f.write(b'BIN\x00')
100
- f.write(binary_data)
101
-
102
- def rename_bones(self, gltf_json: dict, bone_mapping: Dict[str, str]) -> dict:
103
- """Rename bones in GLTF JSON structure."""
104
- # Create a copy to avoid modifying the original
105
- new_gltf = json.loads(json.dumps(gltf_json))
106
-
107
- # Rename bones in nodes
108
- if 'nodes' in new_gltf:
109
- for node in new_gltf['nodes']:
110
- if 'name' in node and node['name'] in bone_mapping:
111
- old_name = node['name']
112
- new_name = bone_mapping[old_name]
113
- node['name'] = new_name
114
- logger.debug(f"Renamed node: {old_name} -> {new_name}")
115
-
116
- # Rename bones in skins
117
- if 'skins' in new_gltf:
118
- for skin in new_gltf['skins']:
119
- if 'joints' in skin:
120
- for i, joint_index in enumerate(skin['joints']):
121
- if joint_index < len(new_gltf.get('nodes', [])):
122
- node = new_gltf['nodes'][joint_index]
123
- if 'name' in node and node['name'] in bone_mapping:
124
- old_name = node['name']
125
- new_name = bone_mapping[old_name]
126
- node['name'] = new_name
127
- logger.debug(f"Renamed skin joint: {old_name} -> {new_name}")
128
-
129
- # Rename bones in animations
130
- if 'animations' in new_gltf:
131
- for anim in new_gltf['animations']:
132
- if 'channels' in anim:
133
- for channel in anim['channels']:
134
- if 'target' in channel and 'node' in channel['target']:
135
- node_index = channel['target']['node']
136
- if node_index < len(new_gltf.get('nodes', [])):
137
- node = new_gltf['nodes'][node_index]
138
- if 'name' in node and node['name'] in bone_mapping:
139
- old_name = node['name']
140
- new_name = bone_mapping[old_name]
141
- node['name'] = new_name
142
- logger.debug(f"Renamed animation target: {old_name} -> {new_name}")
143
-
144
- return new_gltf
145
-
146
- def process_glb(self, input_path: str, output_path: str, bone_mapping: Optional[Dict[str, str]] = None) -> bool:
147
- """Process GLB file to rename bones."""
148
- try:
149
- # Read GLB file
150
- logger.info(f"Reading GLB file: {input_path}")
151
- gltf_json, binary_data = self.read_glb(input_path)
152
-
153
- # Extract current bone names
154
- current_bones = []
155
- if 'nodes' in gltf_json:
156
- for node in gltf_json['nodes']:
157
- if 'name' in node:
158
- current_bones.append(node['name'])
159
-
160
- logger.info(f"Found {len(current_bones)} nodes in GLB file")
161
-
162
- # Create bone mapping if not provided
163
- if bone_mapping is None:
164
- bone_mapping = self._create_bone_mapping(current_bones)
165
-
166
- # Rename bones
167
- logger.info("Renaming bones...")
168
- new_gltf = self.rename_bones(gltf_json, bone_mapping)
169
-
170
- # Write updated GLB file
171
- logger.info(f"Writing updated GLB file: {output_path}")
172
- self.write_glb(output_path, new_gltf, binary_data)
173
-
174
- logger.info("Bone renaming completed successfully!")
175
- return True
176
-
177
- except Exception as e:
178
- logger.error(f"Error processing GLB file: {e}")
179
- import traceback
180
- logger.error(f"Traceback: {traceback.format_exc()}")
181
- return False
182
-
183
- def _create_bone_mapping(self, current_bones: List[str]) -> Dict[str, str]:
184
- """Create mapping from current bone names to standard names."""
185
- bone_mapping = {}
186
- sorted_current_bones = sorted(current_bones)
187
-
188
- for i, current_name in enumerate(sorted_current_bones):
189
- if i < len(self.bone_names):
190
- standard_name = self.bone_names[i]
191
- bone_mapping[current_name] = standard_name
192
- logger.info(f"Mapping {current_name} -> {standard_name}")
193
- else:
194
- bone_mapping[current_name] = current_name
195
- logger.warning(f"No standard name for {current_name}, keeping original")
196
-
197
- return bone_mapping
198
-
199
-
200
- def rename_bones_in_glb(input_file: str, output_file: str, config_file: str = "configs/skeleton/mixamo.yaml") -> bool:
201
- """
202
- Convenience function to rename bones in a GLB file.
203
-
204
- Args:
205
- input_file: Path to input GLB file
206
- output_file: Path to output GLB file
207
- config_file: Path to skeleton configuration file
208
-
209
- Returns:
210
- True if successful, False otherwise
211
- """
212
- processor = GLBProcessor(config_file)
213
- return processor.process_glb(input_file, output_file)
214
-
215
-
216
- if __name__ == "__main__":
217
- import argparse
218
-
219
- parser = argparse.ArgumentParser(description="Rename bones in GLB file to standard names")
220
- parser.add_argument("input", help="Input GLB file path")
221
- parser.add_argument("output", help="Output GLB file path")
222
- parser.add_argument("--config", default="configs/skeleton/mixamo.yaml",
223
- help="Path to skeleton configuration file")
224
- parser.add_argument("--mapping", help="JSON file with custom bone name mapping")
225
- parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose logging")
226
-
227
- args = parser.parse_args()
228
-
229
- if args.verbose:
230
- logging.getLogger().setLevel(logging.DEBUG)
231
-
232
- # Initialize processor
233
- processor = GLBProcessor(args.config)
234
-
235
- # Load custom mapping if provided
236
- bone_mapping = None
237
- if args.mapping:
238
- try:
239
- with open(args.mapping, 'r') as f:
240
- bone_mapping = json.load(f)
241
- logger.info(f"Loaded custom bone mapping from: {args.mapping}")
242
- except Exception as e:
243
- logger.error(f"Failed to load custom mapping: {e}")
244
- exit(1)
245
-
246
- # Process the GLB file
247
- success = processor.process_glb(args.input, args.output, bone_mapping)
248
-
249
- if success:
250
- exit(0)
251
- else:
252
- exit(1)