pyjallib 0.1.8__py3-none-any.whl → 0.1.10__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.
pyjallib/max/twistBone.py CHANGED
@@ -3,7 +3,11 @@
3
3
 
4
4
  """
5
5
  트위스트 뼈대(Twist Bone) 모듈 - 3ds Max용 트위스트 뼈대 생성 관련 기능 제공
6
- 원본 MAXScript의 twistBone.ms를 Python으로 변환하였으며, pymxs 모듈 기반으로 구현됨
6
+
7
+ 이 모듈은 3D 캐릭터 리깅에서 사용되는 트위스트 뼈대를 생성하고 제어하는 기능을 제공합니다.
8
+ 트위스트 뼈대는 팔이나 다리의 회전 움직임을 더욱 자연스럽게 표현하기 위해 사용됩니다.
9
+ 원본 MAXScript의 twistBone.ms를 Python으로 변환하였으며, pymxs 모듈 기반으로 구현되어
10
+ 3ds Max 내에서 스크립트 형태로 실행할 수 있습니다.
7
11
  """
8
12
 
9
13
  from pymxs import runtime as rt
@@ -19,526 +23,305 @@ from .bone import Bone
19
23
  class TwistBone:
20
24
  """
21
25
  트위스트 뼈대(Twist Bone) 관련 기능을 제공하는 클래스.
26
+
27
+ 이 클래스는 3ds Max에서 트위스트 뼈대를 생성하고 제어하는 다양한 기능을 제공합니다.
22
28
  MAXScript의 _TwistBone 구조체 개념을 Python으로 재구현한 클래스이며,
23
29
  3ds Max의 기능들을 pymxs API를 통해 제어합니다.
30
+
31
+ 트위스트 뼈대는 상체(Upper)와 하체(Lower) 두 가지 타입으로 생성이 가능하며,
32
+ 각각 다른 회전 표현식을 사용하여 자연스러운 회전 움직임을 구현합니다.
24
33
  """
25
34
 
26
- def __init__(self, nameService=None, animService=None, constService=None, bipService=None, boneService=None):
35
+ def __init__(self, nameService=None, animService=None, constraintService=None, bipService=None, boneService=None):
27
36
  """
28
- 클래스 초기화.
37
+ TwistBone 클래스 초기화.
38
+
39
+ 의존성 주입 방식으로 필요한 서비스들을 외부에서 제공받거나 내부에서 생성합니다.
40
+ 서비스들이 제공되지 않을 경우 각 서비스의 기본 인스턴스를 생성하여 사용합니다.
29
41
 
30
42
  Args:
31
- nameService: 이름 처리 서비스 (제공되지 않으면 새로 생성)
32
- animService: 애니메이션 서비스 (제공되지 않으면 새로 생성)
33
- constService: 제약 서비스 (제공되지 않으면 새로 생성)
34
- bipService: 바이페드 서비스 (제공되지 않으면 새로 생성)
43
+ nameService (Name, optional): 이름 처리 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
44
+ animService (Anim, optional): 애니메이션 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
45
+ constraintService (Constraint, optional): 제약 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
46
+ bipService (Bip, optional): 바이페드 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
47
+ boneService (Bone, optional): 뼈대 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
35
48
  """
36
49
  self.name = nameService if nameService else Name()
37
50
  self.anim = animService if animService else Anim()
38
51
  # Ensure dependent services use the potentially newly created instances
39
- self.const = constService if constService else Constraint(nameService=self.name)
40
- self.bip = bipService if bipService else Bip(animService=self.anim, nameService=self.name) # Pass potentially new instances
52
+ self.const = constraintService if constraintService else Constraint(nameService=self.name)
53
+ self.bip = bipService if bipService else Bip(animService=self.anim, nameService=self.name)
41
54
  self.bone = boneService if boneService else Bone(nameService=self.name, animService=self.anim)
42
55
 
