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/max/hip.py CHANGED
@@ -1,366 +1,276 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- Hip 모듈 - 3ds Max용 Hip 관련 기능 제공
6
- 원본 MAXScript의 hip.ms를 Python으로 변환하였으며, pymxs 모듈 기반으로 구현됨
7
- """
8
-
9
- from pymxs import runtime as rt
10
- from .header import jal
11
-
12
-
13
- class Hip:
14
- """
15
- Hip 관련 기능을 제공하는 클래스.
16
- MAXScript의 _Hip 구조체 개념을 Python으로 재구현한 클래스이며,
17
- 3ds Max의 기능들을 pymxs API를 통해 제어합니다.
18
- """
19
-
20
- def __init__(self):
21
- """
22
- 클래스 초기화.
23
-
24
- Args:
25
- nameService: 이름 처리 서비스 (제공되지 않으면 새로 생성)
26
- animService: 애니메이션 서비스 (제공되지 않으면 새로 생성)
27
- helperService: 헬퍼 객체 관련 서비스 (제공되지 않으면 새로 생성)
28
- boneService: 뼈대 관련 서비스 (제공되지 않으면 새로 생성)
29
- constraintService: 제약 관련 서비스 (제공되지 않으면 새로 생성)
30
- bipService: Biped 관련 서비스 (제공되지 않으면 새로 생성)
31
- """
32
- # 서비스 초기화
33
- self.name = jal.name
34
- self.anim = jal.anim
35
- self.helper = jal.helper
36
- self.bone = jal.bone
37
- self.const = jal.constraint
38
- self.bip = jal.bip
39
-
40
- # 기본 속성 초기화
41
- self.bone_size = 2.0
42
- self.bone_array = []
43
- self.pelvis_weight = 60.0
44
- self.thigh_weight = 40.0
45
- self.x_axis_offset = 0.1
46
-
47
- # 객체 참조 초기화
48
- self.spine_dummy = None
49
- self.l_hip_dummy = None
50
- self.l_hip_target_dummy = None
51
- self.l_hip_exp = None
52
- self.r_hip_dummy = None
53
- self.r_hip_target_dummy = None
54
- self.r_hip_exp = None
55
-
56
- self.pelvis = None
57
- self.spine = None
58
- self.l_thigh = None
59
- self.l_thigh_twist = None
60
- self.r_thigh = None
61
- self.r_thigh_twist = None
62
-
63
- self.helper_array = []
64
-
65
- def init(self, in_bip, in_l_thigh_twist, in_r_thigh_twist,
66
- in_x_axis_offset=0.1,
67
- in_pelvis_weight=60.0, in_thigh_weight=40.0,
68
- in_bone_size=2.0):
69
-
70
- self.bone_size = in_bone_size
71
- self.x_axis_offset = in_x_axis_offset
72
-
73
- self.pelvis_weight = in_pelvis_weight
74
- self.thigh_weight = in_thigh_weight
75
-
76
- self.pelvis = self.bip.get_grouped_nodes(in_bip, "pelvis")[0]
77
- self.spine = rt.biped.getNode(in_bip, rt.Name("spine"), link=1)
78
- self.l_thigh = rt.biped.getNode(in_bip, rt.Name("lleg"), link=1)
79
- self.r_thigh = rt.biped.getNode(in_bip, rt.Name("rleg"), link=1)
80
- self.l_thigh_twist = in_l_thigh_twist
81
- self.r_thigh_twist = in_r_thigh_twist
82
-
83
- self.bone_array = []
84
- self.helper_array = []
85
-
86
- def assign_position_script(self, in_obj, in_exp, in_scale="0.1"):
87
- """
88
- 위치 스크립트 컨트롤러 할당
89
-
90
- Args:
91
- in_obj: 대상 객체
92
- in_exp: 표현식 객체 (ExposeTm)
93
- in_scale: 스케일 (문자열)
94
- """
95
- # 위치 리스트 컨트롤러 할당
96
- pos_list = self.const.assign_pos_list(in_obj)
97
-
98
- # 위치 스크립트 컨트롤러 생성
99
- pos_script = rt.position_script()
100
- rt.setPropertyController(pos_list, "Available", pos_script)
101
- pos_list.setActive(pos_list.count)
102
-
103
- # 표현식 객체 추가 및 스크립트 설정
104
- pos_script.AddNode("exp", in_exp)
105
- script_str = ""
106
- script_str += "zRotValue = amin 0.0 exp.localEulerZ\n"
107
- script_str += f"result = [0, zRotValue * {in_scale}, 0]\n"
108
- script_str += "result"
109
-
110
- pos_script.SetExpression(script_str)
111
- pos_script.Update()
112
-
113
- # 마지막 컨트롤러 활성화
114
- self.const.set_active_last(in_obj)
115
-
116
- def update_position_script_scale_value(self, in_obj, in_val):
117
- """
118
- 위치 스크립트 스케일 값 업데이트
119
-
120
- Args:
121
- in_obj: 대상 객체
122
- in_val: 새 스케일 값
123
- """
124
- # 위치 리스트 컨트롤러 가져오기
125
- pos_list = self.const.get_pos_list_controller(in_obj)
126
-
127
- if pos_list is not None and pos_list.count >= 3:
128
- # 위치 스크립트 컨트롤러 가져오기
129
- pos_script = rt.getPropertyController(pos_list, "Controller3")
130
-
131
- # pos_script가 Position_Script 형태인지 확인
132
- if rt.classOf(pos_script) == rt.Position_Script:
133
- new_scale = str(in_val)
134
- script_str = ""
135
- script_str += "zRotValue = amin 0.0 exp.localEulerZ\n"
136
- script_str += f"result = [0, zRotValue * {new_scale}, 0]\n"
137
- script_str += "result"
138
-
139
- pos_script.SetExpression(script_str)
140
- pos_script.Update()
141
-
142
- def gen_helpers(self):
143
- """
144
- 헬퍼 객체 생성
145
-
146
- Returns:
147
- 생성된 헬퍼 객체 배열
148
- """
149
- self.spine_dummy = self.helper.create_point(
150
- self.name.combine(in_base=self.base_name,
151
- in_type=self.name.get_dummyStr(),
152
- in_real_name="HipSpine",
153
- in_index="0",
154
- in_fil_char=self.filtering_char),
155
- box_toggle=True, cross_toggle=False, axis_toggle=False
156
- )
157
-
158
- self.l_hip_dummy = self.helper.create_point(
159
- self.name.combine(in_base=self.base_name,
160
- in_type=self.name.get_dummyStr(),
161
- in_side=self.name.get_leftStr(),
162
- in_real_name="Hip",
163
- in_index="0",
164
- in_fil_char=self.filtering_char),
165
- box_toggle=True, cross_toggle=False, axis_toggle=False
166
- )
167
-
168
- self.l_hip_target_dummy = self.helper.create_point(
169
- self.name.combine(in_base=self.base_name,
170
- in_type=self.name.get_dummyStr(),
171
- in_side=self.name.get_leftStr(),
172
- in_real_name="HipTgt",
173
- in_index="0",
174
- in_fil_char=self.filtering_char),
175
- box_toggle=False, cross_toggle=True, axis_toggle=False
176
- )
177
-
178
- # ExposeTm 객체 생성
179
- self.l_hip_exp = rt.ExposeTm(
180
- name=self.name.combine(in_base=self.base_name,
181
- in_type=self.name.get_exposeTMStr(),
182
- in_side=self.name.get_leftStr(),
183
- in_real_name="Hip",
184
- in_index="0",
185
- in_fil_char=self.filtering_char),
186
- size=1,
187
- boxToggle=True,
188
- crossToggle=False,
189
- wirecolor=rt.color(14, 255, 2)
190
- )
191
-
192
- self.r_hip_dummy = self.helper.create_point(
193
- self.name.combine(in_base=self.base_name,
194
- in_type=self.name.get_dummyStr(),
195
- in_side=self.name.get_rightStr(),
196
- in_real_name="Hip",
197
- in_index="0",
198
- in_fil_char=self.filtering_char),
199
- box_toggle=True, cross_toggle=False, axis_toggle=False
200
- )
201
-
202
- self.r_hip_target_dummy = self.helper.create_point(
203
- self.name.combine(in_base=self.base_name,
204
- in_type=self.name.get_dummyStr(),
205
- in_side=self.name.get_rightStr(),
206
- in_real_name="HipTgt",
207
- in_index="0",
208
- in_fil_char=self.filtering_char),
209
- box_toggle=False, cross_toggle=True, axis_toggle=False
210
- )
211
-
212
- # ExposeTm 객체 생성
213
- self.r_hip_exp = rt.ExposeTm(
214
- name=self.name.combine(in_base=self.base_name,
215
- in_type=self.name.get_exposeTMStr(),
216
- in_side=self.name.get_rightStr(),
217
- in_real_name="Hip",
218
- in_index="0",
219
- in_fil_char=self.filtering_char),
220
- size=1,
221
- boxToggle=True,
222
- crossToggle=False,
223
- wirecolor=rt.color(14, 255, 2)
224
- )
225
-
226
- self.helper_array = []
227
- self.helper_array.append(self.spine_dummy)
228
- self.helper_array.append(self.l_hip_dummy)
229
- self.helper_array.append(self.l_hip_target_dummy)
230
- self.helper_array.append(self.l_hip_exp)
231
- self.helper_array.append(self.r_hip_dummy)
232
- self.helper_array.append(self.r_hip_target_dummy)
233
- self.helper_array.append(self.r_hip_exp)
234
-
235
- return self.helper_array
236
-
237
- def create(self):
238
- """
239
- Hip 리깅 생성
240
- """
241
- self.gen_helpers()
242
-
243
- self.l_hip_dummy.transform = self.l_thigh_twist.transform
244
- self.r_hip_dummy.transform = self.r_thigh_twist.transform
245
-
246
- self.const.assign_pos_const(self.spine_dummy, self.spine)
247
- self.const.assign_rot_const_multi(self.spine_dummy, [self.l_thigh_twist, self.r_thigh_twist])
248
- self.const.collapse(self.spine_dummy)
249
-
250
- self.l_hip_dummy.parent = self.pelvis
251
- self.l_hip_target_dummy.parent = self.pelvis
252
- self.l_hip_exp.parent = self.pelvis
253
- self.r_hip_dummy.parent = self.pelvis
254
- self.r_hip_target_dummy.parent = self.pelvis
255
- self.r_hip_exp.parent = self.pelvis
256
- self.spine_dummy.parent = self.pelvis
257
-
258
- # 왼쪽 hip dummy의 rotation constraint 설정
259
- self.const.assign_rot_list(self.l_hip_dummy)
260
- rot_const = rt.Orientation_Constraint()
261
- rot_list = self.const.get_rot_list_controller(self.l_hip_dummy)
262
- rt.setPropertyController(rot_list, "Available", rot_const)
263
- rot_list.setActive(rot_list.count)
264
-
265
- # Constraint 타겟 추가
266
- rot_const.appendTarget(self.spine_dummy, self.pelvis_weight)
267
- rot_const.appendTarget(self.l_thigh_twist, self.thigh_weight)
268
- rot_const.relative = True
269
-
270
- # 오른쪽 hip dummy의 rotation constraint 설정
271
- self.const.assign_rot_list(self.r_hip_dummy)
272
- rot_const = rt.Orientation_Constraint()
273
- rot_list = self.const.get_rot_list_controller(self.r_hip_dummy)
274
- rt.setPropertyController(rot_list, "Available", rot_const)
275
- rot_list.setActive(rot_list.count)
276
-
277
- # Constraint 타겟 추가
278
- rot_const.appendTarget(self.spine_dummy, self.pelvis_weight)
279
- rot_const.appendTarget(self.r_thigh_twist, self.thigh_weight)
280
- rot_const.relative = True
281
-
282
- self.l_hip_target_dummy.transform = self.l_hip_dummy.transform
283
- self.l_hip_exp.transform = self.l_hip_dummy.transform
284
- self.r_hip_target_dummy.transform = self.r_hip_dummy.transform
285
- self.r_hip_exp.transform = self.r_hip_dummy.transform
286
-
287
- self.l_hip_exp.exposeNode = self.l_hip_dummy
288
- self.l_hip_exp.localReferenceNode = self.l_hip_target_dummy
289
- self.l_hip_exp.useParent = False
290
-
291
- self.r_hip_exp.exposeNode = self.r_hip_dummy
292
- self.r_hip_exp.localReferenceNode = self.r_hip_target_dummy
293
- self.r_hip_exp.useParent = False
294
-
295
- self.bone_array = []
296
-
297
- # 왼쪽 Hip 본 생성
298
- l_hip_bone = self.bone.create_simple_bone(
299
- (self.bone_size * 2),
300
- self.name.combine(
301
- in_base=self.base_name,
302
- in_side=self.name.get_leftStr(),
303
- in_real_name="Hip",
304
- in_fil_char=self.filtering_char
305
- ),
306
- size=self.bone_size
307
- )
308
-
309
- l_hip_bone[0].transform = self.l_thigh.transform
310
- self.anim.rotate_local(
311
- l_hip_bone[0],
312
- (self.rot_dir[0] * 0),
313
- (self.rot_dir[1] * 0),
314
- (self.rot_dir[2] * 90)
315
- )
316
- l_hip_bone[0].parent = self.l_hip_dummy
317
- self.bone_array.append(l_hip_bone[0])
318
- self.bone_array.append(l_hip_bone[1])
319
-
320
- # 오른쪽 Hip 본 생성
321
- r_hip_bone = self.bone.create_simple_bone(
322
- (self.bone_size * 2),
323
- self.name.combine(
324
- in_base=self.base_name,
325
- in_side=self.name.get_rightStr(),
326
- in_real_name="Hip",
327
- in_fil_char=self.filtering_char
328
- ),
329
- size=self.bone_size
330
- )
331
-
332
- r_hip_bone[0].transform = self.r_thigh.transform
333
- self.anim.rotate_local(
334
- r_hip_bone[0],
335
- (self.rot_dir[0] * 0),
336
- (self.rot_dir[1] * 0),
337
- (self.rot_dir[2] * 90)
338
- )
339
- r_hip_bone[0].parent = self.r_hip_dummy
340
- self.bone_array.append(r_hip_bone[0])
341
- self.bone_array.append(r_hip_bone[1])
342
-
343
- # 위치 스크립트 설정
344
- self.assign_position_script(l_hip_bone[0], self.l_hip_exp, in_scale=str(self.x_axis_offset))
345
- self.assign_position_script(r_hip_bone[0], self.r_hip_exp, in_scale=str(self.x_axis_offset))
346
-
347
- def del_all(self):
348
- """
349
- 모든 생성된 본과 헬퍼 객체 삭제
350
- """
351
- self.bone.delete_bones_safely(self.bone_array)
352
- self.bone.delete_bones_safely(self.helper_array)
353
-
354
- def set_weight(self, in_pelvis_weight, in_thigh_weight):
355
- """
356
- 골반과 허벅지 가중치 설정
357
-
358
- Args:
359
- in_pelvis_weight: 골반 가중치
360
- in_thigh_weight: 허벅지 가중치
361
- """
362
- self.del_all()
363
- self.pelvis_weight = in_pelvis_weight
364
- self.thigh_weight = in_thigh_weight
365
-
366
- self.create()
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Hip 모듈 - 3ds Max용 Hip 관련 기능 제공
6
+ 원본 MAXScript의 hip.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 .helper import Helper
15
+ from .bone import Bone
16
+ from .constraint import Constraint
17
+
18
+ from .boneChain import BoneChain
19
+
20
+
21
+ class Hip:
22
+ """
23
+ Hip 관련 기능을 제공하는 클래스.
24
+ MAXScript의 _Hip 구조체 개념을 Python으로 재구현한 클래스이며,
25
+ 3ds Max의 기능들을 pymxs API를 통해 제어합니다.
26
+ """
27
+
28
+ def __init__(self, nameService=None, animService=None, helperService=None, boneService=None, constraintService=None):
29
+ """
30
+ 클래스 초기화.
31
+
32
+ Args:
33
+ nameService: 이름 처리 서비스 (제공되지 않으면 새로 생성)
34
+ animService: 애니메이션 서비스 (제공되지 않으면 새로 생성)
35
+ helperService: 헬퍼 객체 관련 서비스 (제공되지 않으면 새로 생성)
36
+ boneService: 뼈대 관련 서비스 (제공되지 않으면 새로 생성)
37
+ constraintService: 제약 관련 서비스 (제공되지 않으면 새로 생성)
38
+ bipService: Biped 관련 서비스 (제공되지 않으면 새로 생성)
39
+ """
40
+ # 서비스 인스턴스 설정 또는 생성
41
+ self.name = nameService if nameService else Name()
42
+ self.anim = animService if animService else Anim()
43
+
44
+ # 종속성이 있는 서비스들은 이미 생성된 서비스들을 전달
45
+ self.helper = helperService if helperService else Helper(nameService=self.name)
46
+ self.const = constraintService if constraintService else Constraint(nameService=self.name, helperService=self.helper)
47
+ self.bone = boneService if boneService else Bone(nameService=self.name, animService=self.anim, helperService=self.helper, constraintService=self.const)
48
+
49
+ # 기본 속성 초기화
50
+ self.pelvisWeight = 0.4
51
+ self.thighWeight = 0.6
52
+ self.pushAmount = 20
53
+
54
+ self.pelvis = None
55
+ self.thigh = None
56
+ self.thighTwist = None
57
+ self.calf = None
58
+
59
+ self.pelvisHelper = None
60
+ self.thighHelper = None
61
+ self.thighTwistHelper = None
62
+ self.thighRotHelper = None
63
+ self.thighPosHelper = None
64
+ self.thighRotRootHelper = None
65
+
66
+ self.helpers = []
67
+ self.bones = []
68
+
69
+ self.posScriptExpression = (
70
+ "localLimbTm = limb.transform * inverse limbParent.transform\n"
71
+ "localDeltaTm = localLimbTm * inverse localRotRefTm\n"
72
+ "\n"
73
+ "q = localDeltaTm.rotation\n"
74
+ "\n"
75
+ "eulerRot = (quatToEuler q order:5)\n"
76
+ "swizzledRot = (eulerAngles eulerRot.y eulerRot.z eulerRot.x)\n"
77
+ "\n"
78
+ "axis = [0,0,1]\n"
79
+ "\n"
80
+ "saturatedTwistZ = (swizzledRot.x*axis.x + swizzledRot.y*axis.y + swizzledRot.z*axis.z)/180.0\n"
81
+ "pushScaleY = (amax 0.0 saturatedTwistZ) * 0.5\n"
82
+ "\n"
83
+ "axis = [0,1,0]\n"
84
+ "saturatedTwistY = (swizzledRot.x*axis.x + swizzledRot.y*axis.y + swizzledRot.z*axis.z)/180.0\n"
85
+ "pushScaleZ = amax 0.0 saturatedTwistY\n"
86
+ "\n"
87
+ "\n"
88
+ "[0, pushAmount * pushScaleY, -pushAmount * pushScaleZ]\n"
89
+ )
90
+
91
+ def reset(self):
92
+ """
93
+ 클래스의 주요 컴포넌트들을 초기화합니다.
94
+ 서비스가 아닌 클래스 자체의 작업 데이터를 초기화하는 함수입니다.
95
+
96
+ Returns:
97
+ self: 메소드 체이닝을 위한 자기 자신 반환
98
+ """
99
+ self.pelvisWeight = 0.4
100
+ self.thighWeight = 0.6
101
+ self.pushAmount = 20
102
+
103
+ self.pelvis = None
104
+ self.thigh = None
105
+ self.thighTwist = None
106
+ self.calf = None
107
+
108
+ self.pelvisHelper = None
109
+ self.thighHelper = None
110
+ self.thighTwistHelper = None
111
+ self.thighRotHelper = None
112
+ self.thighPosHelper = None
113
+ self.thighRotRootHelper = None
114
+
115
+ self.helpers = []
116
+ self.bones = []
117
+
118
+ return self
119
+
120
+ def create_helper(self, inPelvis, inThigh, inThighTwist):
121
+ if not rt.isValidNode(inPelvis) or not rt.isValidNode(inThigh) or not rt.isValidNode(inThighTwist):
122
+ return False
123
+
124
+ self.pelvis = inPelvis
125
+ self.thigh = inThigh
126
+ self.thighTwist = inThighTwist
127
+
128
+ filteringChar = self.name._get_filtering_char(inThigh.name)
129
+ isLower = inThigh.name[0].islower()
130
+
131
+ pelvisHelperName = self.name.replace_name_part("RealName", inThigh.name, self.name.get_RealName(inPelvis.name)+filteringChar+"Hip")
132
+ pelvisHelperName = self.name.replace_name_part("Type", pelvisHelperName, self.name.get_name_part_value_by_description("Type", "Dummy"))
133
+ pelvisHelper = self.helper.create_point(pelvisHelperName)
134
+ rt.setProperty(pelvisHelper, "transform", inThigh.transform)
135
+ pelvisHelper.parent = inPelvis
136
+
137
+ tihgTwistHeleprName = self.name.replace_name_part("RealName", inThigh.name, self.name.get_RealName(inThighTwist.name)+filteringChar+"Hip")
138
+ tihgTwistHeleprName = self.name.replace_name_part("Type", tihgTwistHeleprName, self.name.get_name_part_value_by_description("Type", "Dummy"))
139
+ thighTwistHelper = self.helper.create_point(tihgTwistHeleprName)
140
+ rt.setProperty(thighTwistHelper, "transform", inThighTwist.transform)
141
+ thighTwistHelper.parent = inThighTwist
142
+
143
+ tihghRotHelperName = self.name.replace_name_part("RealName", inThigh.name, self.name.get_RealName(inThigh.name)+filteringChar+"Hip")
144
+ tihghRotHelperName = self.name.replace_name_part("Type", tihghRotHelperName, self.name.get_name_part_value_by_description("Type", "Rotation"))
145
+ thighRotHelper = self.helper.create_point(tihghRotHelperName)
146
+ rt.setProperty(thighRotHelper, "transform", inThighTwist.transform)
147
+ thighRotHelper.parent = inThigh
148
+
149
+ thighPosHelperName = self.name.replace_name_part("RealName", inThigh.name, self.name.get_RealName(inThigh.name)+filteringChar+"Hip")
150
+ thighPosHelperName = self.name.replace_name_part("Type", thighPosHelperName, self.name.get_name_part_value_by_description("Type", "Position"))
151
+ thighPosHelper = self.helper.create_point(thighPosHelperName)
152
+ rt.setProperty(thighPosHelper, "transform", inThighTwist.transform)
153
+ thighPosHelper.parent = thighRotHelper
154
+
155
+ thighRotRootHelperName = self.name.replace_name_part("RealName", inThigh.name, self.name.get_RealName(inThigh.name)+filteringChar+"Hip")
156
+ thighRotRootHelperName = self.name.replace_name_part("Type", thighRotRootHelperName, self.name.get_name_part_value_by_description("Type", "Dummy"))
157
+ thighRotRootHelper = self.helper.create_point(thighRotRootHelperName)
158
+ rt.setProperty(thighRotRootHelper, "transform", thighRotHelper.transform)
159
+ thighRotRootHelper.parent = inThighTwist
160
+
161
+ if isLower:
162
+ pelvisHelper.name = pelvisHelper.name.lower()
163
+ thighTwistHelper.name = thighTwistHelper.name.lower()
164
+ thighRotHelper.name = thighRotHelper.name.lower()
165
+ thighPosHelper.name = thighPosHelper.name.lower()
166
+ thighRotRootHelper.name = thighRotRootHelper.name.lower()
167
+
168
+ self.pelvisHelper = pelvisHelper
169
+ self.thighTwistHelper = thighTwistHelper
170
+ self.thighRotHelper = thighRotHelper
171
+ self.thighPosHelper = thighPosHelper
172
+ self.thighRotRootHelper = thighRotRootHelper
173
+
174
+ self.helpers.append(pelvisHelper)
175
+ self.helpers.append(thighTwistHelper)
176
+ self.helpers.append(thighRotHelper)
177
+ self.helpers.append(thighPosHelper)
178
+ self.helpers.append(thighRotRootHelper)
179
+
180
+ def assing_constraint(self, inCalf, inPelvisWeight=0.6, inThighWeight=0.4, inPushAmount=5.0):
181
+ self.calf = inCalf
182
+ self.pelvisWeight = inPelvisWeight
183
+ self.thighWeight = inThighWeight
184
+ self.pushAmount = rt.Float(inPushAmount)
185
+
186
+ facingDirVec = self.calf.transform.position - self.thigh.transform.position
187
+ inObjXAxisVec = self.thigh.objectTransform.row1
188
+ distanceDir = -1.0 if rt.dot(inObjXAxisVec, facingDirVec) > 0 else 1.0
189
+
190
+ rotConst = self.const.assign_rot_const_multi(self.thighRotHelper, [self.pelvisHelper, self.thighTwistHelper])
191
+ rotConst.setWeight(1, self.pelvisWeight * 100.0)
192
+ rotConst.setWeight(2, self.thighWeight * 100.0)
193
+
194
+ localRotRefTm = self.thighRotHelper.transform * rt.inverse(self.thighRotRootHelper.transform)
195
+ posConst = self.const.assign_pos_script_controller(self.thighPosHelper)
196
+ posConst.addNode("limb", self.thighRotHelper)
197
+ posConst.addNode("limbParent", self.thighRotRootHelper)
198
+ posConst.addConstant("localRotRefTm", localRotRefTm)
199
+ posConst.addConstant("pushAmount", self.pushAmount*distanceDir)
200
+ posConst.setExpression(self.posScriptExpression)
201
+ posConst.update()
202
+
203
+ def create_bone(self, inPelvis, inThigh, inThighTwist, inCalf, pushAmount=5.0, inPelvisWeight=0.6, inThighWeight=0.4):
204
+ if not rt.isValidNode(inPelvis) or not rt.isValidNode(inThigh) or not rt.isValidNode(inThighTwist):
205
+ return False
206
+
207
+ self.create_helper(inPelvis, inThigh, inThighTwist)
208
+ self.assing_constraint(inCalf, inPelvisWeight, inThighWeight, inPushAmount=pushAmount)
209
+
210
+ isLower = inThigh.name[0].islower()
211
+ hipBoneName = self.name.replace_name_part("RealName", inThigh.name, "Hip")
212
+ hipBone = self.bone.create_nub_bone(hipBoneName, 2)
213
+ hipBone.name = self.name.remove_name_part("Nub", hipBone.name)
214
+ if isLower:
215
+ hipBone.name = hipBone.name.lower()
216
+
217
+ rt.setProperty(hipBone, "transform", inThighTwist.transform)
218
+ hipBone.parent = inThigh
219
+
220
+ self.const.assign_rot_const(hipBone, self.thighRotHelper)
221
+ self.const.assign_pos_const(hipBone, self.thighPosHelper)
222
+
223
+ self.bones.append(hipBone)
224
+
225
+ # 결과를 딕셔너리 형태로 준비
226
+ result = {
227
+ "Bones": self.bones,
228
+ "Helpers": self.helpers,
229
+ "SourceBones": [inPelvis, inThigh, inThighTwist, inCalf],
230
+ "Parameters": [pushAmount, inPelvisWeight, inThighWeight]
231
+ }
232
+
233
+ # 메소드 호출 후 데이터 초기화
234
+ self.reset()
235
+
236
+ return BoneChain.from_result(result)
237
+
238
+ def create_bones_from_chain(self, inBoneChain: BoneChain):
239
+ """
240
+ 기존 BoneChain 객체에서 Hip 본을 생성합니다.
241
+ 기존 설정을 복원하거나 저장된 데이터에서 Hip 셋업을 재생성할 때 사용합니다.
242
+
243
+ Args:
244
+ inBoneChain (BoneChain): Hip 정보를 포함한 BoneChain 객체
245
+
246
+ Returns:
247
+ BoneChain: 업데이트된 BoneChain 객체 또는 실패 시 None
248
+ """
249
+ if not inBoneChain or inBoneChain.is_empty():
250
+ return None
251
+
252
+ # 기존 객체 삭제
253
+ inBoneChain.delete()
254
+
255
+ # BoneChain에서 필요한 정보 추출
256
+ sourceBones = inBoneChain.sourceBones
257
+ parameters = inBoneChain.parameters
258
+
259
+ # 필수 소스 본 확인
260
+ if len(sourceBones) < 4 or not all(rt.isValidNode(bone) for bone in sourceBones[:4]):
261
+ return None
262
+
263
+ # 파라미터 가져오기 (또는 기본값 사용)
264
+ pushAmount = parameters[0] if len(parameters) > 0 else 5.0
265
+ pelvisWeight = parameters[1] if len(parameters) > 1 else 0.6
266
+ thighWeight = parameters[2] if len(parameters) > 2 else 0.4
267
+
268
+ # Hip 생성
269
+ inPelvis = sourceBones[0]
270
+ inThigh = sourceBones[1]
271
+ inThighTwist = sourceBones[2]
272
+ inCalf = sourceBones[3]
273
+
274
+ # 새로운 Hip 생성
275
+ return self.create_bone(inPelvis, inThigh, inThighTwist, inCalf, pushAmount, pelvisWeight, thighWeight)
276
+