jasongzy commited on
Commit
d356cac
·
1 Parent(s): 625a222

✨ feat: update readme & scripts

Browse files
README.md CHANGED
@@ -1,3 +1,27 @@
1
  ---
2
  license: apache-2.0
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
  ---
4
+
5
+ ## Data
6
+
7
+ - `character`: 95 characters (T-pose with bones and texture) downloaded from [Mixamo](https://www.mixamo.com/#/?page=1&type=Character)
8
+
9
+ - `character_fbx_upgraded`: 51 (among 95) characters with FBX version upgraded by [FBX Converter](https://aps.autodesk.com/developer/overview/fbx-converter-archives) (so that they can be imported into [Blender](https://www.blender.org/))
10
+
11
+ - **`character_refined`**: all 95 characters (triangle mesh without texture, animatable by any one from `animation`) processed with `character_refine.py`
12
+ - vertices: 2374 ~ 35128 (average: 15482; details in `character_verts.json`)
13
+ - bones: 42 ~ 112 (mostly standard 65 *mixamorig* bones; details in `character_bones.txt`)
14
+
15
+ - **`animation`**: 2453 animations (only bones) downloaded from [Mixamo](https://www.mixamo.com/#/?page=1&type=Motion)
16
+ - frames: 2 ~ 2801 (average: 212; details in `animation_frames.json`)
17
+
18
+ ## Reproduction
19
+
20
+ 1. Download characters and animations [Mixamo](https://www.mixamo.com/).
21
+
22
+ 2. Convert old-version FBX (`try_import_blender.py` > `character_old_fbx.txt`) with [FBX Converter](https://aps.autodesk.com/developer/overview/fbx-converter-archives).
23
+
24
+ 3. ~~Re-target unposed characters with [Auto-Rig Pro](https://blendermarket.com/products/auto-rig-pro) (bind-only) in Blender.~~
25
+ Rename corrupted bone names in unposed characters (`character_unposed.txt`).
26
+
27
+ 4. Convert all characters into **triangle mesh without texture** with [Blender](https://docs.blender.org/api/current/info_advanced_blender_as_bpy.html).
animation_frames.json ADDED
The diff for this file is too large to render. See raw diff
 
character_bones.txt ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ./character/0510032b674ce33343c2e058ef52e8c5.fbx: 65
2
+ ./character/06caf212ded22a78500c06ebf372c9bb.fbx: 65
3
+ ./character/079f3ee7c8d748481707ca78c95750ac.fbx: 65
4
+ ./character/08ed9e6576433de9fb72baae34d482b6.fbx: 65
5
+ ./character/08f7e724f32af241e56a9244c2f37b43.fbx: 65
6
+ ./character/098424150eb08fb107185646afaeee83.fbx: 64
7
+ ./character/0a29fafad2ca23eba1787e20894ea8f6.fbx: 65
8
+ ./character/0b69ca9d9cd64f4c061659f29956e297.fbx: 81
9
+ ./character/0eb7402a9104734d873599c7f9f01c3d.fbx: 99
10
+ ./character/0fa8427ca1b7b2f410e893daa42df16c.fbx: 67
11
+ ./character/123d7c7f828741681ffed14eacaf606d.fbx: 69
12
+ ./character/19b740666ef33a06abf265235d8281a0.fbx: 65
13
+ ./character/1c679b4220a9b78133db6c49f59ca65c.fbx: 83
14
+ ./character/1f6a7214d5f9eee30f4da837ad0db9a9.fbx: 65
15
+ ./character/216f6676c0df33582682a270735a0bda.fbx: 65
16
+ ./character/222261b7a837ccdf5db5ea086430d4c7.fbx: 112
17
+ ./character/258580e0c4983768c0233dca33157732.fbx: 57
18
+ ./character/27de3b0b89d27fa7e654955765e40d3b.fbx: 79
19
+ ./character/28069e1e9f570cc90128fe1241343875.fbx: 47
20
+ ./character/2d925ffeafc887cf96d22d272e6a87cd.fbx: 69
21
+ ./character/32db57cc0f9c3ee01c22924512d56283.fbx: 73
22
+ ./character/39967d464dd297954f89d06fb587045f.fbx: 99
23
+ ./character/3c21546cb958a3daba75704b232b7e4b.fbx: 65
24
+ ./character/3e911fa9c30c9a00a9de31409095cd57.fbx: 67
25
+ ./character/3ec1224ed7c692d1e83a4cdfc2f5340b.fbx: 65
26
+ ./character/4c989f8d4d0b9c1e6e096f21719fd09d.fbx: 66
27
+ ./character/4cd9c2951759527d10bb7916baa80ca2.fbx: 99
28
+ ./character/4fd247797b4f3653d5c2a8b335b03d29.fbx: 69
29
+ ./character/51b67149e52d48e2442f1db223f59ba9.fbx: 65
30
+ ./character/51d19d5e4cd1c8c8d75a97f078ff9476.fbx: 65
31
+ ./character/51e1e51887023725371b27fd0cb3dca1.fbx: 65
32
+ ./character/525795a33ca1026996b5ca009d61e263.fbx: 65
33
+ ./character/57f74ab8c6de76c82d53e3257a6778e4.fbx: 65
34
+ ./character/5bf474106308ccb071045e9579ca95e5.fbx: 65
35
+ ./character/5cd6b5bf8b921a2cb0e4ce71d685ff90.fbx: 69
36
+ ./character/6987df4026a93126ed745db3b5f2fbcf.fbx: 67
37
+ ./character/69c3f460dcf1f1f97942d5dafaac572d.fbx: 65
38
+ ./character/73cd22e7123f4c8e78ffc11ad5fbbc29.fbx: 65
39
+ ./character/75a7bced986dc088580ecbe09e1c8590.fbx: 65
40
+ ./character/761718127eb6d283b7bf7076bca62b78.fbx: 65
41
+ ./character/761b5a0cf1945d0089f00686beb41f49.fbx: 65
42
+ ./character/7dcd7c3eb5f2fb50caf6ae6896e9464c.fbx: 65
43
+ ./character/7dd7bf41bda834a9500b2ff93705ad02.fbx: 65
44
+ ./character/7faa53355e944ba38be5a4b7de179290.fbx: 65
45
+ ./character/7fd6d88afe76663358a61901be3c6c15.fbx: 65
46
+ ./character/8044e1503d3549a144741dc1878d414a.fbx: 43
47
+ ./character/81f41f90717b8383b3d2fffb18f95d07.fbx: 65
48
+ ./character/831a835d6cca7f50fee848116a1e0a6b.fbx: 88
49
+ ./character/83828f0fe01d389df691a0b8f2e19b95.fbx: 72
50
+ ./character/840c84726b0f55c9fa7235074394fd6a.fbx: 67
51
+ ./character/85bc8db2b257cf836c186593aa8a1fce.fbx: 43
52
+ ./character/893b3e8f4a0cea4255ccee36633756e7.fbx: 65
53
+ ./character/8b6cd9d3a78bdf860d3d06b58715b310.fbx: 65
54
+ ./character/8dfaf7ace7778cd25a6b181d98cd7e77.fbx: 67
55
+ ./character/93025f9cd069b342a20217702a522b54.fbx: 65
56
+ ./character/932216e3a518b0468f18bbb824ee6fa5.fbx: 65
57
+ ./character/9882611aba55c935f071e41769da7b99.fbx: 65
58
+ ./character/9a24bbb67c6dac80b1e83238982fc9bd.fbx: 65
59
+ ./character/9a3c048709538dfbe0be943c9fae3d62.fbx: 65
60
+ ./character/9e33cfb2c5443136600e393a4aa2e7f1.fbx: 43
61
+ ./character/a0641e810f7d000c8ca59e7224c9d796.fbx: 72
62
+ ./character/a3d6df0a1670bd02cc732c8137427dbe.fbx: 67
63
+ ./character/a4ce3af02c103b2e9b78b9b14e7a01a3.fbx: 65
64
+ ./character/a688cfa656103db0d2acb62c8d2d9144.fbx: 69
65
+ ./character/aa03d7c7297f3864ce77600f5f940606.fbx: 69
66
+ ./character/aed9922313c4b66e9b3ec1bc6dec06a8.fbx: 65
67
+ ./character/b0ce097858de7591269ef24996ad0808.fbx: 67
68
+ ./character/b1bf836b9d040760b79534e30a8cba76.fbx: 86
69
+ ./character/b1ca6a6e9f48e9a7e4c2a92eb1837e37.fbx: 69
70
+ ./character/b1eea1f10e0a85ad8f6b8c8cc5882cf8.fbx: 65
71
+ ./character/b45062da94f349e53a67b0028539deac.fbx: 63
72
+ ./character/b6e2f4dbb404550f7c05e5158c45f979.fbx: 65
73
+ ./character/b78413c2dc7908bf952a609b24569807.fbx: 65
74
+ ./character/b9ae94869ab838ee63cf92990211e525.fbx: 49
75
+ ./character/bad88bdd65811e64a724b49cb0e505a5.fbx: 65
76
+ ./character/bc9c26c1c3653c81d3d35261cd696839.fbx: 67
77
+ ./character/bd0a2e2cc4da1a2e566e6dd98402edfb.fbx: 65
78
+ ./character/bd5584dc8872126d57d969aa07ec09a6.fbx: 37
79
+ ./character/c3b24f5c406ef4c09c2c07ae65dba0e0.fbx: 65
80
+ ./character/c4d054e07d59a8b2224e07ab2fbf505b.fbx: 75
81
+ ./character/c92d8db4a32b4606fb6258a385f5fcd1.fbx: 65
82
+ ./character/cb8b934b054940623581dfaf5d9fd468.fbx: 68
83
+ ./character/cdf89c5c4430cbc672e0f61c78797d39.fbx: 65
84
+ ./character/cf65a1c8be43a9c90570b99a0b702aff.fbx: 76
85
+ ./character/cf7e9c498421b75e2df678adc5284783.fbx: 65
86
+ ./character/d2f2e35da6c1fcca872fccf83fef9a5a.fbx: 72
87
+ ./character/e000b51a0c9526a75f155bc925722db3.fbx: 65
88
+ ./character/e426198d78eaf096bf1e38ffdaa9af17.fbx: 73
89
+ ./character/e4280b007901ef1c87a68be75323ab39.fbx: 87
90
+ ./character/e5e1eccee079207473fafb1c163e2272.fbx: 65
91
+ ./character/eb5e61abbf1fd39f3e73212723d5f580.fbx: 66
92
+ ./character/eceb1dd6a739c6523c4208394e95a659.fbx: 69
93
+ ./character/ed5953ef8156aee8bbe329c3e6ff39a0.fbx: 68
94
+ ./character/f24b568cf5d54dca7fbe5dd328e49632.fbx: 59
95
+ ./character/fdad443d5251b547f75d6578a6447c7c.fbx: 65
96
+ mixamorig:Hips: 95/95
97
+ mixamorig:Spine: 95/95
98
+ mixamorig:Spine1: 95/95
99
+ mixamorig:Spine2: 95/95
100
+ mixamorig:Neck: 95/95
101
+ mixamorig:Head: 95/95
102
+ mixamorig:HeadTop_End: 95/95
103
+ LeftEye: 3/95
104
+ RightEye: 3/95
105
+ mixamorig:LeftShoulder: 95/95
106
+ mixamorig:LeftArm: 95/95
107
+ mixamorig:LeftForeArm: 95/95
108
+ mixamorig:LeftHand: 95/95
109
+ mixamorig:LeftHandThumb1: 94/95
110
+ mixamorig:LeftHandThumb2: 94/95
111
+ mixamorig:LeftHandThumb3: 94/95
112
+ mixamorig:LeftHandThumb4: 94/95
113
+ mixamorig:LeftHandIndex1: 94/95
114
+ mixamorig:LeftHandIndex2: 94/95
115
+ mixamorig:LeftHandIndex3: 94/95
116
+ mixamorig:LeftHandIndex4: 93/95
117
+ mixamorig:LeftHandMiddle1: 91/95
118
+ mixamorig:LeftHandMiddle2: 91/95
119
+ mixamorig:LeftHandMiddle3: 91/95
120
+ mixamorig:LeftHandMiddle4: 90/95
121
+ mixamorig:LeftHandRing1: 90/95
122
+ mixamorig:LeftHandRing2: 90/95
123
+ mixamorig:LeftHandRing3: 90/95
124
+ mixamorig:LeftHandRing4: 89/95
125
+ mixamorig:LeftHandPinky1: 88/95
126
+ mixamorig:LeftHandPinky2: 88/95
127
+ mixamorig:LeftHandPinky3: 88/95
128
+ mixamorig:LeftHandPinky4: 87/95
129
+ mixamorig:RightShoulder: 95/95
130
+ mixamorig:RightArm: 95/95
131
+ mixamorig:RightForeArm: 95/95
132
+ mixamorig:RightHand: 95/95
133
+ mixamorig:RightHandThumb1: 94/95
134
+ mixamorig:RightHandThumb2: 94/95
135
+ mixamorig:RightHandThumb3: 94/95
136
+ mixamorig:RightHandThumb4: 94/95
137
+ mixamorig:RightHandIndex1: 94/95
138
+ mixamorig:RightHandIndex2: 94/95
139
+ mixamorig:RightHandIndex3: 94/95
140
+ mixamorig:RightHandIndex4: 93/95
141
+ mixamorig:RightHandMiddle1: 89/95
142
+ mixamorig:RightHandMiddle2: 89/95
143
+ mixamorig:RightHandMiddle3: 89/95
144
+ mixamorig:RightHandMiddle4: 88/95
145
+ mixamorig:RightHandRing1: 89/95
146
+ mixamorig:RightHandRing2: 89/95
147
+ mixamorig:RightHandRing3: 89/95
148
+ mixamorig:RightHandRing4: 88/95
149
+ mixamorig:RightHandPinky1: 88/95
150
+ mixamorig:RightHandPinky2: 88/95
151
+ mixamorig:RightHandPinky3: 88/95
152
+ mixamorig:RightHandPinky4: 87/95
153
+ mixamorig:LeftUpLeg: 95/95
154
+ mixamorig:LeftLeg: 95/95
155
+ mixamorig:LeftFoot: 95/95
156
+ mixamorig:LeftToeBase: 95/95
157
+ mixamorig:LeftToe_End: 95/95
158
+ mixamorig:RightUpLeg: 95/95
159
+ mixamorig:RightLeg: 95/95
160
+ mixamorig:RightFoot: 95/95
161
+ mixamorig:RightToeBase: 95/95
162
+ mixamorig:RightToe_End: 95/95
character_old_fbx.txt ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ./character/098424150eb08fb107185646afaeee83.fbx
2
+ ./character/0b69ca9d9cd64f4c061659f29956e297.fbx
3
+ ./character/0eb7402a9104734d873599c7f9f01c3d.fbx
4
+ ./character/0fa8427ca1b7b2f410e893daa42df16c.fbx
5
+ ./character/123d7c7f828741681ffed14eacaf606d.fbx
6
+ ./character/19b740666ef33a06abf265235d8281a0.fbx
7
+ ./character/1c679b4220a9b78133db6c49f59ca65c.fbx
8
+ ./character/222261b7a837ccdf5db5ea086430d4c7.fbx
9
+ ./character/27de3b0b89d27fa7e654955765e40d3b.fbx
10
+ ./character/28069e1e9f570cc90128fe1241343875.fbx
11
+ ./character/2d925ffeafc887cf96d22d272e6a87cd.fbx
12
+ ./character/32db57cc0f9c3ee01c22924512d56283.fbx
13
+ ./character/39967d464dd297954f89d06fb587045f.fbx
14
+ ./character/3e911fa9c30c9a00a9de31409095cd57.fbx
15
+ ./character/4c989f8d4d0b9c1e6e096f21719fd09d.fbx
16
+ ./character/4cd9c2951759527d10bb7916baa80ca2.fbx
17
+ ./character/4fd247797b4f3653d5c2a8b335b03d29.fbx
18
+ ./character/51e1e51887023725371b27fd0cb3dca1.fbx
19
+ ./character/5cd6b5bf8b921a2cb0e4ce71d685ff90.fbx
20
+ ./character/6987df4026a93126ed745db3b5f2fbcf.fbx
21
+ ./character/761b5a0cf1945d0089f00686beb41f49.fbx
22
+ ./character/8044e1503d3549a144741dc1878d414a.fbx
23
+ ./character/840c84726b0f55c9fa7235074394fd6a.fbx
24
+ ./character/85bc8db2b257cf836c186593aa8a1fce.fbx
25
+ ./character/8dfaf7ace7778cd25a6b181d98cd7e77.fbx
26
+ ./character/9e33cfb2c5443136600e393a4aa2e7f1.fbx
27
+ ./character/a0641e810f7d000c8ca59e7224c9d796.fbx
28
+ ./character/a3d6df0a1670bd02cc732c8137427dbe.fbx
29
+ ./character/a688cfa656103db0d2acb62c8d2d9144.fbx
30
+ ./character/aa03d7c7297f3864ce77600f5f940606.fbx
31
+ ./character/aed9922313c4b66e9b3ec1bc6dec06a8.fbx
32
+ ./character/b0ce097858de7591269ef24996ad0808.fbx
33
+ ./character/b1bf836b9d040760b79534e30a8cba76.fbx
34
+ ./character/b1ca6a6e9f48e9a7e4c2a92eb1837e37.fbx
35
+ ./character/b45062da94f349e53a67b0028539deac.fbx
36
+ ./character/bad88bdd65811e64a724b49cb0e505a5.fbx
37
+ ./character/bc9c26c1c3653c81d3d35261cd696839.fbx
38
+ ./character/bd0a2e2cc4da1a2e566e6dd98402edfb.fbx
39
+ ./character/bd5584dc8872126d57d969aa07ec09a6.fbx
40
+ ./character/c3b24f5c406ef4c09c2c07ae65dba0e0.fbx
41
+ ./character/c4d054e07d59a8b2224e07ab2fbf505b.fbx
42
+ ./character/c92d8db4a32b4606fb6258a385f5fcd1.fbx
43
+ ./character/cb8b934b054940623581dfaf5d9fd468.fbx
44
+ ./character/cf65a1c8be43a9c90570b99a0b702aff.fbx
45
+ ./character/cf7e9c498421b75e2df678adc5284783.fbx
46
+ ./character/d2f2e35da6c1fcca872fccf83fef9a5a.fbx
47
+ ./character/e426198d78eaf096bf1e38ffdaa9af17.fbx
48
+ ./character/eb5e61abbf1fd39f3e73212723d5f580.fbx
49
+ ./character/eceb1dd6a739c6523c4208394e95a659.fbx
50
+ ./character/ed5953ef8156aee8bbe329c3e6ff39a0.fbx
51
+ ./character/f24b568cf5d54dca7fbe5dd328e49632.fbx
character_refine.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ from glob import glob
4
+
5
+ import bpy
6
+ import numpy as np
7
+ from tqdm import tqdm
8
+
9
+
10
+ class HiddenPrints:
11
+ def __init__(self, disable=False):
12
+ self.disable = disable
13
+
14
+ def __enter__(self):
15
+ if self.disable:
16
+ return
17
+ self._original_stdout = sys.stdout
18
+ sys.stdout = open(os.devnull, "w")
19
+
20
+ def __exit__(self, exc_type, exc_val, exc_tb):
21
+ if self.disable:
22
+ return
23
+ sys.stdout.close()
24
+ sys.stdout = self._original_stdout
25
+
26
+
27
+ def remove_all(delete_actions=True):
28
+ for obj in bpy.data.objects.values():
29
+ bpy.data.objects.remove(obj, do_unlink=True)
30
+ bpy.ops.outliner.orphans_purge(do_recursive=True)
31
+ if delete_actions:
32
+ for action in bpy.data.actions:
33
+ bpy.data.actions.remove(action, do_unlink=True)
34
+
35
+
36
+ def load_file(filepath: str):
37
+ old_objs = set(bpy.context.scene.objects)
38
+ if filepath.endswith(".glb"):
39
+ bpy.ops.import_scene.gltf(filepath=filepath)
40
+ elif filepath.endswith(".fbx"):
41
+ bpy.ops.import_scene.fbx(filepath=filepath)
42
+ else:
43
+ raise RuntimeError(f"Invalid input file: {filepath}")
44
+ imported_objs = set(bpy.context.scene.objects) - old_objs
45
+ print("Imported:", imported_objs)
46
+ return imported_objs
47
+
48
+
49
+ def get_type_objs(obj_list=None, type="MESH"):
50
+ if not obj_list:
51
+ obj_list = bpy.context.scene.objects
52
+ type_obj_list = []
53
+ for obj in obj_list:
54
+ if obj.type == type:
55
+ type_obj_list.append(obj)
56
+ return type_obj_list
57
+
58
+
59
+ def get_all_mesh_obj(obj_list=None):
60
+ return get_type_objs(obj_list, "MESH")
61
+
62
+
63
+ def get_all_armature_obj(obj_list=None):
64
+ return get_type_objs(obj_list, "ARMATURE")
65
+
66
+
67
+ def get_rest_bones(armature_obj):
68
+ if armature_obj is None:
69
+ return None, None
70
+ else:
71
+ rest_bones = []
72
+ bones_idx_dict: "dict[str,int]" = {}
73
+ for i, bone in enumerate(armature_obj.data.bones):
74
+ rest_bones.append(armature_obj.matrix_world @ bone.head_local)
75
+ bones_idx_dict[bone.name] = i
76
+ rest_bones = np.stack(rest_bones, axis=0)
77
+ # print(bones_idx_dict)
78
+ return rest_bones, bones_idx_dict
79
+
80
+
81
+ def rename_maxiamo_bone(armature_obj):
82
+ """Replace name like 'mixamorig10:xxx' to 'mixamorig:xxx, so that character can be correctly animated.'"""
83
+ import re
84
+
85
+ pattern = re.compile(r"mixamorig[0-9]+:")
86
+ for bone in armature_obj.data.bones:
87
+ bone.name = re.sub(pattern, "mixamorig:", bone.name)
88
+ return armature_obj
89
+
90
+
91
+ def mesh_quads2tris(obj_list=None):
92
+ if not obj_list:
93
+ obj_list = bpy.context.scene.objects
94
+ for obj in obj_list:
95
+ if obj.type == "MESH":
96
+ # obj.select_set(True)
97
+ bpy.context.view_layer.objects.active = obj
98
+ bpy.ops.object.mode_set(mode="EDIT")
99
+ bpy.ops.mesh.quads_convert_to_tris(quad_method="BEAUTY", ngon_method="BEAUTY")
100
+ bpy.ops.object.mode_set(mode="OBJECT")
101
+
102
+
103
+ if __name__ == "__main__":
104
+ input_dir = "."
105
+ output_dir = os.path.join(input_dir, "character_refined")
106
+ os.makedirs(output_dir, exist_ok=True)
107
+ character_list = sorted(glob(os.path.join(input_dir, "character", "*.fbx")))
108
+ animation_list = sorted(glob(os.path.join(input_dir, "animation", "*.fbx")))
109
+ unposed_list_file = "character_unposed.txt"
110
+ if os.path.isfile(unposed_list_file):
111
+ with open(unposed_list_file, "r") as f:
112
+ unposed_list = f.readlines()
113
+ unposed_list = [x.strip() for x in unposed_list if x.strip() != ""]
114
+ else:
115
+ unposed_list = None
116
+ logfile = "character_bones.txt"
117
+
118
+ bones_name_list = []
119
+ for file in tqdm(character_list, dynamic_ncols=True):
120
+ try:
121
+ with HiddenPrints():
122
+ remove_all()
123
+ obj_list = load_file(file)
124
+ armature_obj = get_all_armature_obj(obj_list)
125
+ assert len(armature_obj) == 1, "Armature number is not 1"
126
+ armature_obj = armature_obj[0]
127
+ if unposed_list is None or file in unposed_list:
128
+ rename_maxiamo_bone(armature_obj)
129
+ rest_bones, bones_idx_dict = get_rest_bones(armature_obj)
130
+
131
+ # mesh_quads2tris(get_all_mesh_obj(obj_list))
132
+ bpy.ops.object.select_all(action="DESELECT")
133
+ for obj in obj_list:
134
+ obj.select_set(True)
135
+ bpy.ops.export_scene.fbx(
136
+ filepath=os.path.join(output_dir, os.path.basename(file)),
137
+ check_existing=False,
138
+ use_selection=True,
139
+ use_triangles=True, #!
140
+ add_leaf_bones=False,
141
+ bake_anim=False,
142
+ embed_textures=False,
143
+ )
144
+ bones_name_list += list(bones_idx_dict.keys())
145
+ with open(logfile, "a") as f:
146
+ f.write(f"{file}: {len(bones_idx_dict)}\n")
147
+ except Exception as e:
148
+ # raise
149
+ tqdm.write(f"{file}: {e}")
150
+ with open(logfile, "a") as f:
151
+ f.write(f"{file}: {e}\n")
152
+
153
+ # Calculate the coverage of each bone among all characters
154
+ print(sorted(set(bones_name_list)))
155
+ with HiddenPrints():
156
+ remove_all()
157
+ rest_bones, bones_idx_dict = get_rest_bones(get_all_armature_obj(load_file(animation_list[0]))[0])
158
+ with open(logfile, "a") as f:
159
+ for v in bones_idx_dict.keys():
160
+ f.write(f"{v}: {bones_name_list.count(v)}/{len(character_list)}\n")
character_unposed.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ./character/06caf212ded22a78500c06ebf372c9bb.fbx
2
+ ./character/08f7e724f32af241e56a9244c2f37b43.fbx
3
+ ./character/0a29fafad2ca23eba1787e20894ea8f6.fbx
4
+ ./character/1f6a7214d5f9eee30f4da837ad0db9a9.fbx
5
+ ./character/216f6676c0df33582682a270735a0bda.fbx
6
+ ./character/3c21546cb958a3daba75704b232b7e4b.fbx
7
+ ./character/3ec1224ed7c692d1e83a4cdfc2f5340b.fbx
8
+ ./character/525795a33ca1026996b5ca009d61e263.fbx
9
+ ./character/5bf474106308ccb071045e9579ca95e5.fbx
10
+ ./character/69c3f460dcf1f1f97942d5dafaac572d.fbx
11
+ ./character/73cd22e7123f4c8e78ffc11ad5fbbc29.fbx
12
+ ./character/75a7bced986dc088580ecbe09e1c8590.fbx
13
+ ./character/932216e3a518b0468f18bbb824ee6fa5.fbx
14
+ ./character/9882611aba55c935f071e41769da7b99.fbx
15
+ ./character/9a3c048709538dfbe0be943c9fae3d62.fbx
16
+ ./character/a4ce3af02c103b2e9b78b9b14e7a01a3.fbx
17
+ ./character/b6e2f4dbb404550f7c05e5158c45f979.fbx
18
+ ./character/b9ae94869ab838ee63cf92990211e525.fbx
19
+ ./character/cdf89c5c4430cbc672e0f61c78797d39.fbx
20
+ ./character/e5e1eccee079207473fafb1c163e2272.fbx
character_verts.json ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "0510032b674ce33343c2e058ef52e8c5": 26790,
3
+ "06caf212ded22a78500c06ebf372c9bb": 21796,
4
+ "079f3ee7c8d748481707ca78c95750ac": 14267,
5
+ "08ed9e6576433de9fb72baae34d482b6": 25340,
6
+ "08f7e724f32af241e56a9244c2f37b43": 27341,
7
+ "098424150eb08fb107185646afaeee83": 7482,
8
+ "0a29fafad2ca23eba1787e20894ea8f6": 18922,
9
+ "0b69ca9d9cd64f4c061659f29956e297": 6557,
10
+ "0eb7402a9104734d873599c7f9f01c3d": 7865,
11
+ "0fa8427ca1b7b2f410e893daa42df16c": 7825,
12
+ "123d7c7f828741681ffed14eacaf606d": 8014,
13
+ "19b740666ef33a06abf265235d8281a0": 8136,
14
+ "1c679b4220a9b78133db6c49f59ca65c": 4194,
15
+ "1f6a7214d5f9eee30f4da837ad0db9a9": 35128,
16
+ "216f6676c0df33582682a270735a0bda": 14442,
17
+ "222261b7a837ccdf5db5ea086430d4c7": 17272,
18
+ "258580e0c4983768c0233dca33157732": 6109,
19
+ "27de3b0b89d27fa7e654955765e40d3b": 8574,
20
+ "28069e1e9f570cc90128fe1241343875": 6234,
21
+ "2d925ffeafc887cf96d22d272e6a87cd": 5703,
22
+ "32db57cc0f9c3ee01c22924512d56283": 6294,
23
+ "39967d464dd297954f89d06fb587045f": 7870,
24
+ "3c21546cb958a3daba75704b232b7e4b": 31440,
25
+ "3e911fa9c30c9a00a9de31409095cd57": 5006,
26
+ "3ec1224ed7c692d1e83a4cdfc2f5340b": 29352,
27
+ "4c989f8d4d0b9c1e6e096f21719fd09d": 4858,
28
+ "4cd9c2951759527d10bb7916baa80ca2": 5750,
29
+ "4fd247797b4f3653d5c2a8b335b03d29": 6112,
30
+ "51b67149e52d48e2442f1db223f59ba9": 22183,
31
+ "51d19d5e4cd1c8c8d75a97f078ff9476": 33977,
32
+ "51e1e51887023725371b27fd0cb3dca1": 8094,
33
+ "525795a33ca1026996b5ca009d61e263": 25251,
34
+ "57f74ab8c6de76c82d53e3257a6778e4": 29379,
35
+ "5bf474106308ccb071045e9579ca95e5": 31515,
36
+ "5cd6b5bf8b921a2cb0e4ce71d685ff90": 2654,
37
+ "6987df4026a93126ed745db3b5f2fbcf": 7919,
38
+ "69c3f460dcf1f1f97942d5dafaac572d": 14634,
39
+ "73cd22e7123f4c8e78ffc11ad5fbbc29": 29056,
40
+ "75a7bced986dc088580ecbe09e1c8590": 30736,
41
+ "761718127eb6d283b7bf7076bca62b78": 23243,
42
+ "761b5a0cf1945d0089f00686beb41f49": 5550,
43
+ "7dcd7c3eb5f2fb50caf6ae6896e9464c": 24481,
44
+ "7dd7bf41bda834a9500b2ff93705ad02": 18453,
45
+ "7faa53355e944ba38be5a4b7de179290": 24850,
46
+ "7fd6d88afe76663358a61901be3c6c15": 12456,
47
+ "8044e1503d3549a144741dc1878d414a": 2374,
48
+ "81f41f90717b8383b3d2fffb18f95d07": 29192,
49
+ "831a835d6cca7f50fee848116a1e0a6b": 4260,
50
+ "83828f0fe01d389df691a0b8f2e19b95": 17879,
51
+ "840c84726b0f55c9fa7235074394fd6a": 10754,
52
+ "85bc8db2b257cf836c186593aa8a1fce": 2410,
53
+ "893b3e8f4a0cea4255ccee36633756e7": 29038,
54
+ "8b6cd9d3a78bdf860d3d06b58715b310": 32697,
55
+ "8dfaf7ace7778cd25a6b181d98cd7e77": 19404,
56
+ "93025f9cd069b342a20217702a522b54": 12465,
57
+ "932216e3a518b0468f18bbb824ee6fa5": 34437,
58
+ "9882611aba55c935f071e41769da7b99": 27963,
59
+ "9a24bbb67c6dac80b1e83238982fc9bd": 30535,
60
+ "9a3c048709538dfbe0be943c9fae3d62": 30724,
61
+ "9e33cfb2c5443136600e393a4aa2e7f1": 2414,
62
+ "a0641e810f7d000c8ca59e7224c9d796": 5837,
63
+ "a3d6df0a1670bd02cc732c8137427dbe": 7397,
64
+ "a4ce3af02c103b2e9b78b9b14e7a01a3": 31611,
65
+ "a688cfa656103db0d2acb62c8d2d9144": 7171,
66
+ "aa03d7c7297f3864ce77600f5f940606": 2931,
67
+ "aed9922313c4b66e9b3ec1bc6dec06a8": 24746,
68
+ "b0ce097858de7591269ef24996ad0808": 7512,
69
+ "b1bf836b9d040760b79534e30a8cba76": 3711,
70
+ "b1ca6a6e9f48e9a7e4c2a92eb1837e37": 10273,
71
+ "b1eea1f10e0a85ad8f6b8c8cc5882cf8": 30840,
72
+ "b45062da94f349e53a67b0028539deac": 3985,
73
+ "b6e2f4dbb404550f7c05e5158c45f979": 28745,
74
+ "b78413c2dc7908bf952a609b24569807": 28511,
75
+ "b9ae94869ab838ee63cf92990211e525": 17986,
76
+ "bad88bdd65811e64a724b49cb0e505a5": 5890,
77
+ "bc9c26c1c3653c81d3d35261cd696839": 5209,
78
+ "bd0a2e2cc4da1a2e566e6dd98402edfb": 9285,
79
+ "bd5584dc8872126d57d969aa07ec09a6": 5851,
80
+ "c3b24f5c406ef4c09c2c07ae65dba0e0": 27850,
81
+ "c4d054e07d59a8b2224e07ab2fbf505b": 6675,
82
+ "c92d8db4a32b4606fb6258a385f5fcd1": 6596,
83
+ "cb8b934b054940623581dfaf5d9fd468": 5330,
84
+ "cdf89c5c4430cbc672e0f61c78797d39": 18705,
85
+ "cf65a1c8be43a9c90570b99a0b702aff": 12430,
86
+ "cf7e9c498421b75e2df678adc5284783": 14241,
87
+ "d2f2e35da6c1fcca872fccf83fef9a5a": 7882,
88
+ "e000b51a0c9526a75f155bc925722db3": 16211,
89
+ "e426198d78eaf096bf1e38ffdaa9af17": 4887,
90
+ "e4280b007901ef1c87a68be75323ab39": 4224,
91
+ "e5e1eccee079207473fafb1c163e2272": 25240
92
+ }
mixamo_download_script.js ADDED
@@ -0,0 +1,649 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ INSTRUCTIONS:
3
+ 1. Set your browser NOT to ask where to save files on each download (else you will be bombarded with "Save As" prompts!)
4
+ 2. Navigate to https://www.mixamo.com/#/?page=1&type=Motion%2CMotionPack&limit=96
5
+ 3. For best results, set on-page thumbnails to "small" and "non-animated" (click the little gear icon)
6
+ 4. Set to display 96 items per page (you can also enter 100 in the url, but it makes not much of a difference)
7
+ 5. IMPORTANT: Before you run the script, make sure to manually download one sample animation - the page will remember your settings (if you don't do this, it will use defaults, i.e. it will download the character with each anim)
8
+ 6. Set one (and only 1) of the first 6 variables to TRUE, in order to select the variant you want to download (regular, in place, root) by default it will download only the regular version (without inplace option).
9
+ 7. Open the browser console (Shift+Ctrl+J in Chrome) and paste the entirety of the code
10
+ 8. Hit Enter and wait for it to finish (can take some time)
11
+
12
+ NOTE: the script skips all of mixamos animation "packs", as those are duplicates (their content is available as seperate animations), but mostly because it messed up point no. 5
13
+
14
+ It is RECOMMENDED to use the variables below in the following WORKFLOW:
15
+ (1) set the first variable (Setup_DownloadAllExceptInPlace) from false to true,
16
+ (2) run the script, (3) move all downloaded animations to folder named "\regular",
17
+ (4) set the first variable back to false and the second to true,
18
+ (5) run the script again (make sure to open in a fresh tab and don't forget to repeat 5.),
19
+ (6) move all downloaded animations to folder named "\inplace",
20
+ (7) repeat for 3rd variable to have the entire set, or all 6 to have also a mirrored version.
21
+
22
+ You should end up with 2061 regular animations and 384 in root and inplace each.
23
+
24
+ TROUBLESHOOTING
25
+ With slower connections it is possible that your download queue will start to choke and leave downloads unfinished.
26
+ If that happens, reduce the per page amount of animations from 96 to 24, or manually enter 10 in the URL (like this) - on each page turn the script waits for a couple of seconds to help with the above.
27
+
28
+ For offline browsing purposes, here's a download with all thumbnail:
29
+ Here are the Thumbnails:
30
+ MixamoThumbnails.7z (523.28 MB)
31
+ (I've been made aware that the host uses pesky popup ads and such, keep that in mind or use an adblocker or better yet, a download manager, I highly recommend JDownloader2).
32
+
33
+ Have fun!
34
+ */
35
+
36
+ /* these variables are there to allow running the script in multiple passes so the animations can then be grouped manually into organized folders */
37
+ var Setup_DownloadAllExceptInPlace = true; // example folder: \regular
38
+ var Setup_DownloadOnlyInPlace = false; // example folder: \inplace
39
+ var Setup_DownloadOnlyRoot = false; // example folder: \root
40
+
41
+ var Setup_DownloadOnlyInPlace_Mirrored = false; // example folder: \mirrored\inplace
42
+ var Setup_DownloadAllExceptInPlace_Mirrored = false; // example folder: \mirrored\regular
43
+ var Setup_DownloadOnlyRoot_Mirrored = false; // example folder: \mirrored\root
44
+
45
+
46
+ /* Debug Settings */
47
+
48
+ var debugVerbose = true; // write messages to console
49
+ var debugMaxIndex = 0; // will stop after x anims, 0 = unlimited
50
+ var debugStopAfterPage = 999;
51
+ var debugNoPageTurn = false; // will finish on current page
52
+ var setupGlobalTimeOffset = 0; // all timers will be increased by x (increase if script has to retry often)
53
+ var setupTimeModifier = 2; // all timers will multiply by x (increase if script has to retry often)
54
+ var setupDefaultDelay = 500; // default time step when adding anims to assets (increase when encountering problems)
55
+ var setupPlaySounds = true; // play sound notifications
56
+ var setupBeepOnAdd = false; // notification when an animation has been added to assets
57
+ var setupBeepOnPage = true; // notification when changing page
58
+ var TimeToReloadPage = 10000;
59
+
60
+ /* Do NOT change values below unless you know what you are doing - internal vars and setup constants*/
61
+
62
+ var pageURL = "https://www.mixamo.com/#/?type=Motion%2CMotionPack"; // base url without page and limit data
63
+ var setupElementID_Products = "product";
64
+ var setupElementID_Download = "btn-block btn btn-primary";
65
+ var setupElementID_DownloadConfirm = "btn btn-primary";
66
+ var setupElementID_InPlace = "inplace";
67
+ var setupElementID_Mirror = "mirror";
68
+ var setupElementID_Products = "product";
69
+ var setupElementID_Pagination = ".pagination li:nth-last-child(2) a";
70
+ var setupElementID_DownloadCaption = "Download";
71
+ var DownloadPending_Regular = downloadRegularVariant;
72
+ var DownloadPending_Mirror = downloadMirrorVariant;
73
+ var DownloadPending_InPlace = downloadInPlaceVariant;
74
+ var DownloadPending_InPlaceMirror = downloadInPlaceMirrorVariant;
75
+ var timeEnd = 0, timeStart = 0;
76
+ var scriptPaused = true;
77
+ var index = -1;
78
+ var debugFailedStart = 0;
79
+ var pageNum = geUrlPageNum();
80
+ var itemsPerPage = geUrlLimit();
81
+ var NumOfFilesProcessed = 0;
82
+ var buttonClicked = 0;
83
+ var retryCounter = 0;
84
+ var button = document.querySelector( "setupElementID_AddToAssets" );
85
+ var items = document.getElementsByClassName( setupElementID_Products );
86
+
87
+ var pageMax = 5; // limit pages
88
+ var downloadRegularVariant = true; // no checkboxes set, regular version, i.e. root or default
89
+ var download_RootExclude = false; // affects "downloadRegularVariant" only, ignores anims with "in place" option
90
+ var download_RootExclussive = false; // affects "downloadRegularVariant" only, ignores anims without "in place" option
91
+ var download_RootMirrored = false; // affects "downloadRegularVariant" only, forces mirror, meant to be used with "download_RootExclu[de|ssive]"
92
+ var downloadMirrorVariant = true; // will check only "mirror" and download a separate version
93
+ var downloadInPlaceVariant = true; // set In Place to true
94
+ var downloadInPlaceMirrorVariant = true; // In Place and mirrored to true
95
+
96
+ function DownloadAllExceptInPlace(){
97
+ //A. downloadRegularVariant + download_RootExclude // download all animations that have no INPLACE checkbox \regular
98
+ downloadRegularVariant = true;
99
+ download_RootExclude = true;
100
+ download_RootExclussive = false;
101
+ download_RootMirrored = false;
102
+ downloadMirrorVariant = false;
103
+ downloadInPlaceVariant = true;
104
+ downloadInPlaceMirrorVariant = false;
105
+ }
106
+
107
+ function DownloadAllExceptInPlace_Mirrored(){
108
+ //B. A. + download_RootMirrored // downloads A., but mirrored \regular_mirrored
109
+ downloadRegularVariant = true;
110
+ download_RootExclude = true;
111
+ download_RootExclussive = false;
112
+ download_RootMirrored = true;
113
+ downloadMirrorVariant = false;
114
+ downloadInPlaceVariant = false;
115
+ downloadInPlaceMirrorVariant = false;
116
+ }
117
+
118
+ function DownloadOnlyInPlace(){
119
+ //C. downloadInPlaceVariant // all anims w/ a INPLACE checkbox (set true) \inplace
120
+ downloadRegularVariant = false;
121
+ download_RootExclude = false;
122
+ download_RootExclussive = false;
123
+ download_RootMirrored = false;
124
+ downloadMirrorVariant = false;
125
+ downloadInPlaceVariant = true;
126
+ downloadInPlaceMirrorVariant = false;
127
+ }
128
+
129
+ function DownloadOnlyInPlace_Mirrored(){
130
+ // D. downloadInPlaceMirrorVariant // same as C., but morrored \inplace_mirrored
131
+ downloadRegularVariant = false;
132
+ download_RootExclude = false;
133
+ download_RootExclussive = false;
134
+ download_RootMirrored = false;
135
+ downloadMirrorVariant = false;
136
+ downloadInPlaceVariant = false;
137
+ downloadInPlaceMirrorVariant = true;
138
+ }
139
+
140
+ function DownloadOnlyRoot(){
141
+ //E. downloadRegularVariant + download_RootExclussive // download only anims with INPLACE checkbox (left to false) \root
142
+ downloadRegularVariant = true;
143
+ download_RootExclude = false;
144
+ download_RootExclussive = true;
145
+ download_RootMirrored = false;
146
+ downloadMirrorVariant = false;
147
+ downloadInPlaceVariant = false;
148
+ downloadInPlaceMirrorVariant = false;
149
+ }
150
+
151
+ function DownloadOnlyRoot_Mirrored(){
152
+ //F. E. + download_RootMirrored // E. mirrored \root_mirrored
153
+ downloadRegularVariant = true;
154
+ download_RootExclude = false;
155
+ download_RootExclussive = true;
156
+ download_RootMirrored = true;
157
+ downloadMirrorVariant = false;
158
+ downloadInPlaceVariant = false;
159
+ downloadInPlaceMirrorVariant = false;
160
+ }
161
+
162
+ function geUrlLimit(){
163
+ var result = getUrlVars()["limit"];
164
+ if (result && debugVerbose) console.log(result);
165
+ else {
166
+ if (debugVerbose) console.log("[DEBUG] geUrlLimit :: param LIMIT not found.");
167
+ result = "96";
168
+ }
169
+ return result;
170
+ }
171
+
172
+ function isAnimPack(){
173
+ var str = getAnimName();
174
+ str = str.toLowerCase();
175
+ var n = str.search(" pack");
176
+ return ( n > -1 );
177
+ }
178
+
179
+ var DownloadPending_Any = true;
180
+ function incIndex(){
181
+ if (debugVerbose) console.log("[DEBUG] incIndex :: Start; index:",index);
182
+ ++index;
183
+ ++NumOfFilesProcessed;
184
+ buttonClicked = 0;
185
+
186
+ DownloadPending_Regular = downloadRegularVariant;
187
+ DownloadPending_Mirror = downloadMirrorVariant;
188
+ DownloadPending_InPlace = downloadInPlaceVariant;
189
+ DownloadPending_InPlaceMirror = downloadInPlaceMirrorVariant;
190
+ DownloadPending_Any = true;
191
+
192
+ if (debugVerbose) console.log("[DEBUG] incIndex :: End; index:",index);
193
+
194
+ if (onProcessElement())
195
+ setTimeout(processElement, 2000 );
196
+ }
197
+
198
+ function getUrlVars() {
199
+ var vars = {};
200
+ var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi,
201
+ function(m,key,value) {
202
+ vars[key] = value;
203
+ });
204
+ return vars;
205
+ }
206
+
207
+ function geUrlPageNum(){
208
+ var result = getUrlVars()["page"];
209
+ if (result && debugVerbose) console.log(result);
210
+ else {
211
+ if (debugVerbose) console.log("[DEBUG]param PAGE not found.");
212
+ result = 1;
213
+ }
214
+ return result;
215
+ }
216
+
217
+ function timeMod( time1 ){
218
+ var baseTime = time1 * setupDefaultDelay;
219
+ var t = ((baseTime)*setupTimeModifier) + setupGlobalTimeOffset;
220
+ if (t < baseTime*0.1) t = baseTime*0.1;
221
+ if (t > baseTime*10) t = baseTime*10;
222
+ return t;
223
+ }
224
+
225
+ function reloadPage() {
226
+ if (debugVerbose) console.log("[DEBUG] reloadPage :: Start; index:",index);
227
+ scriptPaused = true;
228
+
229
+ if (pageNum >= debugStopAfterPage) {
230
+ return;
231
+ }
232
+
233
+
234
+ var newUrl = "";
235
+ newUrl = pageURL + "&limit=" + itemsPerPage + "&page=" + pageNum.toString();
236
+
237
+ if (debugVerbose) console.log("[DEBUG] reloadPage :: ",newUrl);
238
+ document.location.href = newUrl;
239
+
240
+ setTimeout( mixamoScript, 2000 );
241
+ }
242
+
243
+ function onFinish(){
244
+ /*
245
+ timeEnd = Date.now();
246
+ scriptPaused = true;
247
+ if (debugVerbose) console.log("[DEBUG]MixamoScript: Added (", numAssetsAdded, ")" );
248
+
249
+ if (setupBeepOnFinish) {
250
+ soundOnFinish();
251
+ setTimeout(promptOnEnd, 2000);
252
+ } else setTimeout(promptOnEnd, 0);
253
+ */
254
+ }
255
+
256
+ if (!audioCtx) var audioCtx = new (window.AudioContext || window.webkitAudioContext || window.audioContext);
257
+ function beep(duration, frequency, volume, type, callback) {
258
+ if (!setupPlaySounds) return;
259
+
260
+ var oscillator = audioCtx.createOscillator();
261
+ var gainNode = audioCtx.createGain();
262
+
263
+ oscillator.connect(gainNode);
264
+ gainNode.connect(audioCtx.destination);
265
+
266
+ if (volume){gainNode.gain.value = volume;};
267
+ if (frequency){oscillator.frequency.value = frequency;}
268
+ if (type){oscillator.type = type;}
269
+ if (callback){oscillator.onended = callback;}
270
+
271
+ oscillator.start();
272
+ setTimeout(function(){oscillator.stop()}, (duration ? duration : 500));
273
+ }
274
+
275
+ function soundOnPageEnd(){
276
+
277
+ setTimeout(function(){ beep(500, 500, 0.060, "triangle") }, 0);
278
+ setTimeout(function(){ beep(500, 550, 0.035, "triangle") }, 600);
279
+ setTimeout(function(){ beep(500, 600, 0.020, "triangle") }, 1200);
280
+ setTimeout(function(){ beep(500, 650, 0.005, "triangle") }, 1800);
281
+ }
282
+
283
+ function beepOnAdd(){
284
+ if (debugVerbose) console.log("[DEBUG] beepOnAdd :: Start; index:",index);
285
+ beep(225, 200, 0.3, "triangle");
286
+ }
287
+
288
+
289
+ /**/
290
+ function printToLogCurrItems(){
291
+
292
+ }
293
+
294
+ function onEndOfPage() {
295
+ if (debugVerbose) console.log("[DEBUG] onEndOfPage :: Start; index:",index);
296
+ scriptPaused = true;
297
+
298
+ var t = 0;
299
+ if (setupBeepOnPage) {
300
+ t = 1000;
301
+ setTimeout(soundOnPageEnd, 0);
302
+ }
303
+
304
+ //printToLogCurrItems();
305
+ if (pageNum >= debugStopAfterPage) {
306
+ setTimeout( onFinish, 2000 );
307
+ if (debugVerbose) console.log("[DEBUG] onEndOfPage_Assets :: Start; pageNum:",pageNum,"; debugStopAfterPage:",debugStopAfterPage);
308
+ return;
309
+ } else {
310
+ if (!debugNoPageTurn) {
311
+ index = 0;
312
+ ++pageNum;
313
+ setTimeout(reloadPage, TimeToReloadPage);
314
+ }
315
+ }
316
+
317
+ }
318
+
319
+ function isDownloadInProgress(){
320
+ var elements = document.getElementsByClassName( "progress-bar" );
321
+ if (elements && elements.length>0)
322
+ {
323
+ console.log("[DEBUG] Download In Progress");
324
+ return true;
325
+ } else {
326
+ console.log("[DEBUG] Download Not In Progress");
327
+ return false;
328
+ }
329
+ }
330
+
331
+ function onProcessElement() {
332
+ if (debugVerbose) console.log("[DEBUG] onProcessElement :: start; index:",index);
333
+
334
+ if (!items || items.length == 0) {
335
+ if (debugVerbose) console.log("[DEBUG] onProcessElement :: items; index:",index);
336
+ items = document.getElementsByClassName( setupElementID_Products );
337
+ }
338
+ if (!button) {
339
+ if (debugVerbose) console.log("[DEBUG] onProcessElement :: button; index:",index);
340
+ //button = document.querySelector( setupElementID_AddToAssets );
341
+ var buttons = document.getElementsByClassName( setupElementID_Download );
342
+ if (buttons && buttons.length>0)
343
+ button = buttons[0];
344
+ }
345
+ if (items.length != 0) {
346
+ // Next Page
347
+ if(index >= items.length) {
348
+ // end of page
349
+ onEndOfPage();
350
+ return true;
351
+ }
352
+ items[index].click();
353
+
354
+ if (debugVerbose) console.log("[DEBUG] onProcessElement :: Clicked");
355
+ return true;
356
+ }
357
+
358
+ return false;
359
+ }
360
+
361
+ function getAnimName(){
362
+ if (debugVerbose) console.log("[DEBUG] getAnimName :: Start; index:",index);
363
+ var element = document.getElementsByClassName( "text-center h5" );
364
+ if (element && element.length>0) {
365
+ if (debugVerbose) console.log("[DEBUG] getAnimName :: name:",element[0].textContent,"; Start; index:",index);
366
+ return element[0].textContent;
367
+ }
368
+ if (debugVerbose) console.log("[DEBUG] getAnimName :: Failed; Start; index:",index);
369
+ return "[]";
370
+ }
371
+
372
+ function confirmDownload(){
373
+ if (debugVerbose) console.log("[DEBUG] confirmDownload :: start; index:",index);
374
+ var buttons = document.getElementsByClassName( setupElementID_DownloadConfirm );
375
+ if (buttons && buttons.length>1) {
376
+ buttons[1].click();
377
+
378
+ if (debugVerbose) console.log("[DEBUG] confirmDownload :: Button Clicked");
379
+
380
+ setTimeout( processElementEx, 1000 );
381
+ } else if (debugVerbose) console.log("[DEBUG] confirmDownload :: Button Not Found");
382
+ }
383
+
384
+ function initAnimDownload() {
385
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload :: Start; Index:",index);
386
+
387
+ var currAnim = getAnimName();
388
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload :: Anim: ",currAnim,"; index:",index);
389
+
390
+ // main button is ready to add asset)
391
+ if (button.textContent == setupElementID_DownloadCaption) {
392
+ if (buttonClicked == 0) {
393
+ button.click();
394
+
395
+ //++buttonClicked;
396
+ //++numAssetsAddedCurrPage;
397
+ if (setupBeepOnAdd) beepOnAdd();
398
+
399
+ setTimeout( confirmDownload, 1000);
400
+
401
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload :: Added To Assets; buttonClicked:",buttonClicked);
402
+ return true;
403
+ }
404
+ } else { // main button caption is something unexpected
405
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload :: button.textContent:",button.textContent);
406
+ return false;
407
+
408
+ }
409
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload :: end");
410
+ }
411
+
412
+ function checkElement(elementName, desiredState) {
413
+ var element = document.getElementsByName(elementName);
414
+ if (element.length != 0) {
415
+ if (element[0].checked != desiredState) {
416
+ if (debugVerbose) console.log("[DEBUG] checkElement :: Clicked; previous state:",element[0].checked,"; elementName:",elementName,"; desiredState:",desiredState);
417
+ element[0].click();
418
+ } else if (debugVerbose) console.log("[DEBUG] checkElement :: Element already has desired state; elementName:",elementName,"; desiredState:",desiredState);
419
+
420
+ return true;
421
+ }
422
+ if (debugVerbose) console.log("[DEBUG] checkElement :: Element not found; elementName:",elementName,"; desiredState:",desiredState);
423
+
424
+ return false;
425
+ }
426
+
427
+ function isElementChecked(elementName, desiredState) {
428
+ var element = document.getElementsByName(elementName);
429
+ if (element.length != 0) {
430
+ if (debugVerbose) console.log("[DEBUG] isElementChecked :: elementName: ",elementName,"; desiredState: ",desiredState,"; current state:",element[0].checked,"; items found: ",element.length);
431
+ if (element[0].checked != desiredState) {
432
+ if (debugVerbose) console.log("[DEBUG] isElementChecked :: return: 0");
433
+ return 0;
434
+ } else {
435
+ if (debugVerbose) console.log("[DEBUG] isElementChecked :: return: 1");
436
+ return 1;
437
+ }
438
+ }
439
+ if (debugVerbose) console.log("[DEBUG] isElementChecked :: Element not found; elementName:",elementName,"; desiredState:",desiredState);
440
+ return -1;
441
+ }
442
+
443
+ var waitingForDownloadToComplete = false;
444
+ function processElement() {
445
+ if (debugVerbose) console.log("[DEBUG] processElement :: start; index:",index);
446
+
447
+ if (isDownloadInProgress()) {
448
+ // give page time to prepare current download
449
+ waitingForDownloadToComplete = true;
450
+ setTimeout(processElement, 500 );
451
+ return;
452
+ }
453
+
454
+ if (waitingForDownloadToComplete === true){
455
+ // some extra time to complete downloading
456
+ waitingForDownloadToComplete = false;
457
+ setTimeout(processElement, 1000 );
458
+ return;
459
+ }
460
+
461
+ if (debugMaxIndex > 0 && NumOfFilesProcessed >= debugMaxIndex) {
462
+ if (debugVerbose) console.log("[DEBUG] processElement :: debugMaxIndex:",debugMaxIndex,"; onFinish");
463
+ onFinish();
464
+ return;
465
+ }
466
+
467
+ if ( scriptPaused ) return;
468
+
469
+ retryCounter = 0;
470
+
471
+ setTimeout(processElementEx, timeMod( 1 ));
472
+
473
+ if (debugVerbose) console.log("[DEBUG] processElement :: End");
474
+ }
475
+
476
+ function processElementEx(){
477
+ if (debugVerbose) {
478
+ console.log("[DEBUG] processElementEx :: DownloadPending_Regular: ",DownloadPending_Regular);
479
+ console.log("[DEBUG] processElementEx :: DownloadPending_Mirror: ",DownloadPending_Mirror);
480
+ console.log("[DEBUG] processElementEx :: DownloadPending_InPlace: ",DownloadPending_InPlace);
481
+ console.log("[DEBUG] processElementEx :: DownloadPending_InPlaceMirror: ",DownloadPending_InPlaceMirror);
482
+ }
483
+
484
+ if (!isAnimPack()) {
485
+ // download variants
486
+ if (DownloadPending_Regular) {
487
+ if (initAnimDownload_Regular() ) {
488
+ setTimeout(initAnimDownload, timeMod( 2 ) );
489
+ if (debugVerbose) console.log("[DEBUG] processElementEx :: call initAnimDownload");
490
+ } else {
491
+ setTimeout(processElementEx, timeMod( 1 ) );
492
+ if (debugVerbose) console.log("[DEBUG] processElementEx :: call processElementEx");
493
+ }
494
+ DownloadPending_Regular = false;
495
+ return;
496
+ } else if (DownloadPending_Mirror){
497
+ setTimeout(initAnimDownload_Mirror, timeMod( 1 ) );
498
+ if (debugVerbose) console.log("[DEBUG] processElementEx :: call initAnimDownload_Mirror");
499
+ return;
500
+ } else if (DownloadPending_InPlace){
501
+ setTimeout(initAnimDownload_InPlace, timeMod( 1 ) );
502
+ if (debugVerbose) console.log("[DEBUG] processElementEx :: call initAnimDownload_InPlace");
503
+ return;
504
+ } else if (DownloadPending_InPlaceMirror){
505
+ setTimeout(initAnimDownload_InPlaceMirror, timeMod( 1 ) );
506
+ if (debugVerbose) console.log("[DEBUG] processElementEx :: call initAnimDownload_InPlaceMirror");
507
+ return;
508
+ }
509
+ } else {
510
+ if (debugVerbose) console.log("[DEBUG] processElementEx :: skipping Pack");
511
+ }
512
+
513
+ if (debugVerbose) {
514
+ console.log("[DEBUG] processElementEx :: DownloadPending_Regular: ",DownloadPending_Regular);
515
+ console.log("[DEBUG] processElementEx :: DownloadPending_Mirror: ",DownloadPending_Mirror);
516
+ console.log("[DEBUG] processElementEx :: DownloadPending_InPlace: ",DownloadPending_InPlace);
517
+ console.log("[DEBUG] processElementEx :: DownloadPending_InPlaceMirror: ",DownloadPending_InPlaceMirror);
518
+ }
519
+
520
+ //DownloadPending_Any = false;
521
+ setTimeout(incIndex, timeMod(2) );
522
+ }
523
+
524
+ function initAnimDownload_Regular(){
525
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload_Regular :: Start");
526
+ r1 = isElementChecked(setupElementID_Mirror, false);
527
+ r2 = isElementChecked(setupElementID_InPlace, false);
528
+
529
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload_Regular :: R1: ",r1,", R2: ",r2);
530
+
531
+ if ((download_RootExclude===true && r2>-1) || (download_RootExclussive===true && r2<0)) {
532
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload_Regular :: download_RootExclude: ",download_RootExclude);
533
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload_Regular :: download_RootExclussive: ",download_RootExclussive);
534
+ return false;
535
+ }
536
+ if (download_RootMirrored===true) {
537
+ DownloadPending_Mirror = true;
538
+ return false;
539
+ } else {
540
+ return true;
541
+ }
542
+ }
543
+
544
+ function initAnimDownload_Mirror(){
545
+ r1 = isElementChecked(setupElementID_Mirror, true);
546
+ r2 = isElementChecked(setupElementID_InPlace, false);
547
+
548
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload_Mirror :: R1: ",r1,", R2: ",r2);
549
+
550
+ if (r1 === -1) {
551
+ // option n/a
552
+ DownloadPending_Mirror = false;
553
+ setTimeout(processElementEx, timeMod( 1 ) );
554
+ } else if (r1===0 || r2===0) {
555
+ // req options not yet not checked
556
+ if (r1===0) checkElement(setupElementID_Mirror, true);
557
+ if (r2===0) checkElement(setupElementID_InPlace, false);
558
+ setTimeout(processElementEx, timeMod( 1 ) );
559
+ } else {
560
+ // req met
561
+ setTimeout(initAnimDownload, timeMod( 2 ) );
562
+ DownloadPending_Mirror = false;
563
+ }
564
+ }
565
+
566
+ function initAnimDownload_InPlace(){
567
+ //r1 = isElementChecked(setupElementID_InPlace, true);
568
+ r1 = isElementChecked(setupElementID_InPlace, false);
569
+ r2 = isElementChecked(setupElementID_Mirror, false);
570
+
571
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload_InPlace :: R1: ",r1,", R2: ",r2);
572
+
573
+ if (r1 === -1) {
574
+ // option n/a
575
+ DownloadPending_InPlace = false;
576
+ setTimeout(processElementEx, timeMod( 1 ) );
577
+ } else if (r1===0 || r2===0) {
578
+ // req options not yet not checked
579
+ //if (r1===0) checkElement(setupElementID_InPlace, true);
580
+ if (r1===0) checkElement(setupElementID_InPlace, false);
581
+ if (r2===0) checkElement(setupElementID_Mirror, false);
582
+ setTimeout(processElementEx, timeMod( 1 ) );
583
+ } else {
584
+ // req met
585
+ setTimeout(initAnimDownload, timeMod( 2 ) );
586
+ DownloadPending_InPlace = false;
587
+ }
588
+ }
589
+
590
+ function initAnimDownload_InPlaceMirror(){
591
+ r1 = isElementChecked(setupElementID_InPlace, true);
592
+ r2 = isElementChecked(setupElementID_Mirror, true);
593
+
594
+ if (debugVerbose) console.log("[DEBUG] initAnimDownload_InPlaceMirror :: R1: ",r1,", R2: ",r2);
595
+
596
+ if (r1 === -1 || r2 === -1) {
597
+ // option n/a
598
+ DownloadPending_InPlaceMirror = false;
599
+ setTimeout(processElementEx, timeMod( 1 ) );
600
+ } else if (r1===0 || r2===0) {
601
+ // req options not yet not checked
602
+ if (r1===0) checkElement(setupElementID_InPlace, true);
603
+ if (r2===0) checkElement(setupElementID_Mirror, true);
604
+ setTimeout(processElementEx, timeMod( 1 ) );
605
+ } else {
606
+ // req met
607
+ setTimeout(initAnimDownload, timeMod( 2 ) );
608
+ DownloadPending_InPlaceMirror = false;
609
+ }
610
+ }
611
+
612
+ function mixamoScript(){
613
+ timeStart = Date.now();
614
+
615
+ if (debugVerbose) console.log("[DEBUG] mixamoScript :: Start; index:",index);
616
+ var pagination = document.querySelector(setupElementID_Pagination);
617
+ if (pagination) pageMax = parseInt(pagination.textContent, 10);
618
+ else pageMax = 1;
619
+
620
+ scriptPaused = false;
621
+ items = document.getElementsByClassName( setupElementID_Products );
622
+
623
+ index = -1;
624
+
625
+ // get products or retry later
626
+ if (items.length == 0) {
627
+ ++debugFailedStart;
628
+ if (debugFailedStart > 2) {
629
+ reloadPage();
630
+ return;
631
+ }
632
+ setTimeout(mixamoScript, 2000 );
633
+ return;
634
+ }
635
+ debugFailedStart = 0;
636
+
637
+ // process first element
638
+ incIndex();
639
+ //processElement();
640
+ }
641
+
642
+ if (Setup_DownloadAllExceptInPlace===true) DownloadAllExceptInPlace();
643
+ else if (Setup_DownloadAllExceptInPlace_Mirrored===true) DownloadAllExceptInPlace_Mirrored();
644
+ else if (Setup_DownloadOnlyInPlace===true) DownloadOnlyInPlace();
645
+ else if (Setup_DownloadOnlyInPlace_Mirrored===true) DownloadOnlyInPlace_Mirrored();
646
+ else if (Setup_DownloadOnlyRoot===true) DownloadOnlyRoot();
647
+ else if (Setup_DownloadOnlyRoot_Mirrored===true) DownloadOnlyRoot_Mirrored();
648
+
649
+ mixamoScript();
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ bpy
2
+ numpy
3
+ tqdm
try_import_blender.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ from glob import glob
4
+
5
+ import bpy
6
+ from tqdm import tqdm
7
+
8
+
9
+ class HiddenPrints:
10
+ def __init__(self, disable=False):
11
+ self.disable = disable
12
+
13
+ def __enter__(self):
14
+ if self.disable:
15
+ return
16
+ self._original_stdout = sys.stdout
17
+ sys.stdout = open(os.devnull, "w")
18
+
19
+ def __exit__(self, exc_type, exc_val, exc_tb):
20
+ if self.disable:
21
+ return
22
+ sys.stdout.close()
23
+ sys.stdout = self._original_stdout
24
+
25
+
26
+ if __name__ == "__main__":
27
+ input_dir = "."
28
+ character_list = sorted(glob(os.path.join(input_dir, "character", "*.fbx")))
29
+ # animation_list = sorted(glob(os.path.join(input_dir, "animation", "*.fbx")))
30
+ for filepath in tqdm(character_list, dynamic_ncols=True):
31
+ try:
32
+ with HiddenPrints():
33
+ bpy.ops.import_scene.fbx(filepath=filepath)
34
+ except Exception as e:
35
+ tqdm.write(filepath)
36
+ with open("character_old_fbx.txt", "a") as f:
37
+ f.write(f"{filepath}\n")
38
+
39
+ # https://aps.autodesk.com/developer/overview/fbx-converter-archives
40
+ # Manually convert and replace FBX in the txt