43
- # 표현식 초기화
44
- self._init_expressions()
45
-
46
- def _init_expressions(self):
47
- """표현식 초기화"""
48
- # 허벅지(Thigh) 표현식
49
- self.thighExpression = (
50
- "try(\n"
51
- "TM=Limb.transform*inverse Limb.parent.transform\n"
52
- "vector=normalize (cross -TM.row1 [1,0,0])\n"
53
- "angle=acos -(normalize TM.row1).x\n"
54
- "(quat 0 1 0 0)*(quat angle vector)*inverse TM.rotation)\n"
55
- "catch((quat 0 0 0 1))"
56
- )
57
-
58
- # 허벅지 추가 표현식
59
- self.thighExtraExpression = (
60
- "try(\n"
61
- "(Limb.transform*inverse LimbParent.transform).rotation\n"
62
- ")catch((quat 0 0 0 1))"
63
- )
64
-
65
- # 종아리(Calf) 표현식
66
- self.calfExpression = (
67
- "try(\n"
68
- "TM=Limb.transform*inverse Limb.parent.transform\n"
69
- "vector=normalize (cross TM.row1 [1,0,0])\n"
70
- "angle=acos (normalize TM.row1).x\n"
71
- "TM.rotation*(quat -angle vector))\n"
72
- "catch((quat 0 0 0 1))"
73
- )
74
-
75
- # 종아리 추가 표현식
76
- self.calfExtraExpression = (
77
- "try(dependson TB\n"
78
- "TB.rotation.controller[1].value\n"
79
- ")catch((quat 0 0 0 1))"
80
- )
81
-
82
- # 상완(Upper Arm) 표현식
83
- self.upperArmExpression = (
84
- "try(\n"
85
- "TM=Limb.transform*inverse Limb.parent.transform\n"
86
- "vector=normalize (cross TM.row1 [1,0,0])\n"
87
- "angle=acos (normalize TM.row1).x\n"
88
- "(quat angle vector)*inverse TM.rotation)\n"
89
- "catch((quat 0 0 0 1))"
90
- )
91
-
92
- # 상완 추가 표현식
93
- self.upperArmExtraExpression = (
94
- "try(\n"
95
- "(Limb.transform*inverse LimbParent.transform).rotation\n"
96
- ")catch((quat 0 0 0 1))"
56
+ # 객체 속성 초기화
57
+ self.limb = None
58
+ self.child = None
59
+ self.twistNum = 0
60
+ self.bones = []
61
+ self.twistType = ""
62
+
63
+ self.upperTwistBoneExpression = (
64
+ "localTm = limb.transform * (inverse limbParent.transform)\n"
65
+ "tm = localTm * inverse(localRefTm)\n"
66
+ "\n"
67
+ "q = tm.rotation\n"
68
+ "\n"
69
+ "axis = [1,0,0]\n"
70
+ "proj = (dot q.axis axis) * axis\n"
71
+ "twist = quat q.angle proj\n"
72
+ "twist = normalize twist\n"
73
+ "--swing = tm.rotation * (inverse twist)\n"
74
+ "\n"
75
+ "inverse twist\n"
97
76
  )
98
77
 
99
- # 오른쪽 전완(Forearm) 표현식
100
- self.rForeArmExpression = (
101
- "try(\n"
102
- "TM=(matrix3 [1,0,0] [0,0,-1] [0,1,0] [0,0,0])*Limb.transform*inverse Limb.parent.transform\n"
103
- "vector=normalize (cross TM.row1 [1,0,0])\n"
104
- "angle=acos (normalize TM.row1).x\n"
105
- "TM.rotation*(quat -angle vector))\n"
106
- "catch((quat 0 0 0 1))"
107
- )
108
-
109
- # 왼쪽 전완(Forearm) 표현식
110
- self.lForeArmExpression = (
111
- "try(\n"
112
- "TM=(matrix3 [1,0,0] [0,0,1] [0,-1,0] [0,0,0])*Limb.transform*inverse Limb.parent.transform\n"
113
- "vector=normalize (cross TM.row1 [1,0,0])\n"
114
- "angle=acos (normalize TM.row1).x\n"
115
- "TM.rotation*(quat -angle vector))\n"
116
- "catch((quat 0 0 0 1))"
117
- )
118
-
119
- # 전완 추가 표현식
120
- self.foreArmExtraExpression = (
121
- "try(dependson TB\n"
122
- "TB.rotation.controller[1].value\n"
123
- ")catch((quat 0 0 0 1))"
124
- )
125
-
126
- def create_bones(self, inObj, inChild, inTwistNum, inExpression, inExtraExpression, inControllerLimb, inWeightVar):
127
- """
128
- 트위스트 뼈대 체인 생성
129
-
130
- Args:
131
- inObj: 시작 객체
132
- inChild: 끝 객체
133
- inTwistNum: 트위스트 뼈대 개수
134
- inExpression: 기본 회전 표현식
135
- inExtraExpression: 추가 회전 표현식
136
- inControllerLimb: 컨트롤러 대상 팔다리
137
- inWeightVar: 가중치
138
-
139
- Returns:
140
- 생성된 트위스트 뼈대 체인 배열
141
- """
142
- Limb = inObj
143
- distanceVar = rt.distance(Limb, inChild)
144
-
145
- TBExpression = inExpression
146
- ControllerLimb = inControllerLimb
147
- weightVar = inWeightVar
148
-
149
- boneChainArray = []
150
-
151
- # 첫 번째 트위스트 뼈대 생성
152
- TwistBone = rt.BoneSys.createBone(
153
- Limb.transform.position,
154
- inChild.transform.position,
155
- rt.Point3(0, 0, 1)
78
+ self.lowerTwistBoneExpression = (
79
+ "localTm = limb.transform * (inverse limbParent.transform)\n"
80
+ "tm = localTm * inverse(localRefTm)\n"
81
+ "\n"
82
+ "q = tm.rotation\n"
83
+ "\n"
84
+ "axis = [1,0,0]\n"
85
+ "proj = (dot q.axis axis) * axis\n"
86
+ "twist = quat q.angle proj\n"
87
+ "twist = normalize twist\n"
88
+ "--swing = tm.rotation * (inverse twist)\n"
89
+ "\n"
90
+ "twist\n"
156
91
  )
157
- boneName = self.name.get_string(inObj.name) + "Twist"
158
- TwistBone.name = self.name.replace_Index(boneName, "0")
159
- TwistBone.transform = Limb.transform
160
- TwistBone.parent = Limb
161
- TwistBone.length = distanceVar / inTwistNum
162
- TwistBone.width = distanceVar / 8
163
- TwistBone.height = TwistBone.width
164
- TwistBone.taper = 0
165
- TwistBone.sidefins = False
166
- TwistBone.frontfin = False
167
- TwistBone.backfin = False
168
-
169
- # 회전 컨트롤러 설정
170
- TBRotListController = self.const.assign_rot_list(TwistBone)
171
- TBController = rt.Rotation_Script()
172
- TBController.addNode("Limb", ControllerLimb)
173
- TBController.setExpression(TBExpression)
174
-
175
- rt.setPropertyController(TBRotListController, "Available", TBController)
176
- TBRotListController.delete(1)
177
- TBRotListController.setActive(TBRotListController.count)
178
- TBRotListController.weight[0] = weightVar
179
-
180
- boneChainArray.append(TwistBone)
181
-
182
- # 추가 회전 컨트롤러 설정
183
- TBExtraController = rt.Rotation_Script()
184
- if rt.matchPattern(inExtraExpression, pattern="*\nTB.*"):
185
- TBExtraController.addNode("TB", TwistBone)
186
- else:
187
- TBExtraController.addNode("Limb", Limb)
188
- TBExtraController.addNode("LimbParent", TwistBone)
189
- TBExtraController.setExpression(inExtraExpression)
190
-
191
- PrevTBE = TwistBone
192
-
193
- # 추가 트위스트 뼈대 생성 (2개 이상인 경우)
194
- if inTwistNum > 1:
195
- for j in range(2, inTwistNum):
196
- TwistBoneExtra = rt.BoneSys.createBone(
197
- rt.Point3(0, 0, 0),
198
- rt.Point3(1, 0, 0),
199
- rt.Point3(0, 0, 1)
200
- )
201
- matAux = rt.matrix3(1)
202
- matAux.position = rt.Point3(distanceVar/inTwistNum, 0, 0)
203
- TwistBoneExtra.transform = matAux * PrevTBE.transform
204
- TwistBoneExtra.name = self.name.replace_Index(boneName, str(j-1))
205
- TwistBoneExtra.parent = PrevTBE
206
- TwistBoneExtra.length = distanceVar / inTwistNum
207
- TwistBoneExtra.width = PrevTBE.width
208
- TwistBoneExtra.height = PrevTBE.height
209
- TwistBoneExtra.taper = 0
210
- TwistBoneExtra.sidefins = False
211
- TwistBoneExtra.frontfin = False
212
- TwistBoneExtra.backfin = False
213
-
214
- # 회전 컨트롤러 설정
215
- TBExtraRotListController = self.const.assign_rot_list(TwistBoneExtra)
216
- rt.setPropertyController(TBExtraRotListController, "Available", TBExtraController)
217
- TBExtraRotListController.delete(1)
218
- TBExtraRotListController.setActive(TBExtraRotListController.count)
219
- TBExtraRotListController.weight[0] = 100 / (inTwistNum - 1)
220
-
221
- PrevTBE = TwistBoneExtra
222
- boneChainArray.append(TwistBoneExtra)
223
-
224
- # 마지막 트위스트 뼈대 생성
225
- TwistBoneEnd = rt.BoneSys.createBone(
226
- rt.Point3(0, 0, 0),
227
- rt.Point3(1, 0, 0),
228
- rt.Point3(0, 0, 1)
229
- )
230
- matAux = rt.matrix3(1)
231
- matAux.position = rt.Point3(distanceVar/inTwistNum, 0, 0)
232
- TwistBoneEnd.transform = matAux * PrevTBE.transform
233
- TwistBoneEnd.name = self.name.replace_Index(boneName, str(inTwistNum-1))
234
- TwistBoneEnd.parent = inObj
235
- TwistBoneEnd.length = distanceVar / inTwistNum
236
- TwistBoneEnd.width = PrevTBE.width
237
- TwistBoneEnd.height = PrevTBE.height
238
- TwistBoneEnd.taper = 0
239
- TwistBoneEnd.sidefins = False
240
- TwistBoneEnd.frontfin = False
241
- TwistBoneEnd.backfin = False
242
92
 
243
- boneChainArray.append(TwistBoneEnd)
244
-
245
- return boneChainArray
246
-
247
- def reorder_bones(self, inBoneChainArray):
93
+ def reset(self):
248
94
  """
249
- 뼈대 체인의 순서 재배치
95
+ 클래스의 주요 컴포넌트들을 초기화합니다.
96
+ 서비스가 아닌 클래스 자체의 작업 데이터를 초기화하는 함수입니다.
250
97
 
251
- Args:
252
- inBoneChainArray: 재배치할 뼈대 체인 배열
253
-
254
98
  Returns:
255
- 재배치된 뼈대 체인 배열
256
- """
257
- boneChainArray = rt.deepcopy(inBoneChainArray)
258
- returnBoneArray = []
259
-
260
- # 첫 번째와 마지막 뼈대 가져오기
261
- firstBone = boneChainArray[0]
262
- lastBone = boneChainArray[-1]
263
- returnBoneArray.append(lastBone)
264
-
265
- # 뼈대가 2개 이상인 경우 위치 조정
266
- if len(boneChainArray) > 1:
267
- self.anim.move_local(firstBone, firstBone.length, 0, 0)
268
- self.anim.move_local(lastBone, -(firstBone.length * (len(boneChainArray)-1)), 0, 0)
269
-
270
- # 중간 뼈대들을 새 배열에 추가
271
- for i in range(len(boneChainArray)-1):
272
- returnBoneArray.append(boneChainArray[i])
273
-
274
- # 새로운 순서대로 이름 재설정
275
- for i in range(len(returnBoneArray)):
276
- returnBoneArray[i].name = self.name.replace_Index(boneChainArray[i].name, str(i))
277
-
278
- return returnBoneArray
279
-
280
- def create_upperArm_type(self, inObj, inTwistNum):
99
+ self: 메소드 체이닝을 위한 자기 자신 반환
281
100
  """
282
- 상완(Upper Arm) 타입의 트위스트 뼈대 생성
101
+ self.limb = None
102
+ self.child = None
103
+ self.twistNum = 0
104
+ self.bones = []
105
+ self.twistType = ""
283
106
 
284
- Args:
285
- inObj: 상완 뼈대 객체
286
- inTwistNum: 트위스트 뼈대 개수
107
+ return self
287
108
 
288
- Returns:
289
- 생성된 트위스트 뼈대 체인 또는 False(실패 시)
109
+ def create_upper_limb_bones(self, inObj, inChild, twistNum=4):
290
110
  """
291
- if inObj.parent is None or inObj.children.count == 0:
292
- return False
293
-
294
- weightVal = 100.0
295
-
296
- return self.create_bones(
297
- inObj,
298
- inObj.children[0],
299
- inTwistNum,
300
- self.upperArmExpression,
301
- self.upperArmExtraExpression,
302
- inObj,
303
- weightVal
304
- )
305
-
306
- def create_foreArm_type(self, inObj, inTwistNum, reorder=True):
307
- """
308
- 전완(Forearm) 타입의 트위스트 뼈대 생성
309
-
310
- Args:
311
- inObj: 전완 뼈대 객체
312
- inTwistNum: 트위스트 뼈대 개수
313
- side: 좌/우측 ("left" 또는 "right", 기본값: "left")
314
-
315
- Returns:
316
- 생성된 트위스트 뼈대 체인 또는 False(실패 시)
317
- """
318
- if inObj.parent is None or inObj.children.count == 0:
319
- return False
320
-
321
- controllerLimb = None
322
- weightVal = 100.0
111
+ 상체(팔, 어깨 등) 부분의 트위스트 뼈대를 생성하는 메소드.
323
112
 
324
- # 좌/우측에 따른 표현식 선택
325
- TBExpression = self.lForeArmExpression if self.bip.is_left_node(inObj) else self.rForeArmExpression
326
-
327
- # Biped 컨트롤러 노드 설정
328
- if self.bip.is_left_node(inObj):
329
- controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lArm"), link=4)
330
- else:
331
- controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rArm"), link=4)
332
-
333
- if inTwistNum > 1:
334
- weightVal = 100 / (inTwistNum - 1)
335
-
336
- createdBones = self.create_bones(
337
- inObj,
338
- controllerLimb,
339
- inTwistNum,
340
- TBExpression,
341
- self.foreArmExtraExpression,
342
- controllerLimb,
343
- weightVal
344
- )
345
-
346
- return self.reorder_bones(createdBones) if reorder else createdBones
347
-
348
- def create_thigh_type(self, inObj, inTwistNum):
349
- """
350
- 허벅지(Thigh) 타입의 트위스트 뼈대 생성
113
+ 상체용 트위스트 뼈대는 부모 객체(inObj)의 위치에서 시작하여
114
+ 자식 객체(inChild) 방향으로 여러 개의 뼈대를 생성합니다.
115
+ 생성된 뼈대들은 스크립트 컨트롤러를 통해 자동으로 회전되어
116
+ 자연스러운 트위스트 움직임을 표현합니다.
351
117
 
352
118
  Args:
353
- inObj: 허벅지 뼈대 객체
354
- inTwistNum: 트위스트 뼈대 개수
355
-
356
- Returns:
357
- 생성된 트위스트 뼈대 체인 또는 False(실패 시)
358
- """
359
- if inObj.parent is None or inObj.children.count == 0:
360
- return False
361
-
362
- controllerLimb = None
363
- weightVal = 100
364
-
365
- return self.create_bones(
366
- inObj,
367
- inObj.children[0],
368
- inTwistNum,
369
- self.thighExpression,
370
- self.thighExtraExpression,
371
- inObj,
372
- weightVal
373
- )
374
-
375
- def create_calf_type(self, inObj, inTwistNum, reorder=True):
376
- """
377
- 종아리(Calf) 타입의 트위스트 뼈대 생성
119
+ inObj: 트위스트 뼈대의 부모 객체(뼈). 일반적으로 상완 또는 대퇴부에 해당합니다.
120
+ inChild: 자식 객체(뼈). 일반적으로 전완 또는 하퇴부에 해당합니다.
121
+ twistNum (int, optional): 생성할 트위스트 뼈대의 개수. 기본값은 4입니다.
378
122
 
379
- Args:
380
- inObj: 종아리 뼈대 객체
381
- inTwistNum: 트위스트 뼈대 개수
382
- side: 좌/우측 ("left" 또는 "right", 기본값: "left")
383
-
384
123
  Returns:
385
- 생성된 트위스트 뼈대 체인 또는 False(실패 시)
124
+ dict: 생성된 트위스트 뼈대 정보를 담고 있는 사전 객체입니다.
125
+ "Bones": 생성된 뼈대 객체들의 배열
126
+ "Type": "Upper" (상체 타입)
127
+ "Limb": 부모 객체 참조
128
+ "Child": 자식 객체 참조
129
+ "TwistNum": 생성된 트위스트 뼈대 개수
386
130
  """
387
- if inObj.parent is None or inObj.children.count == 0:
388
- return False
131
+ limb = inObj
132
+ distance = rt.distance(limb, inChild)
133
+ facingDirVec = inChild.transform.position - inObj.transform.position
134
+ inObjXAxisVec = inObj.objectTransform.row1
135
+ distanceDir = 1.0 if rt.dot(inObjXAxisVec, facingDirVec) > 0 else -1.0
136
+ offssetAmount = (distance / twistNum) * distanceDir
137
+ weightVal = 100.0 / (twistNum-1)
389
138
 
390
- controllerLimb = None
391
- weightVal = 100
392
-
393
- # Biped 컨트롤러 노드 설정
394
- if self.bip.is_left_node(inObj):
395
- controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lLeg"), link=3)
396
- else:
397
- controllerLimb = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rLeg"), link=3)
398
-
399
- # 복수 뼈대인 경우 가중치 조정
400
- if inTwistNum > 1:
401
- weightVal = 100 / (inTwistNum - 1)
402
-
403
- createdBones = self.create_bones(
404
- inObj,
405
- controllerLimb,
406
- inTwistNum,
407
- self.calfExpression,
408
- self.calfExtraExpression,
409
- controllerLimb,
410
- weightVal
411
- )
412
-
413
- return self.reorder_bones(createdBones) if reorder else createdBones
414
-
415
- def create_bend_type(self):
416
- """
417
- 굽힘(Bend) 타입의 트위스트 뼈대 생성
418
- (아직 구현되지 않음)
419
- """
420
- pass
421
-
422
- def get_upperArm_type(self, inObj):
423
- """
424
- 상완(Upper Arm) 타입의 트위스트 뼈대 가져오기
139
+ boneChainArray = []
425
140
 
426
- Args:
427
- inObj: 상완 뼈대 객체
141
+ # 첫 번째 트위스트 뼈대 생성
142
+ boneName = self.name.add_suffix_to_real_name(inObj.name, self.name._get_filtering_char(inObj.name) + "Twist")
143
+ if inObj.name[0].islower():
144
+ boneName = boneName.lower()
145
+ twistBone = self.bone.create_nub_bone(boneName, 2)
146
+ twistBone.name = self.name.replace_name_part("Index", boneName, "1")
147
+ twistBone.name = self.name.remove_name_part("Nub", twistBone.name)
148
+ twistBone.transform = limb.transform
149
+ twistBone.parent = limb
150
+ twistBoneLocalRefTM = limb.transform * rt.inverse(limb.parent.transform)
151
+
152
+ twistBoneRotListController = self.const.assign_rot_list(twistBone)
153
+ twistBoneController = rt.Rotation_Script()
154
+ twistBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
155
+ twistBoneController.addNode("limb", limb)
156
+ twistBoneController.addNode("limbParent", limb.parent)
157
+ twistBoneController.setExpression(self.upperTwistBoneExpression)
158
+ twistBoneController.update()
159
+
160
+ rt.setPropertyController(twistBoneRotListController, "Available", twistBoneController)
161
+ twistBoneRotListController.delete(1)
162
+ twistBoneRotListController.setActive(twistBoneRotListController.count)
163
+ twistBoneRotListController.weight[0] = 100.0
164
+
165
+ boneChainArray.append(twistBone)
166
+
167
+ if twistNum > 1:
168
+ lastBone = self.bone.create_nub_bone(boneName, 2)
169
+ lastBone.name = self.name.replace_name_part("Index", boneName, str(twistNum))
170
+ lastBone.name = self.name.remove_name_part("Nub", lastBone.name)
171
+ lastBone.transform = limb.transform
172
+ lastBone.parent = limb
173
+ self.anim.move_local(lastBone, offssetAmount*(twistNum-1), 0, 0)
428
174
 
429
- Returns:
430
- 상완 타입의 트위스트 뼈대 또는 False(실패 )
431
- """
432
- returnVal = []
433
-
434
- parentBipObj = None
435
-
436
- if not self.bip.is_biped_object(inObj):
437
- return returnVal
438
-
439
- if self.bip.is_left_node(inObj):
440
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lArm"), link=2)
441
- else:
442
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rArm"), link=2)
175
+ if twistNum > 2:
176
+ for i in range(1, twistNum-1):
177
+ twistExtraBone = self.bone.create_nub_bone(boneName, 2)
178
+ twistExtraBone.name = self.name.replace_name_part("Index", boneName, str(i+1))
179
+ twistExtraBone.name = self.name.remove_name_part("Nub", twistExtraBone.name)
180
+ twistExtraBone.transform = limb.transform
181
+ twistExtraBone.parent = limb
182
+ self.anim.move_local(twistExtraBone, offssetAmount*i, 0, 0)
183
+
184
+ twistExtraBoneRotListController = self.const.assign_rot_list(twistExtraBone)
185
+ twistExtraBoneController = rt.Rotation_Script()
186
+ twistExtraBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
187
+ twistExtraBoneController.addNode("limb", limb)
188
+ twistExtraBoneController.addNode("limbParent", limb.parent)
189
+ twistExtraBoneController.setExpression(self.upperTwistBoneExpression)
190
+
191
+ rt.setPropertyController(twistExtraBoneRotListController, "Available", twistExtraBoneController)
192
+ twistExtraBoneRotListController.delete(1)
193
+ twistExtraBoneRotListController.setActive(twistExtraBoneRotListController.count)
194
+ twistExtraBoneRotListController.weight[0] = weightVal * (twistNum-1-i)
195
+
196
+ boneChainArray.append(twistExtraBone)
443
197
 
444
- children = self.bone.get_every_children(parentBipObj)
445
- for child in children:
446
- if rt.matchPattern(child.name, pattern="*Twist*") and rt.classOf(child) == rt.BoneGeometry:
447
- returnVal.append(child)
448
-
449
- returnVal = self.name.sort_by_name(returnVal)
198
+ boneChainArray.append(lastBone)
199
+
200
+ # 결과를 멤버 변수에 저장
201
+ self.limb = inObj
202
+ self.child = inChild
203
+ self.twistNum = twistNum
204
+ self.bones = boneChainArray
205
+ self.twistType = "Upper"
206
+
207
+ returnVal = {
208
+ "Bones": boneChainArray,
209
+ "Type": "Upper",
210
+ "Limb": inObj,
211
+ "Child": inChild,
212
+ "TwistNum": twistNum
213
+ }
214
+
215
+ # 메소드 호출 후 데이터 초기화
216
+ self.reset()
450
217
 
451
218
  return returnVal
452
-
453
- def get_foreArm_type(self, inObj):
454
- """
455
- 전완(Forearm) 타입의 트위스트 뼈대 가져오기
456
-
457
- Args:
458
- inObj: 전완 뼈대 객체
459
-
460
- Returns:
461
- 전완 타입의 트위스트 뼈대 또는 False(실패 시)
219
+
220
+ def create_lower_limb_bones(self, inObj, inChild, twistNum=4):
462
221
  """
463
- returnVal = []
464
-
465
- parentBipObj = None
222
+ 하체(팔뚝, 다리 등) 부분의 트위스트 뼈대를 생성하는 메소드.
466
223
 
467
- if not self.bip.is_biped_object(inObj):
468
- return returnVal
469
-
470
- if self.bip.is_left_node(inObj):
471
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lArm"), link=3)
472
- else:
473
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rArm"), link=3)
474
-
475
- children = self.bone.get_every_children(parentBipObj)
476
- for child in children:
477
- if rt.matchPattern(child.name, pattern="*Twist*") and rt.classOf(child) == rt.BoneGeometry:
478
- returnVal.append(child)
479
-
480
- returnVal = self.name.sort_by_name(returnVal)
481
-
482
- return returnVal
483
-
484
- def get_thigh_type(self, inObj):
485
- """
486
- 허벅지(Thigh) 타입의 트위스트 뼈대 가져오기
224
+ 하체용 트위스트 뼈대는 부모 객체(inObj)의 위치에서 시작하여
225
+ 자식 객체(inChild) 쪽으로 여러 개의 뼈대를 생성합니다.
226
+ 상체와는 다른 회전 표현식을 사용하여 하체에 적합한 트위스트 움직임을 구현합니다.
487
227
 
488
228
  Args:
489
- inObj: 허벅지 뼈대 객체
490
-
491
- Returns:
492
- 허벅지 타입의 트위스트 뼈대 또는 False(실패 시)
493
- """
494
- returnVal = []
495
-
496
- parentBipObj = None
229
+ inObj: 트위스트 뼈대의 부모 객체(뼈). 일반적으로 전완 또는 하퇴부에 해당합니다.
230
+ inChild: 자식 객체(뼈). 일반적으로 손목 또는 발목에 해당합니다.
231
+ twistNum (int, optional): 생성할 트위스트 뼈대의 개수. 기본값은 4입니다.
497
232
 
498
- if not self.bip.is_biped_object(inObj):
499
- return returnVal
500
-
501
- if self.bip.is_left_node(inObj):
502
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lLeg"), link=1)
503
- else:
504
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rLeg"), link=1)
505
-
506
- children = self.bone.get_every_children(parentBipObj)
507
- for child in children:
508
- if rt.matchPattern(child.name, pattern="*Twist*") and rt.classOf(child) == rt.BoneGeometry:
509
- returnVal.append(child)
510
-
511
- returnVal = self.name.sort_by_name(returnVal)
512
-
513
- return returnVal
514
-
515
- def get_calf_type(self, inObj):
516
- """
517
- 종아리(Calf) 타입의 트위스트 뼈대 가져오기
518
-
519
- Args:
520
- inObj: 종아리 뼈대 객체
521
-
522
233
  Returns:
523
- 종아리 타입의 트위스트 뼈대 또는 False(실패 시)
234
+ dict: 생성된 트위스트 뼈대 정보를 담고 있는 사전 객체입니다.
235
+ "Bones": 생성된 뼈대 객체들의 배열
236
+ "Type": "Lower" (하체 타입)
237
+ "Limb": 부모 객체 참조
238
+ "Child": 자식 객체 참조
239
+ "TwistNum": 생성된 트위스트 뼈대 개수
524
240
  """
525
- returnVal = []
241
+ limb = inChild
242
+ distance = rt.distance(inObj, inChild)
243
+ facingDirVec = inChild.transform.position - inObj.transform.position
244
+ inObjXAxisVec = inObj.objectTransform.row1
245
+ distanceDir = 1.0 if rt.dot(inObjXAxisVec, facingDirVec) > 0 else -1.0
246
+ offssetAmount = (distance / twistNum) * distanceDir
247
+ weightVal = 100.0 / (twistNum-1)
526
248
 
527
- parentBipObj = None
528
-
529
- if not self.bip.is_biped_object(inObj):
530
- return returnVal
249
+ boneChainArray = []
531
250
 
532
- if self.bip.is_left_node(inObj):
533
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("lLeg"), link=2)
534
- else:
535
- parentBipObj = rt.biped.getNode(inObj.controller.rootNode, rt.Name("rLeg"), link=2)
251
+ # 첫 번째 트위스트 뼈대 생성
252
+ boneName = self.name.add_suffix_to_real_name(inObj.name, self.name._get_filtering_char(inObj.name) + "Twist")
253
+ if inObj.name[0].islower():
254
+ boneName = boneName.lower()
255
+ twistBone = self.bone.create_nub_bone(boneName, 2)
256
+ twistBone.name = self.name.replace_name_part("Index", boneName, "1")
257
+ twistBone.name = self.name.remove_name_part("Nub", twistBone.name)
258
+ twistBone.transform = inObj.transform
259
+ twistBone.parent = inObj
260
+ self.anim.move_local(twistBone, offssetAmount*(twistNum-1), 0, 0)
261
+ twistBoneLocalRefTM = limb.transform * rt.inverse(limb.parent.transform)
262
+
263
+ twistBoneRotListController = self.const.assign_rot_list(twistBone)
264
+ twistBoneController = rt.Rotation_Script()
265
+ twistBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
266
+ twistBoneController.addNode("limb", limb)
267
+ twistBoneController.addNode("limbParent", limb.parent)
268
+ twistBoneController.setExpression(self.lowerTwistBoneExpression)
269
+ twistBoneController.update()
270
+
271
+ rt.setPropertyController(twistBoneRotListController, "Available", twistBoneController)
272
+ twistBoneRotListController.delete(1)
273
+ twistBoneRotListController.setActive(twistBoneRotListController.count)
274
+ twistBoneRotListController.weight[0] = 100.0
275
+
276
+ if twistNum > 1:
277
+ lastBone = self.bone.create_nub_bone(boneName, 2)
278
+ lastBone.name = self.name.replace_name_part("Index", boneName, str(twistNum))
279
+ lastBone.name = self.name.remove_name_part("Nub", lastBone.name)
280
+ lastBone.transform = inObj.transform
281
+ lastBone.parent = inObj
282
+ self.anim.move_local(lastBone, 0, 0, 0)
536
283
 
537
- children = self.bone.get_every_children(parentBipObj)
538
- for child in children:
539
- if rt.matchPattern(child.name, pattern="*Twist*") and rt.classOf(child) == rt.BoneGeometry:
540
- returnVal.append(child)
541
-
542
- returnVal = self.name.sort_by_name(returnVal)
284
+ if twistNum > 2:
285
+ for i in range(1, twistNum-1):
286
+ twistExtraBone = self.bone.create_nub_bone(boneName, 2)
287
+ twistExtraBone.name = self.name.replace_name_part("Index", boneName, str(i+1))
288
+ twistExtraBone.name = self.name.remove_name_part("Nub", twistExtraBone.name)
289
+ twistExtraBone.transform = inObj.transform
290
+ twistExtraBone.parent = inObj
291
+ self.anim.move_local(twistExtraBone, offssetAmount*(twistNum-1-i), 0, 0)
292
+
293
+ twistExtraBoneRotListController = self.const.assign_rot_list(twistExtraBone)
294
+ twistExtraBoneController = rt.Rotation_Script()
295
+ twistExtraBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
296
+ twistExtraBoneController.addNode("limb", limb)
297
+ twistExtraBoneController.addNode("limbParent", limb.parent)
298
+ twistExtraBoneController.setExpression(self.lowerTwistBoneExpression)
299
+
300
+ rt.setPropertyController(twistExtraBoneRotListController, "Available", twistExtraBoneController)
301
+ twistExtraBoneRotListController.delete(1)
302
+ twistExtraBoneRotListController.setActive(twistExtraBoneRotListController.count)
303
+ twistExtraBoneRotListController.weight[0] = weightVal * (twistNum-1-i)
304
+
305
+ boneChainArray.append(twistExtraBone)
306
+
307
+ boneChainArray.append(lastBone)
308
+
309
+ # 결과를 멤버 변수에 저장
310
+ self.limb = inObj
311
+ self.child = inChild
312
+ self.twistNum = twistNum
313
+ self.bones = boneChainArray
314
+ self.twistType = "Lower"
315
+
316
+ returnVal = {
317
+ "Bones": boneChainArray,
318
+ "Type": "Lower",
319
+ "Limb": inObj,
320
+ "Child": inChild,
321
+ "TwistNum": twistNum
322
+ }
323
+
324
+ # 메소드 호출 후 데이터 초기화
325
+ self.reset()
543
326
 
544
327
  return returnVal