pyjallib 0.1.12__tar.gz → 0.1.13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. {pyjallib-0.1.12 → pyjallib-0.1.13}/.gitignore +11 -11
  2. {pyjallib-0.1.12 → pyjallib-0.1.13}/.python-version +1 -1
  3. {pyjallib-0.1.12 → pyjallib-0.1.13}/PKG-INFO +1 -1
  4. pyjallib-0.1.13/PRD/BIPPY_/353/260/224/354/235/264/355/214/250/353/223/234_/354/203/235/354/204/261_/353/266/204/354/204/235.md +440 -0
  5. pyjallib-0.1.13/PRD/PyJalLib_Mocap_Module_PRD.md +361 -0
  6. {pyjallib-0.1.12 → pyjallib-0.1.13}/pyproject.toml +1 -1
  7. pyjallib-0.1.13/ref/BIPPY.ms +1555 -0
  8. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/__init__.py +1 -1
  9. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/__init__.py +8 -4
  10. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/anim.py +84 -0
  11. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/autoClavicle.py +1 -1
  12. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/bip.py +89 -79
  13. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/bone.py +84 -22
  14. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/boneChain.py +19 -22
  15. pyjallib-0.1.13/src/pyjallib/max/fbxHandler.py +215 -0
  16. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/groinBone.py +3 -3
  17. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/header.py +10 -13
  18. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/hip.py +4 -4
  19. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/kneeBone.py +44 -20
  20. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/layer.py +12 -6
  21. pyjallib-0.1.13/src/pyjallib/max/mocap.py +376 -0
  22. pyjallib-0.1.13/src/pyjallib/max/rootMotion.py +639 -0
  23. pyjallib-0.1.13/src/pyjallib/max/toolManager.py +92 -0
  24. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/twistBone.py +5 -1
  25. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/volumeBone.py +2 -1
  26. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/perforce.py +34 -0
  27. pyjallib-0.1.13/tests/animNodeTest.py +24 -0
  28. pyjallib-0.1.13/tests/fbxExportTest.py +26 -0
  29. {pyjallib-0.1.12 → pyjallib-0.1.13}/uv.lock +1 -1
  30. {pyjallib-0.1.12 → pyjallib-0.1.13}/README.md +0 -0
  31. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/index.html +0 -0
  32. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/max.html +0 -0
  33. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/namePart.html +0 -0
  34. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/nameToPath.html +0 -0
  35. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/naming.html +0 -0
  36. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/namingConfig.html +0 -0
  37. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/p4module.html +0 -0
  38. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/perforce.html +0 -0
  39. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib/reloadModules.html +0 -0
  40. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/pyjallib.html +0 -0
  41. {pyjallib-0.1.12 → pyjallib-0.1.13}/docs/search.js +0 -0
  42. {pyjallib-0.1.12 → pyjallib-0.1.13}/generate_docs.ps1 +0 -0
  43. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/ConfigFiles/namingConfig.json +0 -0
  44. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/ConfigFiles/3DSMaxNamingConfig.json +0 -0
  45. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/ConfigFiles/Default_3DSMaxNamingConfig.json +0 -0
  46. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/align.py +0 -0
  47. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/constraint.py +0 -0
  48. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/helper.py +0 -0
  49. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/link.py +0 -0
  50. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/macro/jal_macro_align.py +0 -0
  51. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/macro/jal_macro_bone.py +0 -0
  52. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/macro/jal_macro_constraint.py +0 -0
  53. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/macro/jal_macro_helper.py +0 -0
  54. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/macro/jal_macro_link.py +0 -0
  55. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/macro/jal_macro_select.py +0 -0
  56. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/mirror.py +0 -0
  57. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/morph.py +0 -0
  58. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/name.py +0 -0
  59. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/select.py +0 -0
  60. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/skin.py +0 -0
  61. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/max/ui/Container.py +0 -0
  62. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/namePart.py +0 -0
  63. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/nameToPath.py +0 -0
  64. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/naming.py +0 -0
  65. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/namingConfig.py +0 -0
  66. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/py.typed +0 -0
  67. {pyjallib-0.1.12 → pyjallib-0.1.13}/src/pyjallib/reloadModules.py +0 -0
  68. {pyjallib-0.1.12 → pyjallib-0.1.13}/tests/autoclavicleTest.py +0 -0
  69. {pyjallib-0.1.12 → pyjallib-0.1.13}/tests/globalVarTest.py +0 -0
  70. {pyjallib-0.1.12 → pyjallib-0.1.13}/tests/moduleImportTest.py +0 -0
  71. {pyjallib-0.1.12 → pyjallib-0.1.13}/tests/p4Test.py +0 -0
  72. {pyjallib-0.1.12 → pyjallib-0.1.13}/tests/volumePreserveBoneTest.py +0 -0
