pyjallib 0.1.9__py3-none-any.whl → 0.1.11__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/__init__.py +7 -7
- pyjallib/max/ConfigFiles/Default_3DSMaxNamingConfig.json +161 -0
- pyjallib/max/__init__.py +31 -20
- pyjallib/max/anim.py +60 -36
- pyjallib/max/autoClavicle.py +122 -122
- pyjallib/max/bip.py +213 -14
- pyjallib/max/bone.py +378 -16
- pyjallib/max/boneChain.py +182 -0
- pyjallib/max/groinBone.py +148 -73
- pyjallib/max/header.py +42 -6
- pyjallib/max/helper.py +3 -21
- pyjallib/max/hip.py +276 -366
- pyjallib/max/kneeBone.py +552 -0
- pyjallib/max/macro/jal_macro_align.py +11 -10
- pyjallib/max/macro/jal_macro_bone.py +3 -2
- pyjallib/max/macro/jal_macro_constraint.py +2 -1
- pyjallib/max/macro/jal_macro_helper.py +2 -1
- pyjallib/max/macro/jal_macro_link.py +2 -1
- pyjallib/max/macro/jal_macro_select.py +2 -1
- pyjallib/max/mirror.py +1 -1
- pyjallib/max/twistBone.py +264 -462
- pyjallib/max/volumeBone.py +324 -0
- pyjallib/namePart.py +16 -16
- pyjallib/nameToPath.py +1 -1
- pyjallib/naming.py +16 -17
- pyjallib/namingConfig.py +3 -3
- pyjallib/perforce.py +127 -9
- {pyjallib-0.1.9.dist-info → pyjallib-0.1.11.dist-info}/METADATA +1 -1
- pyjallib-0.1.11.dist-info/RECORD +43 -0
- pyjallib/max/volumePreserveBone.py +0 -209
- pyjallib/p4module.py +0 -488
- pyjallib-0.1.9.dist-info/RECORD +0 -41
- {pyjallib-0.1.9.dist-info → pyjallib-0.1.11.dist-info}/WHEEL +0 -0
pyjallib/max/twistBone.py
CHANGED
@@ -3,7 +3,11 @@
|
|
3
3
|
|
4
4
|
"""
|
5
5
|
트위스트 뼈대(Twist Bone) 모듈 - 3ds Max용 트위스트 뼈대 생성 관련 기능 제공
|
6
|
-
|
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
|
@@ -15,530 +19,328 @@ from .constraint import Constraint
|
|
15
19
|
from .bip import Bip
|
16
20
|
from .bone import Bone
|
17
21
|
|
22
|
+
from .boneChain import BoneChain
|
23
|
+
|
18
24
|
|
19
25
|
class TwistBone:
|
20
26
|
"""
|
21
27
|
트위스트 뼈대(Twist Bone) 관련 기능을 제공하는 클래스.
|
28
|
+
|
29
|
+
이 클래스는 3ds Max에서 트위스트 뼈대를 생성하고 제어하는 다양한 기능을 제공합니다.
|
22
30
|
MAXScript의 _TwistBone 구조체 개념을 Python으로 재구현한 클래스이며,
|
23
31
|
3ds Max의 기능들을 pymxs API를 통해 제어합니다.
|
32
|
+
|
33
|
+
트위스트 뼈대는 상체(Upper)와 하체(Lower) 두 가지 타입으로 생성이 가능하며,
|
34
|
+
각각 다른 회전 표현식을 사용하여 자연스러운 회전 움직임을 구현합니다.
|
24
35
|
"""
|
25
36
|
|
26
|
-
def __init__(self, nameService=None, animService=None,
|
37
|
+
def __init__(self, nameService=None, animService=None, constraintService=None, bipService=None, boneService=None):
|
27
38
|
"""
|
28
|
-
클래스 초기화.
|
39
|
+
TwistBone 클래스 초기화.
|
40
|
+
|
41
|
+
의존성 주입 방식으로 필요한 서비스들을 외부에서 제공받거나 내부에서 생성합니다.
|
42
|
+
서비스들이 제공되지 않을 경우 각 서비스의 기본 인스턴스를 생성하여 사용합니다.
|
29
43
|
|
30
44
|
Args:
|
31
|
-
nameService: 이름 처리
|
32
|
-
animService: 애니메이션
|
33
|
-
|
34
|
-
bipService: 바이페드
|
45
|
+
nameService (Name, optional): 이름 처리 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
|
46
|
+
animService (Anim, optional): 애니메이션 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
|
47
|
+
constraintService (Constraint, optional): 제약 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
|
48
|
+
bipService (Bip, optional): 바이페드 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
|
49
|
+
boneService (Bone, optional): 뼈대 서비스. 기본값은 None이며, 제공되지 않으면 새로 생성됩니다.
|
35
50
|
"""
|
36
51
|
self.name = nameService if nameService else Name()
|
37
52
|
self.anim = animService if animService else Anim()
|
38
53
|
# Ensure dependent services use the potentially newly created instances
|
39
|
-
self.const =
|
54
|
+
self.const = constraintService if constraintService else Constraint(nameService=self.name)
|
40
55
|
self.bip = bipService if bipService else Bip(animService=self.anim, nameService=self.name)
|
41
56
|
self.bone = boneService if boneService else Bone(nameService=self.name, animService=self.anim)
|
42
57
|
|
43
|
-
#
|
44
|
-
self.
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
"
|
52
|
-
"
|
53
|
-
"
|
54
|
-
"
|
55
|
-
"
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
"
|
61
|
-
"
|
62
|
-
"
|
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))"
|
97
|
-
)
|
98
|
-
|
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))"
|
58
|
+
# 객체 속성 초기화
|
59
|
+
self.limb = None
|
60
|
+
self.child = None
|
61
|
+
self.twistNum = 0
|
62
|
+
self.bones = []
|
63
|
+
self.twistType = ""
|
64
|
+
|
65
|
+
self.upperTwistBoneExpression = (
|
66
|
+
"localTm = limb.transform * (inverse limbParent.transform)\n"
|
67
|
+
"tm = localTm * inverse(localRefTm)\n"
|
68
|
+
"\n"
|
69
|
+
"q = tm.rotation\n"
|
70
|
+
"\n"
|
71
|
+
"axis = [1,0,0]\n"
|
72
|
+
"proj = (dot q.axis axis) * axis\n"
|
73
|
+
"twist = quat q.angle proj\n"
|
74
|
+
"twist = normalize twist\n"
|
75
|
+
"--swing = tm.rotation * (inverse twist)\n"
|
76
|
+
"\n"
|
77
|
+
"inverse twist\n"
|
117
78
|
)
|
118
79
|
|
119
|
-
|
120
|
-
|
121
|
-
"
|
122
|
-
"
|
123
|
-
"
|
80
|
+
self.lowerTwistBoneExpression = (
|
81
|
+
"localTm = limb.transform * (inverse limbParent.transform)\n"
|
82
|
+
"tm = localTm * inverse(localRefTm)\n"
|
83
|
+
"\n"
|
84
|
+
"q = tm.rotation\n"
|
85
|
+
"\n"
|
86
|
+
"axis = [1,0,0]\n"
|
87
|
+
"proj = (dot q.axis axis) * axis\n"
|
88
|
+
"twist = quat q.angle proj\n"
|
89
|
+
"twist = normalize twist\n"
|
90
|
+
"--swing = tm.rotation * (inverse twist)\n"
|
91
|
+
"\n"
|
92
|
+
"twist\n"
|
124
93
|
)
|
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
94
|
|
139
|
-
|
140
|
-
생성된 트위스트 뼈대 체인 배열
|
95
|
+
def reset(self):
|
141
96
|
"""
|
142
|
-
|
143
|
-
|
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)
|
156
|
-
)
|
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
|
-
|
243
|
-
boneChainArray.append(TwistBoneEnd)
|
97
|
+
클래스의 주요 컴포넌트들을 초기화합니다.
|
98
|
+
서비스가 아닌 클래스 자체의 작업 데이터를 초기화하는 함수입니다.
|
244
99
|
|
245
|
-
|
246
|
-
|
247
|
-
def reorder_bones(self, inBoneChainArray):
|
100
|
+
Returns:
|
101
|
+
self: 메소드 체이닝을 위한 자기 자신 반환
|
248
102
|
"""
|
249
|
-
|
103
|
+
self.limb = None
|
104
|
+
self.child = None
|
105
|
+
self.twistNum = 0
|
106
|
+
self.bones = []
|
107
|
+
self.twistType = ""
|
250
108
|
|
251
|
-
|
252
|
-
inBoneChainArray: 재배치할 뼈대 체인 배열
|
109
|
+
return self
|
253
110
|
|
254
|
-
|
255
|
-
재배치된 뼈대 체인 배열
|
111
|
+
def create_upper_limb_bones(self, inObj, inChild, twistNum=4):
|
256
112
|
"""
|
257
|
-
|
258
|
-
returnBoneArray = []
|
113
|
+
상체(팔, 어깨 등) 부분의 트위스트 뼈대를 생성하는 메소드.
|
259
114
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
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):
|
281
|
-
"""
|
282
|
-
상완(Upper Arm) 타입의 트위스트 뼈대 생성
|
115
|
+
상체용 트위스트 뼈대는 부모 객체(inObj)의 위치에서 시작하여
|
116
|
+
자식 객체(inChild) 방향으로 여러 개의 뼈대를 생성합니다.
|
117
|
+
생성된 뼈대들은 스크립트 컨트롤러를 통해 자동으로 회전되어
|
118
|
+
자연스러운 트위스트 움직임을 표현합니다.
|
283
119
|
|
284
120
|
Args:
|
285
|
-
inObj: 상완
|
286
|
-
|
287
|
-
|
288
|
-
Returns:
|
289
|
-
생성된 트위스트 뼈대 체인 또는 False(실패 시)
|
290
|
-
"""
|
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) 타입의 트위스트 뼈대 생성
|
121
|
+
inObj: 트위스트 뼈대의 부모 객체(뼈). 일반적으로 상완 또는 대퇴부에 해당합니다.
|
122
|
+
inChild: 자식 객체(뼈). 일반적으로 전완 또는 하퇴부에 해당합니다.
|
123
|
+
twistNum (int, optional): 생성할 트위스트 뼈대의 개수. 기본값은 4입니다.
|
309
124
|
|
310
|
-
Args:
|
311
|
-
inObj: 전완 뼈대 객체
|
312
|
-
inTwistNum: 트위스트 뼈대 개수
|
313
|
-
side: 좌/우측 ("left" 또는 "right", 기본값: "left")
|
314
|
-
|
315
125
|
Returns:
|
316
|
-
생성된 트위스트 뼈대
|
126
|
+
BoneChain: 생성된 트위스트 뼈대 BoneChain 객체
|
317
127
|
"""
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
128
|
+
limb = inObj
|
129
|
+
distance = rt.distance(limb, inChild)
|
130
|
+
facingDirVec = inChild.transform.position - inObj.transform.position
|
131
|
+
inObjXAxisVec = inObj.objectTransform.row1
|
132
|
+
distanceDir = 1.0 if rt.dot(inObjXAxisVec, facingDirVec) > 0 else -1.0
|
133
|
+
offssetAmount = (distance / twistNum) * distanceDir
|
323
134
|
|
324
|
-
|
325
|
-
TBExpression = self.lForeArmExpression if self.bip.is_left_node(inObj) else self.rForeArmExpression
|
135
|
+
boneChainArray = []
|
326
136
|
|
327
|
-
#
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
137
|
+
# 첫 번째 트위스트 뼈대 생성
|
138
|
+
boneName = self.name.add_suffix_to_real_name(inObj.name, self.name._get_filtering_char(inObj.name) + "Twist")
|
139
|
+
if inObj.name[0].islower():
|
140
|
+
boneName = boneName.lower()
|
141
|
+
twistBone = self.bone.create_nub_bone(boneName, 2)
|
142
|
+
twistBone.name = self.name.replace_name_part("Index", boneName, "1")
|
143
|
+
twistBone.name = self.name.remove_name_part("Nub", twistBone.name)
|
144
|
+
twistBone.transform = limb.transform
|
145
|
+
twistBone.parent = limb
|
146
|
+
twistBoneLocalRefTM = limb.transform * rt.inverse(limb.parent.transform)
|
147
|
+
|
148
|
+
twistBoneRotListController = self.const.assign_rot_list(twistBone)
|
149
|
+
twistBoneController = rt.Rotation_Script()
|
150
|
+
twistBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
|
151
|
+
twistBoneController.addNode("limb", limb)
|
152
|
+
twistBoneController.addNode("limbParent", limb.parent)
|
153
|
+
twistBoneController.setExpression(self.upperTwistBoneExpression)
|
154
|
+
twistBoneController.update()
|
155
|
+
|
156
|
+
rt.setPropertyController(twistBoneRotListController, "Available", twistBoneController)
|
157
|
+
twistBoneRotListController.delete(1)
|
158
|
+
twistBoneRotListController.setActive(twistBoneRotListController.count)
|
159
|
+
twistBoneRotListController.weight[0] = 100.0
|
160
|
+
|
161
|
+
boneChainArray.append(twistBone)
|
162
|
+
|
163
|
+
if twistNum > 1:
|
164
|
+
lastBone = self.bone.create_nub_bone(boneName, 2)
|
165
|
+
lastBone.name = self.name.replace_name_part("Index", boneName, str(twistNum))
|
166
|
+
lastBone.name = self.name.remove_name_part("Nub", lastBone.name)
|
167
|
+
lastBone.transform = limb.transform
|
168
|
+
lastBone.parent = limb
|
169
|
+
self.anim.move_local(lastBone, offssetAmount*(twistNum-1), 0, 0)
|
332
170
|
|
333
|
-
|
334
|
-
weightVal = 100 / (inTwistNum - 1)
|
171
|
+
weightVal = 100.0 / (twistNum-1)
|
335
172
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
173
|
+
if twistNum > 2:
|
174
|
+
for i in range(1, twistNum-1):
|
175
|
+
twistExtraBone = self.bone.create_nub_bone(boneName, 2)
|
176
|
+
twistExtraBone.name = self.name.replace_name_part("Index", boneName, str(i+1))
|
177
|
+
twistExtraBone.name = self.name.remove_name_part("Nub", twistExtraBone.name)
|
178
|
+
twistExtraBone.transform = limb.transform
|
179
|
+
twistExtraBone.parent = limb
|
180
|
+
self.anim.move_local(twistExtraBone, offssetAmount*i, 0, 0)
|
181
|
+
|
182
|
+
twistExtraBoneRotListController = self.const.assign_rot_list(twistExtraBone)
|
183
|
+
twistExtraBoneController = rt.Rotation_Script()
|
184
|
+
twistExtraBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
|
185
|
+
twistExtraBoneController.addNode("limb", limb)
|
186
|
+
twistExtraBoneController.addNode("limbParent", limb.parent)
|
187
|
+
twistExtraBoneController.setExpression(self.upperTwistBoneExpression)
|
188
|
+
|
189
|
+
rt.setPropertyController(twistExtraBoneRotListController, "Available", twistExtraBoneController)
|
190
|
+
twistExtraBoneRotListController.delete(1)
|
191
|
+
twistExtraBoneRotListController.setActive(twistExtraBoneRotListController.count)
|
192
|
+
twistExtraBoneRotListController.weight[0] = weightVal * (twistNum-1-i)
|
193
|
+
|
194
|
+
boneChainArray.append(twistExtraBone)
|
355
195
|
|
356
|
-
|
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) 타입의 트위스트 뼈대 생성
|
196
|
+
boneChainArray.append(lastBone)
|
378
197
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
"""
|
387
|
-
if inObj.parent is None or inObj.children.count == 0:
|
388
|
-
return False
|
389
|
-
|
390
|
-
controllerLimb = None
|
391
|
-
weightVal = 100
|
198
|
+
# 결과를 BoneChain 형태로 준비
|
199
|
+
result = {
|
200
|
+
"Bones": boneChainArray,
|
201
|
+
"Helpers": [],
|
202
|
+
"SourceBones": [inObj, inChild],
|
203
|
+
"Parameters": [twistNum, "Upper"]
|
204
|
+
}
|
392
205
|
|
393
|
-
#
|
394
|
-
|
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
|
-
)
|
206
|
+
# 메소드 호출 후 데이터 초기화
|
207
|
+
self.reset()
|
412
208
|
|
413
|
-
return
|
414
|
-
|
415
|
-
def
|
416
|
-
"""
|
417
|
-
굽힘(Bend) 타입의 트위스트 뼈대 생성
|
418
|
-
(아직 구현되지 않음)
|
419
|
-
"""
|
420
|
-
pass
|
421
|
-
|
422
|
-
def get_upperArm_type(self, inObj):
|
209
|
+
return BoneChain.from_result(result)
|
210
|
+
|
211
|
+
def create_lower_limb_bones(self, inObj, inChild, twistNum=4):
|
423
212
|
"""
|
424
|
-
|
213
|
+
하체(팔뚝, 다리 등) 부분의 트위스트 뼈대를 생성하는 메소드.
|
214
|
+
|
215
|
+
하체용 트위스트 뼈대는 부모 객체(inObj)의 위치에서 시작하여
|
216
|
+
자식 객체(inChild) 쪽으로 여러 개의 뼈대를 생성합니다.
|
217
|
+
상체와는 다른 회전 표현식을 사용하여 하체에 적합한 트위스트 움직임을 구현합니다.
|
425
218
|
|
426
219
|
Args:
|
427
|
-
inObj:
|
428
|
-
|
220
|
+
inObj: 트위스트 뼈대의 부모 객체(뼈). 일반적으로 전완 또는 하퇴부에 해당합니다.
|
221
|
+
inChild: 자식 객체(뼈). 일반적으로 손목 또는 발목에 해당합니다.
|
222
|
+
twistNum (int, optional): 생성할 트위스트 뼈대의 개수. 기본값은 4입니다.
|
223
|
+
|
429
224
|
Returns:
|
430
|
-
|
225
|
+
BoneChain: 생성된 트위스트 뼈대 BoneChain 객체
|
431
226
|
"""
|
432
|
-
|
433
|
-
|
434
|
-
|
227
|
+
limb = inChild
|
228
|
+
distance = rt.distance(inObj, inChild)
|
229
|
+
facingDirVec = inChild.transform.position - inObj.transform.position
|
230
|
+
inObjXAxisVec = inObj.objectTransform.row1
|
231
|
+
distanceDir = 1.0 if rt.dot(inObjXAxisVec, facingDirVec) > 0 else -1.0
|
232
|
+
offssetAmount = (distance / twistNum) * distanceDir
|
435
233
|
|
436
|
-
|
437
|
-
return returnVal
|
234
|
+
boneChainArray = []
|
438
235
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
236
|
+
# 첫 번째 트위스트 뼈대 생성
|
237
|
+
boneName = self.name.add_suffix_to_real_name(inObj.name, self.name._get_filtering_char(inObj.name) + "Twist")
|
238
|
+
if inObj.name[0].islower():
|
239
|
+
boneName = boneName.lower()
|
240
|
+
twistBone = self.bone.create_nub_bone(boneName, 2)
|
241
|
+
twistBone.name = self.name.replace_name_part("Index", boneName, "1")
|
242
|
+
twistBone.name = self.name.remove_name_part("Nub", twistBone.name)
|
243
|
+
twistBone.transform = inObj.transform
|
244
|
+
twistBone.parent = inObj
|
245
|
+
self.anim.move_local(twistBone, offssetAmount*(twistNum-1), 0, 0)
|
246
|
+
twistBoneLocalRefTM = limb.transform * rt.inverse(limb.parent.transform)
|
247
|
+
|
248
|
+
twistBoneRotListController = self.const.assign_rot_list(twistBone)
|
249
|
+
twistBoneController = rt.Rotation_Script()
|
250
|
+
twistBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
|
251
|
+
twistBoneController.addNode("limb", limb)
|
252
|
+
twistBoneController.addNode("limbParent", limb.parent)
|
253
|
+
twistBoneController.setExpression(self.lowerTwistBoneExpression)
|
254
|
+
twistBoneController.update()
|
255
|
+
|
256
|
+
rt.setPropertyController(twistBoneRotListController, "Available", twistBoneController)
|
257
|
+
twistBoneRotListController.delete(1)
|
258
|
+
twistBoneRotListController.setActive(twistBoneRotListController.count)
|
259
|
+
twistBoneRotListController.weight[0] = 100.0
|
260
|
+
|
261
|
+
if twistNum > 1:
|
262
|
+
lastBone = self.bone.create_nub_bone(boneName, 2)
|
263
|
+
lastBone.name = self.name.replace_name_part("Index", boneName, str(twistNum))
|
264
|
+
lastBone.name = self.name.remove_name_part("Nub", lastBone.name)
|
265
|
+
lastBone.transform = inObj.transform
|
266
|
+
lastBone.parent = inObj
|
267
|
+
self.anim.move_local(lastBone, 0, 0, 0)
|
443
268
|
|
444
|
-
|
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)
|
450
|
-
|
451
|
-
return returnVal
|
452
|
-
|
453
|
-
def get_foreArm_type(self, inObj):
|
454
|
-
"""
|
455
|
-
전완(Forearm) 타입의 트위스트 뼈대 가져오기
|
456
|
-
|
457
|
-
Args:
|
458
|
-
inObj: 전완 뼈대 객체
|
269
|
+
weightVal = 100.0 / (twistNum-1)
|
459
270
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
271
|
+
if twistNum > 2:
|
272
|
+
for i in range(1, twistNum-1):
|
273
|
+
twistExtraBone = self.bone.create_nub_bone(boneName, 2)
|
274
|
+
twistExtraBone.name = self.name.replace_name_part("Index", boneName, str(i+1))
|
275
|
+
twistExtraBone.name = self.name.remove_name_part("Nub", twistExtraBone.name)
|
276
|
+
twistExtraBone.transform = inObj.transform
|
277
|
+
twistExtraBone.parent = inObj
|
278
|
+
self.anim.move_local(twistExtraBone, offssetAmount*(twistNum-1-i), 0, 0)
|
279
|
+
|
280
|
+
twistExtraBoneRotListController = self.const.assign_rot_list(twistExtraBone)
|
281
|
+
twistExtraBoneController = rt.Rotation_Script()
|
282
|
+
twistExtraBoneController.addConstant("localRefTm", twistBoneLocalRefTM)
|
283
|
+
twistExtraBoneController.addNode("limb", limb)
|
284
|
+
twistExtraBoneController.addNode("limbParent", limb.parent)
|
285
|
+
twistExtraBoneController.setExpression(self.lowerTwistBoneExpression)
|
286
|
+
|
287
|
+
rt.setPropertyController(twistExtraBoneRotListController, "Available", twistExtraBoneController)
|
288
|
+
twistExtraBoneRotListController.delete(1)
|
289
|
+
twistExtraBoneRotListController.setActive(twistExtraBoneRotListController.count)
|
290
|
+
twistExtraBoneRotListController.weight[0] = weightVal * (twistNum-1-i)
|
291
|
+
|
292
|
+
boneChainArray.append(twistExtraBone)
|
474
293
|
|
475
|
-
|
476
|
-
for child in children:
|
477
|
-
if rt.matchPattern(child.name, pattern="*Twist*") and rt.classOf(child) == rt.BoneGeometry:
|
478
|
-
returnVal.append(child)
|
294
|
+
boneChainArray.append(lastBone)
|
479
295
|
|
480
|
-
|
296
|
+
# 결과를 BoneChain 형태로 준비
|
297
|
+
result = {
|
298
|
+
"Bones": boneChainArray,
|
299
|
+
"Helpers": [],
|
300
|
+
"SourceBones": [inObj, inChild],
|
301
|
+
"Parameters": [twistNum, "Lower"]
|
302
|
+
}
|
481
303
|
|
482
|
-
|
304
|
+
# 메소드 호출 후 데이터 초기화
|
305
|
+
self.reset()
|
306
|
+
|
307
|
+
return BoneChain.from_result(result)
|
483
308
|
|
484
|
-
def
|
309
|
+
def create_bones_from_chain(self, inBoneChain: BoneChain):
|
485
310
|
"""
|
486
|
-
|
311
|
+
기존 BoneChain 객체에서 트위스트 본을 생성합니다.
|
312
|
+
기존 설정을 복원하거나 저장된 데이터에서 트위스트 본 셋업을 재생성할 때 사용합니다.
|
487
313
|
|
488
314
|
Args:
|
489
|
-
|
490
|
-
|
315
|
+
inBoneChain (BoneChain): 트위스트 본 정보를 포함한 BoneChain 객체
|
316
|
+
|
491
317
|
Returns:
|
492
|
-
|
318
|
+
BoneChain: 업데이트된 BoneChain 객체 또는 실패 시 None
|
493
319
|
"""
|
494
|
-
|
495
|
-
|
496
|
-
parentBipObj = None
|
497
|
-
|
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)
|
320
|
+
if not inBoneChain or inBoneChain.is_empty():
|
321
|
+
return None
|
505
322
|
|
506
|
-
|
507
|
-
|
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: 종아리 뼈대 객체
|
323
|
+
# 기존 객체 삭제
|
324
|
+
inBoneChain.delete()
|
521
325
|
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
returnVal = []
|
526
|
-
|
527
|
-
parentBipObj = None
|
326
|
+
# BoneChain에서 필요한 정보 추출
|
327
|
+
sourceBones = inBoneChain.sourceBones
|
328
|
+
parameters = inBoneChain.parameters
|
528
329
|
|
529
|
-
|
530
|
-
|
531
|
-
|
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)
|
330
|
+
# 필수 소스 본 확인
|
331
|
+
if len(sourceBones) < 2 or not rt.isValidNode(sourceBones[0]) or not rt.isValidNode(sourceBones[1]):
|
332
|
+
return None
|
536
333
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
returnVal.append(child)
|
334
|
+
# 파라미터 가져오기 (또는 기본값 사용)
|
335
|
+
twistNum = parameters[0] if len(parameters) > 0 else 4
|
336
|
+
twistType = parameters[1] if len(parameters) > 1 else "Upper"
|
541
337
|
|
542
|
-
|
338
|
+
# 본 생성
|
339
|
+
inObj = sourceBones[0]
|
340
|
+
inChild = sourceBones[1]
|
543
341
|
|
544
|
-
|
342
|
+
# 타입에 따라 적절한 방식으로 트위스트 본 생성
|
343
|
+
if twistType == "Upper":
|
344
|
+
return self.create_upper_limb_bones(inObj, inChild, twistNum)
|
345
|
+
else:
|
346
|
+
return self.create_lower_limb_bones(inObj, inChild, twistNum)
|