pyjallib 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,418 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ 트위스트 뼈대(Twist Bone) 모듈 - 3ds Max용 트위스트 뼈대 생성 관련 기능 제공
6
+ 원본 MAXScript의 twistBone.ms를 Python으로 변환하였으며, pymxs 모듈 기반으로 구현됨
7
+ """
8
+
9
+ from pymxs import runtime as rt
10
+
11
+ # Import necessary service classes for default initialization
12
+ from .name import Name
13
+ from .anim import Anim
14
+ from .constraint import Constraint
15
+ from .bip import Bip
16
+
17
+
18
+ class TwistBone:
19
+ """
20
+ 트위스트 뼈대(Twist Bone) 관련 기능을 제공하는 클래스.
21
+ MAXScript의 _TwistBone 구조체 개념을 Python으로 재구현한 클래스이며,
22
+ 3ds Max의 기능들을 pymxs API를 통해 제어합니다.
23
+ """
24
+
25
+ def __init__(self, nameService=None, animService=None, constService=None, bipService=None):
26
+ """
27
+ 클래스 초기화.
28
+
29
+ Args:
30
+ nameService: 이름 처리 서비스 (제공되지 않으면 새로 생성)
31
+ animService: 애니메이션 서비스 (제공되지 않으면 새로 생성)
32
+ constService: 제약 서비스 (제공되지 않으면 새로 생성)
33
+ bipService: 바이페드 서비스 (제공되지 않으면 새로 생성)
34
+ """
35
+ self.name = nameService if nameService else Name()
36
+ self.anim = animService if animService else Anim()
37
+ # Ensure dependent services use the potentially newly created instances
38
+ self.const = constService if constService else Constraint(nameService=self.name)
39
+ self.bip = bipService if bipService else Bip(animService=self.anim, nameService=self.name) # Pass potentially new instances
40
+
41
+ # 표현식 초기화
42
+ self._init_expressions()
43
+
44
+ def _init_expressions(self):
45
+ """표현식 초기화"""
46
+ # 허벅지(Thigh) 표현식
47
+ self.thighExpression = (
48
+ "try(\n"
49
+ "TM=Limb.transform*inverse Limb.parent.transform\n"
50
+ "vector=normalize (cross -TM.row1 [1,0,0])\n"
51
+ "angle=acos -(normalize TM.row1).x\n"
52
+ "(quat 0 1 0 0)*(quat angle vector)*inverse TM.rotation)\n"
53
+ "catch((quat 0 0 0 1))"
54
+ )
55
+
56
+ # 허벅지 추가 표현식
57
+ self.thighExtraExpression = (
58
+ "try(\n"
59
+ "(Limb.transform*inverse LimbParent.transform).rotation\n"
60
+ ")catch((quat 0 0 0 1))"
61
+ )
62
+
63
+ # 종아리(Calf) 표현식
64
+ self.calfExpression = (
65
+ "try(\n"
66
+ "TM=Limb.transform*inverse Limb.parent.transform\n"
67
+ "vector=normalize (cross TM.row1 [1,0,0])\n"
68
+ "angle=acos (normalize TM.row1).x\n"
69
+ "TM.rotation*(quat -angle vector))\n"
70
+ "catch((quat 0 0 0 1))"
71
+ )
72
+
73
+ # 종아리 추가 표현식
74
+ self.calfExtraExpression = (
75
+ "try(dependson TB\n"
76
+ "TB.rotation.controller[1].value\n"
77
+ ")catch((quat 0 0 0 1))"
78
+ )
79
+
80
+ # 상완(Upper Arm) 표현식
81
+ self.upperArmExpression = (
82
+ "try(\n"
83
+ "TM=Limb.transform*inverse Limb.parent.transform\n"
84
+ "vector=normalize (cross TM.row1 [1,0,0])\n"
85
+ "angle=acos (normalize TM.row1).x\n"
86
+ "(quat angle vector)*inverse TM.rotation)\n"
87
+ "catch((quat 0 0 0 1))"
88
+ )
89
+
90
+ # 상완 추가 표현식
91
+ self.upperArmExtraExpression = (
92
+ "try(\n"
93
+ "(Limb.transform*inverse LimbParent.transform).rotation\n"
94
+ ")catch((quat 0 0 0 1))"
95
+ )
96
+
97
+ # 오른쪽 전완(Forearm) 표현식
98
+ self.rForeArmExpression = (
99
+ "try(\n"
100
+ "TM=(matrix3 [1,0,0] [0,0,-1] [0,1,0] [0,0,0])*Limb.transform*inverse Limb.parent.transform\n"
101
+ "vector=normalize (cross TM.row1 [1,0,0])\n"
102
+ "angle=acos (normalize TM.row1).x\n"
103
+ "TM.rotation*(quat -angle vector))\n"
104
+ "catch((quat 0 0 0 1))"
105
+ )
106
+
107
+ # 왼쪽 전완(Forearm) 표현식
108
+ self.lForeArmExpression = (
109
+ "try(\n"
110
+ "TM=(matrix3 [1,0,0] [0,0,1] [0,-1,0] [0,0,0])*Limb.transform*inverse Limb.parent.transform\n"
111
+ "vector=normalize (cross TM.row1 [1,0,0])\n"
112
+ "angle=acos (normalize TM.row1).x\n"
113
+ "TM.rotation*(quat -angle vector))\n"
114
+ "catch((quat 0 0 0 1))"
115
+ )
116
+
117
+ # 전완 추가 표현식
118
+ self.foreArmExtraExpression = (
119
+ "try(dependson TB\n"
120
+ "TB.rotation.controller[1].value\n"
121
+ ")catch((quat 0 0 0 1))"
122
+ )
123
+
124
+ def create_bones(self, inObj, inChild, inTwistNum, inExpression, inExtraExpression, inControllerLimb, inWeightVar):
125
+ """
126
+ 트위스트 뼈대 체인 생성
127
+
128
+ Args:
129
+ inObj: 시작 객체
130
+ inChild: 끝 객체
131
+ inTwistNum: 트위스트 뼈대 개수
132
+ inExpression: 기본 회전 표현식
133
+ inExtraExpression: 추가 회전 표현식
134
+ inControllerLimb: 컨트롤러 대상 팔다리
135
+ inWeightVar: 가중치
136
+
137
+ Returns:
138
+ 생성된 트위스트 뼈대 체인 배열
139
+ """
140
+ Limb = inObj
141
+ distanceVar = rt.distance(Limb, inChild)
142
+
143
+ TBExpression = inExpression
144
+ ControllerLimb = inControllerLimb
145
+ weightVar = inWeightVar
146
+
147
+ boneChainArray = []
148
+
149
+ # 첫 번째 트위스트 뼈대 생성
150
+ TwistBone = rt.BoneSys.createBone(
151
+ Limb.transform.position,
152
+ inChild.transform.position,
153
+ rt.Point3(0, 0, 1)
154
+ )
155
+ boneName = self.name.get_string(inObj.name) + "Twist"
156
+ TwistBone.name = self.name.replace_Index(boneName, "0")
157
+ TwistBone.transform = Limb.transform
158
+ TwistBone.parent = Limb
159
+ TwistBone.length = distanceVar / inTwistNum
160
+ TwistBone.width = distanceVar / 8
161
+ TwistBone.height = TwistBone.width
162
+ TwistBone.taper = 0
163
+ TwistBone.sidefins = False
164
+ TwistBone.frontfin = False
165
+ TwistBone.backfin = False
166
+
167
+ # 회전 컨트롤러 설정
168
+ TBRotListController = self.const.assign_rot_list(TwistBone)
169
+ TBController = rt.Rotation_Script()
170
+ TBController.addNode("Limb", ControllerLimb)
171
+ TBController.setExpression(TBExpression)
172
+
173
+ rt.setPropertyController(TBRotListController, "Available", TBController)
174
+ TBRotListController.delete(1)
175
+ TBRotListController.setActive(TBRotListController.count)
176
+ TBRotListController.weight[0] = weightVar
177
+
178
+ boneChainArray.append(TwistBone)
179
+
180
+ # 추가 회전 컨트롤러 설정
181
+ TBExtraController = rt.Rotation_Script()
182
+ if rt.matchPattern(inExtraExpression, pattern="*\nTB.*"):
183
+ TBExtraController.addNode("TB", TwistBone)
184
+ else:
185
+ TBExtraController.addNode("Limb", Limb)
186
+ TBExtraController.addNode("LimbParent", TwistBone)
187
+ TBExtraController.setExpression(inExtraExpression)
188
+
189
+ PrevTBE = TwistBone
190
+
191
+ # 추가 트위스트 뼈대 생성 (2개 이상인 경우)
192
+ if inTwistNum > 1:
193
+ for j in range(2, inTwistNum):
194
+ TwistBoneExtra = rt.BoneSys.createBone(
195
+ rt.Point3(0, 0, 0),
196
+ rt.Point3(1, 0, 0),
197
+ rt.Point3(0, 0, 1)
198
+ )
199
+ matAux = rt.matrix3(1)
200
+ matAux.position = rt.Point3(distanceVar/inTwistNum, 0, 0)
201
+ TwistBoneExtra.transform = matAux * PrevTBE.transform
202
+ TwistBoneExtra.name = self.name.replace_Index(boneName, str(j-1))
203
+ TwistBoneExtra.parent = PrevTBE
204
+ TwistBoneExtra.length = distanceVar / inTwistNum
205
+ TwistBoneExtra.width = PrevTBE.width
206
+ TwistBoneExtra.height = PrevTBE.height
207
+ TwistBoneExtra.taper = 0
208
+ TwistBoneExtra.sidefins = False
209
+ TwistBoneExtra.frontfin = False
210
+ TwistBoneExtra.backfin = False
211
+
212
+ # 회전 컨트롤러 설정
213
+ TBExtraRotListController = self.const.assign_rot_list(TwistBoneExtra)
214
+ rt.setPropertyController(TBExtraRotListController, "Available", TBExtraController)
215
+ TBExtraRotListController.delete(1)
216
+ TBExtraRotListController.setActive(TBExtraRotListController.count)
217
+ TBExtraRotListController.weight[0] = 100 / (inTwistNum - 1)
218
+
219
+ PrevTBE = TwistBoneExtra
220
+ boneChainArray.append(TwistBoneExtra)
221
+
222
+ # 마지막 트위스트 뼈대 생성
223
+ TwistBoneEnd = rt.BoneSys.createBone(
224
+ rt.Point3(0, 0, 0),
225
+ rt.Point3(1, 0, 0),
226
+ rt.Point3(0, 0, 1)
227
+ )
228
+ matAux = rt.matrix3(1)
229
+ matAux.position = rt.Point3(distanceVar/inTwistNum, 0, 0)
230
+ TwistBoneEnd.transform = matAux * PrevTBE.transform
231
+ TwistBoneEnd.name = self.name.replace_Index(boneName, str(inTwistNum-1))
232
+ TwistBoneEnd.parent = inObj
233
+ TwistBoneEnd.length = distanceVar / inTwistNum
234
+ TwistBoneEnd.width = PrevTBE.width
235
+ TwistBoneEnd.height = PrevTBE.height
236
+ TwistBoneEnd.taper = 0
237
+ TwistBoneEnd.sidefins = False
238
+ TwistBoneEnd.frontfin = False
239
+ TwistBoneEnd.backfin = False
240
+
241
+ boneChainArray.append(TwistBoneEnd)
242
+
243
+ return boneChainArray
244
+
245
+ def reorder_bones(self, inBoneChainArray):
246
+ """
247
+ 뼈대 체인의 순서 재배치
248
+
249
+ Args:
250
+ inBoneChainArray: 재배치할 뼈대 체인 배열
251
+
252
+ Returns:
253
+ 재배치된 뼈대 체인 배열
254
+ """
255
+ boneChainArray = rt.deepcopy(inBoneChainArray)
256
+ returnBoneArray = []
257
+
258
+ # 첫 번째와 마지막 뼈대 가져오기
259
+ firstBone = boneChainArray[0]
260
+ lastBone = boneChainArray[-1]
261
+ returnBoneArray.append(lastBone)
262
+
263
+ # 뼈대가 2개 이상인 경우 위치 조정
264
+ if len(boneChainArray) > 1:
265
+ self.anim.move_local(firstBone, firstBone.length, 0, 0)
266
+ self.anim.move_local(lastBone, -(firstBone.length * (len(boneChainArray)-1)), 0, 0)
267
+
268
+ # 중간 뼈대들을 새 배열에 추가
269
+ for i in range(len(boneChainArray)-1):
270
+ returnBoneArray.append(boneChainArray[i])
271
+
272
+ # 새로운 순서대로 이름 재설정
273
+ for i in range(len(returnBoneArray)):
274
+ returnBoneArray[i].name = self.name.replace_Index(boneChainArray[i].name, str(i))
275
+
276
+ return returnBoneArray
277
+
278
+ def create_upperArm_type(self, inObj, inTwistNum):
279
+ """
280
+ 상완(Upper Arm) 타입의 트위스트 뼈대 생성
281
+
282
+ Args:
283
+ inObj: 상완 뼈대 객체
284
+ inTwistNum: 트위스트 뼈대 개수
285
+
286
+ Returns:
287
+ 생성된 트위스트 뼈대 체인 또는 False(실패 시)
288
+ """
289
+ if inObj.parent is None or inObj.children.count == 0:
290
+ return False
291
+
292
+ weightVal = 100.0
293
+
294
+ return self.create_bones(
295
+ inObj,
296
+ inObj.children[0],
297
+ inTwistNum,
298
+ self.upperArmExpression,
299
+ self.upperArmExtraExpression,
300
+ inObj,
301
+ weightVal
302
+ )
303
+
304
+ def create_foreArm_type(self, inObj, inTwistNum, reorder=True):
305
+ """
306
+ 전완(Forearm) 타입의 트위스트 뼈대 생성
307
+
308
+ Args:
309
+ inObj: 전완 뼈대 객체
310
+ inTwistNum: 트위스트 뼈대 개수
311
+ side: 좌/우측 ("left" 또는 "right", 기본값: "left")
312
+
313
+ Returns:
314
+ 생성된 트위스트 뼈대 체인 또는 False(실패 시)
315
+ """
316
+ if inObj.parent is None or inObj.children.count == 0:
317
+ return False
318
+
319
+ controllerLimb = None
320
+ weightVal = 100.0
321
+
322
+ # 좌/우측에 따른 표현식 선택
323
+ TBExpression = self.lForeArmExpression if self.bip.is_left_node(inObj) else self.rForeArmExpression
324
+
325
+ # Biped 컨트롤러 노드 설정
326
+ if self.bip.is_left_node(inObj):
327
+ controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lArm"), link=4)
328
+ else:
329
+ controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rArm"), link=4)
330
+
331
+ if inTwistNum > 1:
332
+ weightVal = 100 / (inTwistNum - 1)
333
+
334
+ createdBones = self.create_bones(
335
+ inObj,
336
+ controllerLimb,
337
+ inTwistNum,
338
+ TBExpression,
339
+ self.foreArmExtraExpression,
340
+ controllerLimb,
341
+ weightVal
342
+ )
343
+
344
+ return self.reorder_bones(createdBones) if reorder else createdBones
345
+
346
+ def create_thigh_type(self, inObj, inTwistNum):
347
+ """
348
+ 허벅지(Thigh) 타입의 트위스트 뼈대 생성
349
+
350
+ Args:
351
+ inObj: 허벅지 뼈대 객체
352
+ inTwistNum: 트위스트 뼈대 개수
353
+
354
+ Returns:
355
+ 생성된 트위스트 뼈대 체인 또는 False(실패 시)
356
+ """
357
+ if inObj.parent is None or inObj.children.count == 0:
358
+ return False
359
+
360
+ controllerLimb = None
361
+ weightVal = 100
362
+
363
+ return self.create_bones(
364
+ inObj,
365
+ inObj.children[0],
366
+ inTwistNum,
367
+ self.thighExpression,
368
+ self.thighExtraExpression,
369
+ inObj,
370
+ weightVal
371
+ )
372
+
373
+ def create_calf_type(self, inObj, inTwistNum, reorder=True):
374
+ """
375
+ 종아리(Calf) 타입의 트위스트 뼈대 생성
376
+
377
+ Args:
378
+ inObj: 종아리 뼈대 객체
379
+ inTwistNum: 트위스트 뼈대 개수
380
+ side: 좌/우측 ("left" 또는 "right", 기본값: "left")
381
+
382
+ Returns:
383
+ 생성된 트위스트 뼈대 체인 또는 False(실패 시)
384
+ """
385
+ if inObj.parent is None or inObj.children.count == 0:
386
+ return False
387
+
388
+ controllerLimb = None
389
+ weightVal = 100
390
+
391
+ # Biped 컨트롤러 노드 설정
392
+ if self.bip.is_left_node(inObj):
393
+ controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lLeg"), link=3)
394
+ else:
395
+ controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rLeg"), link=3)
396
+
397
+ # 복수 뼈대인 경우 가중치 조정
398
+ if inTwistNum > 1:
399
+ weightVal = 100 / (inTwistNum - 1)
400
+
401
+ createdBones = self.create_bones(
402
+ inObj,
403
+ controllerLimb,
404
+ inTwistNum,
405
+ self.calfExpression,
406
+ self.calfExtraExpression,
407
+ controllerLimb,
408
+ weightVal
409
+ )
410
+
411
+ return self.reorder_bones(createdBones) if reorder else createdBones
412
+
413
+ def create_bend_type(self):
414
+ """
415
+ 굽힘(Bend) 타입의 트위스트 뼈대 생성
416
+ (아직 구현되지 않음)
417
+ """
418
+ pass