@@ -1,12 +1,12 @@
1
- # Python-generated files
2
- __pycache__/
3
- *.py[oc]
4
- build/
5
- dist/
6
- wheels/
7
- *.egg-info
8
-
9
- # Virtual environments
10
- .venv/
11
-
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv/
11
+
12
12
  .vscode/
@@ -1 +1 @@
1
- 3.10.14
1
+ 3.10.14
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyjallib
3
- Version: 0.1.12
3
+ Version: 0.1.13
4
4
  Summary: A utility library for 3D game character development pipelines.
5
5
  Author-email: Dongseok Kim <jalnagakds@gmail.com>
6
6
  Requires-Python: >=3.10
@@ -0,0 +1,440 @@
1
+ # BIPPY MaxScript 바이패드(Biped) 생성 분석 문서
2
+
3
+ ## 개요
4
+
5
+ BIPPY는 3DS Max에서 FBX 파일의 본(bone) 데이터를 Biped 시스템으로 변환하는 MaxScript 도구입니다. 본 문서는 바이패드를 최초로 생성하는 핵심 메커니즘을 분석합니다.
6
+
7
+ ## 주요 함수
8
+
9
+ ### 1. assess_and_create_biped() 함수
10
+ **위치:** 576-703 라인
11
+ **목적:** FBX 본 구조를 분석하여 적절한 Biped를 생성
12
+
13
+ #### 1.1 바이패드 높이 계산
14
+ ```maxscript
15
+ bip_height = (distance FBX_convert_str.FBX_array[140] FBX_convert_str.FBX_array[13])*1.8
16
+ ```
17
+ - FBX_array[140]: 발목 본 위치
18
+ - FBX_array[13]: 목 본 위치
19
+ - 두 본 사이의 거리에 1.8을 곱하여 바이패드 전체 높이 결정
20
+
21
+ #### 1.2 본 구조 분석 및 카운팅
22
+
23
+ ##### 척추(Spine) 본 카운팅
24
+ ```maxscript
25
+ number_of_spines = 0
26
+ for c = 3 to 12 do (
27
+ if FBX_convert_str.FBX_array[c] != undefined do(
28
+ number_of_spines += 1
29
+ )
30
+ )
31
+ ```
32
+ - 인덱스 3-12: 척추 본들
33
+ - 존재하는 척추 본의 개수를 계산
34
+
35
+ ##### 다리(Leg) 본 카운팅
36
+ ```maxscript
37
+ number_of_legs = 0
38
+ for c = 137 to 140 do (
39
+ if FBX_convert_str.FBX_array[c] != undefined do(
40
+ number_of_legs += 1
41
+ )
42
+ )
43
+ ```
44
+ - 인덱스 137-140: 다리 본들
45
+ - 각 다리의 관절 개수 계산
46
+
47
+ ##### 꼬리(Tail) 본 카운팅
48
+ ```maxscript
49
+ number_of_tails = 0
50
+ for c = 165 to 189 do (
51
+ if FBX_convert_str.FBX_array[c] != undefined do(
52
+ number_of_tails += 1
53
+ )
54
+ )
55
+ ```
56
+
57
+ ##### 목(Neck) 본 카운팅
58
+ ```maxscript
59
+ number_of_necks = 0
60
+ for c = 13 to 37 do (
61
+ if FBX_convert_str.FBX_array[c] != undefined do(
62
+ number_of_necks += 1
63
+ )
64
+ )
65
+ ```
66
+
67
+ ##### 포니테일(Ponytail) 본 카운팅
68
+ ```maxscript
69
+ // 포니테일 1
70
+ number_of_ponytails1 = 0
71
+ for c = 39 to 63 do (
72
+ if FBX_convert_str.FBX_array[c] != undefined do(
73
+ number_of_ponytails1 += 1
74
+ )
75
+ )
76
+
77
+ // 포니테일 2
78
+ number_of_ponytails2 = 0
79
+ for c = 64 to 88 do (
80
+ if FBX_convert_str.FBX_array[c] != undefined do(
81
+ number_of_ponytails2 += 1
82
+ )
83
+ )
84
+ ```
85
+
86
+ ##### 손가락(Finger) 본 카운팅
87
+ ```maxscript
88
+ number_of_fingers = 0
89
+
90
+ // 각 손가락별로 체크 (엄지, 검지, 중지, 약지, 새끼)
91
+ if FBX_convert_str.FBX_array[93] != undefined do(
92
+ number_of_fingers += 1
93
+ )
94
+ // ... (다른 손가락들도 동일한 방식)
95
+ ```
96
+
97
+ ##### 발가락(Toe) 본 카운팅
98
+ ```maxscript
99
+ number_of_toes = 0
100
+ if FBX_convert_str.FBX_array[141] != undefined do(
101
+ number_of_toes += 1
102
+ )
103
+ // ... (다른 발가락들도 동일한 방식)
104
+ ```
105
+
106
+ ##### Props 본 체크
107
+ ```maxscript
108
+ number_of_prop1 = false
109
+ if FBX_convert_str.FBX_array[200] != undefined do(
110
+ number_of_prop1 = true
111
+ )
112
+ // Prop2, Prop3도 동일한 방식
113
+ ```
114
+
115
+ #### 1.3 바이패드 생성
116
+ ```maxscript
117
+ FBX_convert_str.bipObj = biped.createNew bip_height 0 [0,0,0] \
118
+ spineLinks:number_of_spines \
119
+ legLinks:number_of_legs \
120
+ tailLinks:number_of_tails \
121
+ ponyTail1Links:number_of_ponytails1 \
122
+ neckLinks:number_of_necks \
123
+ ponyTail2Links:number_of_ponytails2 \
124
+ fingers:number_of_fingers \
125
+ fingerLinks:number_of_fingerlinks \
126
+ toes:number_of_toes \
127
+ toeLinks:number_of_toelinks \
128
+ prop1Exists:number_of_prop1 \
129
+ prop2Exists:number_of_prop2 \
130
+ prop3Exists:number_of_prop3
131
+ ```
132
+
133
+ 이 코드는 3DS Max의 `biped.createNew` 명령을 사용하여:
134
+ - 계산된 높이로 바이패드 생성
135
+ - 위치: [0,0,0]
136
+ - 분석된 본 구조에 맞춰 각 부위별 관절 수 설정
137
+
138
+ #### 1.4 본 매핑 배열 생성
139
+ ```maxscript
140
+ local file = (getDir #userscripts + "\\Bippy/Bip.btf")
141
+ // BTF 파일에서 바이패드 본 이름들을 읽어옴
142
+ nam = FBX_convert_str.bipObj.name
143
+ FBX_convert_str.retarget_array[1] = FBX_convert_str.bipObj
144
+
145
+ for bI = 2 to FBX_convert_str.boneNum do(
146
+ name_Temp = "$'"+nam+" "+(readLine fileIO)+"'"
147
+ if FBX_convert_str.FBX_array[bI] != undefined do(
148
+ FBX_convert_str.retarget_array[bI] = temp = execute(name_Temp)
149
+ )
150
+ )
151
+ ```
152
+
153
+ ### 2. resize_biped() 함수
154
+ **위치:** 704-893 라인
155
+ **목적:** 생성된 바이패드를 FBX 본 크기에 맞춰 조정
156
+
157
+ #### 2.1 Figure Mode 활성화
158
+ ```maxscript
159
+ FBX_convert_str.biped_ctrl = FBX_convert_str.bipObj.transform.controller
160
+ FBX_convert_str.biped_ctrl.figureMode = true
161
+ ```
162
+
163
+ #### 2.2 각 부위별 크기 조정
164
+
165
+ ##### 루트(Root) 및 펠비스(Pelvis) 조정
166
+ ```maxscript
167
+ -- 루트 본의 위치와 회전 설정
168
+ biped.setTransform FBX_convert_str.retarget_array[1] #pos (FBX_convert_str.FBX_array[1].transform.pos) True
169
+ biped.setTransform FBX_convert_str.retarget_array[1] #rotation (FBX_convert_str.FBX_array[1].transform.rotation) True
170
+
171
+ -- 펠비스 크기 조정 (FBX_array[2]는 펠비스, FBX_array[137]은 왼쪽 다리)
172
+ local temp = (distance FBX_convert_str.FBX_array[2] FBX_convert_str.FBX_array[137])*2
173
+ biped.setTransform FBX_convert_str.retarget_array[2] #scale ([temp,temp,temp]) True
174
+ ```
175
+
176
+ ##### 척추(Spine) 본 조정
177
+ ```maxscript
178
+ -- 척추 본들 (인덱스 3-12, 최대 10개)
179
+ for i = 1 to 10 do(
180
+ if FBX_convert_str.FBX_array[i+2] != undefined do(
181
+ if FBX_convert_str.FBX_array[i+3] != undefined then (
182
+ -- 다음 척추 본이 있으면 그 사이의 거리 측정
183
+ local temp = distance FBX_convert_str.FBX_array[i+2] FBX_convert_str.FBX_array[i+3]
184
+ biped.setTransform FBX_convert_str.retarget_array[i+2] #scale ([temp,temp,temp]) True
185
+ )else(
186
+ -- 마지막 척추 본이면 목까지의 거리 측정 (FBX_array[13]은 첫 번째 목 본)
187
+ local temp = distance FBX_convert_str.FBX_array[i+2] FBX_convert_str.FBX_array[13]
188
+ biped.setTransform FBX_convert_str.retarget_array[i+2] #scale ([temp,temp,temp]) True
189
+ )
190
+ )
191
+ )
192
+ ```
193
+
194
+ ##### 목(Neck) 본 조정
195
+ ```maxscript
196
+ -- 목 본들 (인덱스 13-37, 최대 25개)
197
+ for i = 1 to 25 do(
198
+ if FBX_convert_str.FBX_array[i+12] != undefined do(
199
+ if FBX_convert_str.FBX_array[i+13] != undefined then (
200
+ -- 다음 목 본이 있으면 그 사이의 거리 측정
201
+ local temp = distance FBX_convert_str.FBX_array[i+12] FBX_convert_str.FBX_array[i+13]
202
+ biped.setTransform FBX_convert_str.retarget_array[i+12] #scale ([temp,temp,temp]) True
203
+ )else(
204
+ -- 마지막 목 본이면 머리까지의 거리 측정 (FBX_array[38]은 머리)
205
+ local temp = distance FBX_convert_str.FBX_array[i+12] FBX_convert_str.FBX_array[38]
206
+ biped.setTransform FBX_convert_str.retarget_array[i+12] #scale ([temp,temp,temp]) True
207
+ )
208
+ )
209
+ )
210
+ ```
211
+
212
+ ##### 포니테일 1 본 조정
213
+ ```maxscript
214
+ -- 첫 번째 포니테일 (인덱스 39-63)
215
+ for i = 1 to 25 do(
216
+ if FBX_convert_str.FBX_array[i+38] != undefined do(
217
+ if (FBX_convert_str.FBX_array[i+39] != undefined) and (FBX_convert_str.FBX_array[i+39].parent == FBX_convert_str.FBX_array[i+38]) then (
218
+ -- 다음 포니테일 본이 있고 부모-자식 관계가 맞으면
219
+ local temp = distance FBX_convert_str.FBX_array[i+38] FBX_convert_str.FBX_array[i+39]
220
+ biped.setTransform FBX_convert_str.retarget_array[i+38] #scale ([temp,temp,temp]) True
221
+ )else(
222
+ -- 그렇지 않으면 이전 본과의 거리 사용
223
+ local temp = distance FBX_convert_str.FBX_array[i+37] FBX_convert_str.FBX_array[i+38]
224
+ biped.setTransform FBX_convert_str.retarget_array[i+38] #scale ([temp,temp,temp]) True
225
+ )
226
+ )
227
+ )
228
+ ```
229
+
230
+ ##### 포니테일 2 본 조정
231
+ ```maxscript
232
+ -- 두 번째 포니테일 (인덱스 64-88)
233
+ for i = 1 to 25 do(
234
+ if FBX_convert_str.FBX_array[i+63] != undefined do(
235
+ if (FBX_convert_str.FBX_array[i+64] != undefined) and (FBX_convert_str.FBX_array[i+64].parent == FBX_convert_str.FBX_array[i+63]) then (
236
+ local temp = distance FBX_convert_str.FBX_array[i+63] FBX_convert_str.FBX_array[i+64]
237
+ biped.setTransform FBX_convert_str.retarget_array[i+63] #scale ([temp,temp,temp]) True
238
+ )else(
239
+ local temp = distance FBX_convert_str.FBX_array[i+62] FBX_convert_str.FBX_array[i+63]
240
+ biped.setTransform FBX_convert_str.retarget_array[i+63] #scale ([temp,temp,temp]) True
241
+ )
242
+ )
243
+ )
244
+ ```
245
+
246
+ ##### 왼쪽 팔(Left Arm) 조정
247
+ ```maxscript
248
+ -- 왼쪽 팔 (인덱스 89-92: 쇄골, 어깨, 팔꿈치, 손목)
249
+ for i = 1 to 3 do(
250
+ local temp = distance FBX_convert_str.FBX_array[i+88] FBX_convert_str.FBX_array[i+89]
251
+ biped.setTransform FBX_convert_str.retarget_array[i+88] #scale ([temp,temp,temp]) True
252
+ )
253
+
254
+ -- 왼쪽 손목에서 첫 번째 손가락까지 (있는 경우)
255
+ if FBX_convert_str.FBX_array[93] != undefined do(
256
+ local temp = distance FBX_convert_str.FBX_array[92] FBX_convert_str.FBX_array[93]
257
+ biped.setTransform FBX_convert_str.retarget_array[92] #scale ([temp,temp,temp]) True
258
+ )
259
+ ```
260
+
261
+ ##### 오른쪽 팔(Right Arm) 조정
262
+ ```maxscript
263
+ -- 오른쪽 팔 (인덱스 113-116: 쇄골, 어깨, 팔꿈치, 손목)
264
+ for i = 1 to 3 do(
265
+ local temp = distance FBX_convert_str.FBX_array[i+112] FBX_convert_str.FBX_array[i+113]
266
+ biped.setTransform FBX_convert_str.retarget_array[i+112] #scale ([temp,temp,temp]) True
267
+ )
268
+
269
+ -- 오른쪽 손목에서 첫 번째 손가락까지 (있는 경우)
270
+ if FBX_convert_str.FBX_array[117] != undefined do(
271
+ local temp = distance FBX_convert_str.FBX_array[116] FBX_convert_str.FBX_array[117]
272
+ biped.setTransform FBX_convert_str.retarget_array[116] #scale ([temp,temp,temp]) True
273
+ )
274
+ ```
275
+
276
+ ##### 왼쪽 다리(Left Leg) 조정
277
+ ```maxscript
278
+ -- 왼쪽 다리 (인덱스 137-140: 허벅지, 무릎, 발목)
279
+ for i = 1 to 3 do(
280
+ if FBX_convert_str.FBX_array[i+136] != undefined do(
281
+ if FBX_convert_str.FBX_array[i+137] != undefined then (
282
+ -- 다음 다리 본이 있으면 그 사이의 거리
283
+ local temp = distance FBX_convert_str.FBX_array[i+136] FBX_convert_str.FBX_array[i+137]
284
+ biped.setTransform FBX_convert_str.retarget_array[i+136] #scale ([temp,temp,temp]) True
285
+ )else(
286
+ -- 다음 본이 없으면 그 다음 본까지의 거리
287
+ local temp = distance FBX_convert_str.FBX_array[i+136] FBX_convert_str.FBX_array[i+138]
288
+ biped.setTransform FBX_convert_str.retarget_array[i+136] #scale ([temp,temp,temp]) True
289
+ )
290
+ )
291
+ )
292
+ ```
293
+
294
+ ##### 오른쪽 다리(Right Leg) 조정
295
+ ```maxscript
296
+ -- 오른쪽 다리 (인덱스 156-159: 허벅지, 무릎, 발목)
297
+ for i = 1 to 3 do(
298
+ if FBX_convert_str.FBX_array[i+155] != undefined do(
299
+ if FBX_convert_str.FBX_array[i+156] != undefined then (
300
+ local temp = distance FBX_convert_str.FBX_array[i+155] FBX_convert_str.FBX_array[i+156]
301
+ biped.setTransform FBX_convert_str.retarget_array[i+155] #scale ([temp,temp,temp]) True
302
+ )else(
303
+ local temp = distance FBX_convert_str.FBX_array[i+155] FBX_convert_str.FBX_array[i+157]
304
+ biped.setTransform FBX_convert_str.retarget_array[i+155] #scale ([temp,temp,temp]) True
305
+ )
306
+ )
307
+ )
308
+ ```
309
+
310
+ ##### 발 크기 계산 (주석 처리된 코드)
311
+ ```maxscript
312
+ -- 왼쪽 발 크기 계산 예제 (현재는 주석 처리됨)
313
+ local a = FBX_convert_str.FBX_array[141].pos -- 왼쪽 발가락 위치
314
+ local b = FBX_convert_str.FBX_array[140].pos -- 왼쪽 발목 위치
315
+ local d = [b.x,b.y,a.z] -- 발목의 X,Y와 발가락의 Z
316
+ local c = [a.x,a.y,b.z] -- 발가락의 X,Y와 발목의 Z
317
+ local lenght = distance c b -- 발의 길이
318
+ local height = distance b d -- 발의 높이
319
+ -- 실제 적용 코드는 주석 처리됨
320
+
321
+ -- 오른쪽 발도 동일한 방식으로 계산
322
+ ```
323
+
324
+ ##### 최종 위치 조정
325
+ ```maxscript
326
+ -- 첫 번째 척추 본의 위치를 FBX에 맞춰 재조정
327
+ biped.setTransform FBX_convert_str.retarget_array[3] #pos (FBX_convert_str.FBX_array[3].transform.pos) True
328
+
329
+ -- 모든 바이패드 본의 위치와 회전을 FBX 본에 맞춰 최종 조정
330
+ for b = 1 to local_number_of_items do (
331
+ biped.setTransform local_retarget_array[b] #pos (local_fbx_array[b].transform.pos) True
332
+ biped.setTransform local_retarget_array[b] #rotation (local_fbx_array[b].transform.rotation) True
333
+ -- 위치와 회전을 두 번 설정하여 확실하게 적용
334
+ biped.setTransform local_retarget_array[b] #pos (local_fbx_array[b].transform.pos) True
335
+ biped.setTransform local_retarget_array[b] #rotation (local_fbx_array[b].transform.rotation) True
336
+ )
337
+ ```
338
+
339
+ ##### Clavicle과 팔 본들의 위치 조정
340
+ BIPPY에서는 Clavicle(쇄골)과 팔 본들에 대한 별도의 위치 조정 루틴은 없습니다. 대신 **모든 본들의 위치와 회전이 일괄적으로 조정**됩니다:
341
+
342
+ ```maxscript
343
+ -- 모든 바이패드 본의 위치와 회전을 FBX 본에 맞춰 최종 조정
344
+ for b = 1 to local_number_of_items do (
345
+ -- 위치 설정
346
+ biped.setTransform local_retarget_array[b] #pos (local_fbx_array[b].transform.pos) True
347
+ -- 회전 설정
348
+ biped.setTransform local_retarget_array[b] #rotation (local_fbx_array[b].transform.rotation) True
349
+ -- 안정성을 위해 두 번 설정
350
+ biped.setTransform local_retarget_array[b] #pos (local_fbx_array[b].transform.pos) True
351
+ biped.setTransform local_retarget_array[b] #rotation (local_fbx_array[b].transform.rotation) True
352
+ )
353
+ ```
354
+
355
+ **Clavicle과 팔 본 인덱스 매핑:**
356
+ - **왼쪽 Clavicle**: FBX_array[89] → retarget_array[89]
357
+ - **왼쪽 Upper Arm**: FBX_array[90] → retarget_array[90]
358
+ - **왼쪽 Forearm**: FBX_array[91] → retarget_array[91]
359
+ - **왼쪽 Hand**: FBX_array[92] → retarget_array[92]
360
+ - **오른쪽 Clavicle**: FBX_array[113] → retarget_array[113]
361
+ - **오른쪽 Upper Arm**: FBX_array[114] → retarget_array[114]
362
+ - **오른쪽 Forearm**: FBX_array[115] → retarget_array[115]
363
+ - **오른쪽 Hand**: FBX_array[116] → retarget_array[116]
364
+
365
+ 이 과정에서 Clavicle과 팔 본들도 다른 모든 본들과 동일하게:
366
+ 1. **크기 조정 단계**: `distance` 함수로 본 간 거리를 측정하여 스케일 설정
367
+ 2. **위치 조정 단계**: FBX 본의 `transform.pos`를 바이패드 본에 직접 복사
368
+ 3. **회전 조정 단계**: FBX 본의 `transform.rotation`을 바이패드 본에 직접 복사
369
+
370
+ ##### Figure Mode 해제
371
+ ```maxscript
372
+ -- 크기 조정이 완료되면 Figure Mode 해제
373
+ FBX_convert_str.biped_ctrl.figureMode = false
374
+ ```
375
+
376
+ **주요 특징:**
377
+ - **거리 기반 스케일링**: 각 본 간의 3D 거리를 측정하여 바이패드 본의 스케일 설정
378
+ - **조건부 처리**: 본이 존재하지 않는 경우를 대비한 예외 처리
379
+ - **부모-자식 관계 확인**: 포니테일과 같은 체인 구조에서 올바른 연결 확인
380
+ - **일괄 변환**: 모든 본(Clavicle, 팔, 다리, 척추 등)이 동일한 로직으로 처리
381
+ - **이중 설정**: 위치와 회전을 두 번 설정하여 안정적인 적용 보장
382
+
383
+ ### 3. Map_biped_to_FBX() 함수
384
+ **위치:** 894 라인 이후
385
+ **목적:** 전체 바이패드 생성 프로세스 관리
386
+
387
+ #### 3.1 생성 모드 결정
388
+ ```maxscript
389
+ if(FBX_convert_str.using_Own_FIG == false) then (
390
+ assess_and_create_biped()
391
+ resize_biped()
392
+ )
393
+ else (
394
+ assess_and_create_biped()
395
+ // FIG 파일 로드 로직
396
+ biped.LoadFigFile FBX_convert_str.biped_ctrl FBX_convert_str.Fig_File
397
+ )
398
+ ```
399
+
400
+ 두 가지 모드:
401
+ 1. **자동 생성 모드**: FBX 구조 분석하여 자동으로 바이패드 생성
402
+ 2. **FIG 파일 모드**: 미리 저장된 FIG 파일을 사용하여 바이패드 구조 적용
403
+
404
+ ## FBX 본 인덱스 매핑
405
+
406
+ | 인덱스 범위 | 본 유형 | 설명 |
407
+ |-------------|---------|------|
408
+ | 1 | Root | 루트 본 |
409
+ | 3-12 | Spine | 척추 본들 |
410
+ | 13-37 | Neck | 목 본들 |
411
+ | 39-63 | Ponytail1 | 첫 번째 포니테일 |
412
+ | 64-88 | Ponytail2 | 두 번째 포니테일 |
413
+ | 89-92 | Left Arm | 왼쪽 팔 |
414
+ | 93-109 | Left Fingers | 왼쪽 손가락들 |
415
+ | 113-116 | Right Arm | 오른쪽 팔 |
416
+ | 117-133 | Right Fingers | 오른쪽 손가락들 |
417
+ | 137-140 | Left Leg | 왼쪽 다리 |
418
+ | 141-153 | Left Toes | 왼쪽 발가락들 |
419
+ | 156-159 | Right Leg | 오른쪽 다리 |
420
+ | 160-172 | Right Toes | 오른쪽 발가락들 |
421
+ | 165-189 | Tail | 꼬리 |
422
+ | 200-202 | Props | 프롭 오브젝트들 |
423
+
424
+ ## 생성 프로세스 요약
425
+
426
+ 1. **FBX 본 구조 분석**: 각 부위별 본의 존재 여부와 개수 파악
427
+ 2. **바이패드 높이 계산**: 발목-목 거리 기반으로 전체 높이 결정
428
+ 3. **바이패드 생성**: `biped.createNew`로 분석된 구조에 맞는 바이패드 생성
429
+ 4. **본 매핑**: BTF 파일에서 바이패드 본 이름들을 읽어와 매핑 배열 구성
430
+ 5. **크기 조정**: Figure Mode에서 각 본의 길이를 FBX 본에 맞춰 조정
431
+ 6. **애니메이션 적용**: 프레임별로 FBX 본의 transform을 바이패드에 복사
432
+
433
+ ## 주요 특징
434
+
435
+ - **동적 구조 분석**: FBX 파일의 본 구조를 자동으로 분석하여 적절한 바이패드 생성
436
+ - **유연한 매핑**: 다양한 캐릭터 구조(꼬리, 포니테일, 다양한 손가락 수 등)에 대응
437
+ - **정확한 크기 조정**: 실제 FBX 본 간의 거리를 측정하여 바이패드 크기 조정
438
+ - **배치 처리 지원**: 여러 FBX 파일을 일괄 처리할 수 있는 구조
439
+
440
+ 이 시스템은 모션 캡처 데이터를 3DS Max의 Biped 시스템으로 효율적으로 변환하기 위한 포괄적인 솔루션을 제공합니다.