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/groinBone.py CHANGED
@@ -10,11 +10,9 @@ from pymxs import runtime as rt
10
10
  # Import necessary service classes for default initialization
11
11
  from .name import Name
12
12
  from .anim import Anim
13
- from .constraint import Constraint
14
- from .bip import Bip
15
- from .bone import Bone
16
13
  from .helper import Helper
17
- from .twistBone import TwistBone
14
+ from .bone import Bone
15
+ from .constraint import Constraint
18
16
 
19
17
  class GroinBone:
20
18
  """
@@ -22,69 +20,141 @@ class GroinBone:
22
20
  3DS Max에서 고간 부 본을 생성하고 관리하는 기능을 제공합니다.
23
21
  """
24
22
 
25
- def __init__(self, nameService=None, animService=None, helperService=None, constService=None, bipService=None, boneService=None, twistBoneService=None):
23
+ def __init__(self, nameService=None, animService=None, constraintService=None, boneService=None, helperService=None):
26
24
  """
27
25
  클래스 초기화.
28
26
 
29
27
  Args:
30
28
  nameService: 이름 처리 서비스 (제공되지 않으면 새로 생성)
31
29
  animService: 애니메이션 서비스 (제공되지 않으면 새로 생성)
32
- constService: 제약 서비스 (제공되지 않으면 새로 생성)
33
- bipService: 바이페드 서비스 (제공되지 않으면 새로 생성)
30
+ constraintService: 제약 서비스 (제공되지 않으면 새로 생성)
31
+ bipService: Biped 서비스 (제공되지 않으면 새로 생성)
32
+ boneService: 뼈대 서비스 (제공되지 않으면 새로 생성)
33
+ twistBoneService: 트위스트 본 서비스 (제공되지 않으면 새로 생성)
34
+ helperService: 헬퍼 객체 서비스 (제공되지 않으면 새로 생성)
34
35
  """
36
+ # 서비스 인스턴스 설정 또는 생성
35
37
  self.name = nameService if nameService else Name()
36
38
  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)
39
+
40
+ # 종속성이 있는 서비스들은 이미 생성된 서비스들을 전달
41
+ self.const = constraintService if constraintService else Constraint(nameService=self.name)
40
42
  self.bone = boneService if boneService else Bone(nameService=self.name, animService=self.anim)
41
- self.twistBone = twistBoneService if twistBoneService else TwistBone(nameService=self.name, animService=self.anim, constService=self.const, bipService=self.bip, boneService=self.bone)
42
43
  self.helper = helperService if helperService else Helper(nameService=self.name)
44
+
45
+ # 초기화된 결과를 저장할 변수들
46
+ self.pelvis = None
47
+ self.lThighTwist = None
48
+ self.rThighTwist = None
49
+ self.bones = []
50
+ self.helpers = []
51
+ self.pelvisWeight = 40.0
52
+ self.thighWeight = 60.0
43
53
 
44
- def create_bone(self, inObj):
54
+ def reset(self):
55
+ """
56
+ 클래스의 주요 컴포넌트들을 초기화합니다.
57
+ 서비스가 아닌 클래스 자체의 작업 데이터를 초기화하는 함수입니다.
58
+
59
+ Returns:
60
+ self: 메소드 체이닝을 위한 자기 자신 반환
61
+ """
62
+ self.pelvis = None
63
+ self.lThighTwist = None
64
+ self.rThighTwist = None
65
+ self.bones = []
66
+ self.helpers = []
67
+ self.pelvisWeight = 40.0
68
+ self.thighWeight = 60.0
69
+
70
+ return self
71
+
72
+ def create_bone(self, inPelvis, inLThighTwist, inRThighTwist, inPelvisWeight=40.0, inThighWeight=60.0):
45
73
  """
46
74
  고간 부 본을 생성하는 메소드.
47
75
 
48
76
  Args:
49
- name: 생성할 본의 이름
50
- parent: 부모 (제공되지 않으면 None)
77
+ inPelvis: Biped 객체
78
+ inPelvisWeight: 골반 가중치 (기본값: 40.0)
79
+ inThighWeight: 허벅지 가중치 (기본값: 60.0)
51
80
 
52
81
  Returns:
53
- 생성된 객체
82
+ 성공 여부 (Boolean)
54
83
  """
55
- if self.bip.is_biped_object(inObj) == False:
56
- rt.messageBox("This is not a biped object.")
84
+ returnVal = {
85
+ "Pelvis": None,
86
+ "LThighTwist": None,
87
+ "RThighTwist": None,
88
+ "Bones": [],
89
+ "Helpers": [],
90
+ "PelvisWeight": inPelvisWeight,
91
+ "ThighWeight": inThighWeight
92
+ }
93
+ if rt.isValidNode(inPelvis) == False or rt.isValidNode(inLThighTwist) == False or rt.isValidNode(inRThighTwist) == False:
94
+ rt.messageBox("There is no valid node.")
57
95
  return False
58
96
 
59
- bipObj = self.bip.get_com(inObj)
97
+ groinName = "Groin"
98
+ if inPelvis.name[0].islower():
99
+ groinName = groinName.lower()
60
100
 
61
- lThigh = self.bip.get_grouped_nodes(inObj, "lLeg")[0]
62
- rThigh = self.bip.get_grouped_nodes(inObj, "rLeg")[0]
63
- pelvis = self.bip.get_grouped_nodes(inObj, "pelvis")[0]
101
+ groinBaseName = self.name.replace_name_part("RealName", inPelvis.name, groinBaseName)
64
102
 
65
- lThighTwists = self.twistBone.get_thigh_type(lThigh)
66
- rThighTwists = self.twistBone.get_thigh_type(rThigh)
103
+ pelvisHelperName = self.name.replace_name_part("Type", groinBaseName, self.name.get_name_part_value_by_description("Type", "Dummy"))
104
+ pelvisHelperName = self.name.replace_name_part("Index", pelvisHelperName, "00")
105
+ pelvisHelper = self.helper.create_point(pelvisHelperName)
106
+ pelvisHelper.transform = inPelvis.transform
107
+ self.anim.rotate_local(pelvisHelper, 0.0, 0.0, -180.0)
108
+ pelvisHelper.parent = inPelvis
109
+ self.helper.set_shape_to_box(pelvisHelper)
67
110
 
68
- if len(lThighTwists) == 0 or len(rThighTwists) == 0:
69
- rt.messageBox("There is no twist bone.")
70
- return False
111
+ lThighTwistHelperName = self.name.replace_name_part("Type", groinBaseName, self.name.get_name_part_value_by_description("Type", "Dummy"))
112
+ lThighTwistHelperName = self.name.replace_name_part("Side", lThighTwistHelperName, self.name.get_name_part_value_by_description("Side", "Left"))
113
+ lThighTwistHelperName = self.name.replace_name_part("Index", lThighTwistHelperName, "00")
114
+ lThighTwistHelper = self.helper.create_point(lThighTwistHelperName)
115
+ lThighTwistHelper.transform = pelvisHelper.transform
116
+ lThighTwistHelper.position = inLThighTwist.position
117
+ lThighTwistHelper.parent = inLThighTwist
118
+ self.helper.set_shape_to_box(lThighTwistHelper)
71
119
 
72
- pelvisHelper = self.helper.create_point(bipObj.name + " Dum Groin 00")
73
- pelvisHelper.transform = bipObj.transform
74
- self.anim.rotate_local(pelvisHelper, 90, 0, 0)
75
- self.anim.rotate_local(pelvisHelper, 0, 0, -90)
76
- pelvisHelper.parent = pelvis
77
- self.helper.set_shape_to_box(pelvisHelper)
120
+ rThighTwistHelperName = self.name.replace_name_part("Type", groinBaseName, self.name.get_name_part_value_by_description("Type", "Dummy"))
121
+ rThighTwistHelperName = self.name.replace_name_part("Side", rThighTwistHelperName, self.name.get_name_part_value_by_description("Side", "Right"))
122
+ rThighTwistHelperName = self.name.replace_name_part("Index", rThighTwistHelperName, "00")
123
+ rThighTwistHelper = self.helper.create_point(rThighTwistHelperName)
124
+ rThighTwistHelper.transform = pelvisHelper.transform
125
+ rThighTwistHelper.position = inRThighTwist.position
126
+ rThighTwistHelper.parent = inRThighTwist
127
+ self.helper.set_shape_to_box(rThighTwistHelper)
78
128
 
79
- groinBones = self.bone.create_simple_bone(3.0, bipObj.name +" Groin 00", size=2)
129
+ groinBoneName = self.name.replace_name_part("Index", groinBaseName, "00")
130
+ groinBones = self.bone.create_simple_bone(3.0, groinBoneName, size=2)
80
131
  groinBones[0].transform = pelvisHelper.transform
81
- groinBones[0].parent = pelvis
132
+ groinBones[0].parent = inPelvis
82
133
 
83
- self.const.assign_rot_const_multi(groinBones[0], [pelvisHelper, lThigh, rThigh])
134
+ self.const.assign_rot_const_multi(groinBones[0], [pelvisHelper, lThighTwistHelper, rThighTwistHelper])
84
135
  rotConst = self.const.get_rot_list_controller(groinBones[0])[1]
85
- rotConst.setWeight(1, 40.0)
86
- rotConst.setWeight(2, 30.0)
87
- rotConst.setWeight(3, 30.0)
136
+ rotConst.setWeight(1, inPelvisWeight)
137
+ rotConst.setWeight(2, inThighWeight/2.0)
138
+ rotConst.setWeight(3, inThighWeight/2.0)
139
+
140
+ # 결과를 멤버 변수에 저장
141
+ self.pelvis = inPelvis
142
+ self.lThighTwist = inLThighTwist
143
+ self.rThighTwist = inRThighTwist
144
+ self.bones = groinBones
145
+ self.helpers = [pelvisHelper, lThighTwistHelper, rThighTwistHelper]
146
+ self.pelvisWeight = inPelvisWeight
147
+ self.thighWeight = inThighWeight
148
+
149
+ returnVal["Pelvis"] = inPelvis
150
+ returnVal["LThighTwist"] = inLThighTwist
151
+ returnVal["RThighTwist"] = inRThighTwist
152
+ returnVal["Bones"] = groinBones
153
+ returnVal["Helpers"] = [pelvisHelper, lThighTwistHelper, rThighTwistHelper]
154
+ returnVal["PelvisWeight"] = inPelvisWeight
155
+ returnVal["ThighWeight"] = inThighWeight
88
156
 
157
+ # 메소드 호출 후 데이터 초기화
158
+ self.reset()
89
159
 
90
-
160
+ return returnVal
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ 고간 부 본 체인(Groin Bone Chain) 관련 기능을 제공하는 클래스.
6
+ GroinBone 클래스가 생성한 고간 부 본들과 헬퍼들을 관리하고 접근하는 인터페이스를 제공합니다.
7
+
8
+ Examples:
9
+ # GroinBone 클래스로 고간 본 생성 후 체인으로 관리하기
10
+ groin_bone = GroinBone()
11
+ biped_obj = rt.selection[0] # 선택된 바이패드 객체
12
+
13
+ # 고간 본 생성
14
+ success = groin_bone.create_bone(biped_obj, 40.0, 60.0)
15
+ if success:
16
+ # 생성된 본과 헬퍼로 체인 생성
17
+ chain = GroinBoneChain.from_groin_bone_result(
18
+ groin_bone.genBones,
19
+ groin_bone.genHelpers,
20
+ biped_obj,
21
+ 40.0,
22
+ 60.0
23
+ )
24
+
25
+ # 체인 가중치 업데이트
26
+ chain.update_weights(35.0, 65.0)
27
+
28
+ # 본과 헬퍼 이름 변경
29
+ chain.rename_bones(prefix="Character_", suffix="_Groin")
30
+ chain.rename_helpers(prefix="Character_", suffix="_Helper")
31
+
32
+ # 현재 가중치 값 확인
33
+ pelvis_w, thigh_w = chain.get_weights()
34
+ print(f"Current weights: Pelvis={pelvis_w}, Thigh={thigh_w}")
35
+
36
+ # 체인 삭제
37
+ # chain.delete_all()
38
+ """
39
+
40
+ from pymxs import runtime as rt
41
+ from pyjallib.max.header import get_pyjallibmaxheader
42
+ jal = get_pyjallibmaxheader()
43
+
44
+ class GroinBoneChain:
45
+ def __init__(self, inResult):
46
+ """
47
+ 클래스 초기화.
48
+
49
+ Args:
50
+ bones: 고간 부 본 체인을 구성하는 뼈대 배열 (기본값: None)
51
+ helpers: 고간 부 본과 연관된 헬퍼 객체 배열 (기본값: None)
52
+ biped_obj: 연관된 Biped 객체 (기본값: None)
53
+ """
54
+ self.pelvis =inResult["Pelvis"]
55
+ self.lThighTwist = inResult["LThighTwist"]
56
+ self.rThighTwist = inResult["RThighTwist"]
57
+ self.bones = inResult["Bones"]
58
+ self.helpers = inResult["Helpers"]
59
+ self.pelvisWeight = inResult["PelvisWeight"]
60
+ self.thighWeight = inResult["ThighWeight"]
61
+
62
+ def is_empty(self):
63
+ """
64
+ 체인이 비어있는지 확인
65
+
66
+ Returns:
67
+ 본과 헬퍼가 모두 비어있으면 True, 아니면 False
68
+ """
69
+ return len(self.bones) == 0 and len(self.helpers) == 0
70
+
71
+ def clear(self):
72
+ """체인의 모든 본과 헬퍼 참조 제거"""
73
+ self.bones = []
74
+ self.helpers = []
75
+ self.pelvis = None
76
+ self.lThighTwist = None
77
+ self.rThighTwist = None
78
+ self.pelvisWeight = 40.0 # 기본 골반 가중치
79
+ self.thighWeight = 60.0 # 기본 허벅지 가중치
80
+
81
+ def delete(self):
82
+ """
83
+ 체인의 모든 본과 헬퍼를 3ds Max 씬에서 삭제
84
+
85
+ Returns:
86
+ 삭제 성공 여부 (boolean)
87
+ """
88
+ if self.is_empty():
89
+ return False
90
+
91
+ try:
92
+ rt.delete(self.bones)
93
+ rt.delete(self.helpers)
94
+ return True
95
+ except:
96
+ return False
97
+
98
+ def delete_all(self):
99
+ """
100
+ 체인의 모든 본과 헬퍼를 3ds Max 씬에서 삭제
101
+
102
+ Returns:
103
+ 삭제 성공 여부 (boolean)
104
+ """
105
+ if self.is_empty():
106
+ return False
107
+
108
+ try:
109
+ rt.delete(self.bones)
110
+ rt.delete(self.helpers)
111
+ self.clear()
112
+ return True
113
+ except:
114
+ return False
115
+
116
+ def update_weights(self, pelvisWeight=None, thighWeight=None):
117
+ """
118
+ 고간 부 본의 가중치 업데이트
119
+
120
+ Args:
121
+ pelvisWeight: 골반 가중치 (None인 경우 현재 값 유지)
122
+ thighWeight: 허벅지 가중치 (None인 경우 현재 값 유지)
123
+
124
+ Returns:
125
+ 업데이트 성공 여부 (boolean)
126
+ """
127
+ if self.is_empty():
128
+ return False
129
+
130
+ # 새 가중치 설정
131
+ if pelvisWeight is not None:
132
+ self.pelvisWeight = pelvisWeight
133
+ if thighWeight is not None:
134
+ self.thighWeight = thighWeight
135
+
136
+ self.delete()
137
+ result = jal.groinBone.create_bone(
138
+ self.pelvis,
139
+ self.lThighTwist,
140
+ self.rThighTwist,
141
+ self.pelvisWeight,
142
+ self.thighWeight
143
+ )
144
+ self.bones = result["Bones"]
145
+ self.helpers = result["Helpers"]
146
+
147
+ def get_weights(self):
148
+ """
149
+ 현재 설정된 가중치 값 가져오기
150
+
151
+ Returns:
152
+ (pelvis_weight, thigh_weight) 형태의 튜플
153
+ """
154
+ return (self.pelvis_weight, self.thigh_weight)
155
+
156
+ @classmethod
157
+ def from_groin_bone_result(cls, inResult):
158
+ """
159
+ GroinBone 클래스의 결과로부터 GroinBoneChain 인스턴스 생성
160
+
161
+ Args:
162
+ bones: GroinBone 클래스가 생성한 뼈대 배열
163
+ helpers: GroinBone 클래스가 생성한 헬퍼 배열
164
+ biped_obj: 연관된 Biped 객체 (기본값: None)
165
+ pelvisWeight: 골반 가중치 (기본값: 40.0)
166
+ thighWeight: 허벅지 가중치 (기본값: 60.0)
167
+
168
+ Returns:
169
+ GroinBoneChain 인스턴스
170
+ """
171
+ chain = cls(inResult)
172
+
173
+ return chain
pyjallib/max/header.py CHANGED
@@ -25,9 +25,11 @@ from .bip import Bip
25
25
  from .skin import Skin
26
26
 
27
27
  from .twistBone import TwistBone
28
- from .groinBone import GroinBone
29
28
  from .autoClavicle import AutoClavicle
30
- from .volumePreserveBone import VolumePreserveBone
29
+ from .groinBone import GroinBone
30
+ from .volumeBone import VolumeBone
31
+ from .kneeBone import KneeBone
32
+ from .hip import Hip
31
33
 
32
34
  from .morph import Morph
33
35
 
@@ -68,14 +70,46 @@ class Header:
68
70
  self.bip = Bip(animService=self.anim, nameService=self.name, boneService=self.bone)
69
71
  self.skin = Skin()
70
72
 
71
- self.twistBone = TwistBone(nameService=self.name, animService=self.anim, constService=self.constraint, bipService=self.bip, boneService=self.bone)
72
- self.groinBone = GroinBone(nameService=self.name, animService=self.anim, helperService=self.helper, constService=self.constraint, bipService=self.bip, boneService=self.bone, twistBoneService=self.twistBone)
73
+ self.twistBone = TwistBone(nameService=self.name, animService=self.anim, constraintService=self.constraint, bipService=self.bip, boneService=self.bone)
74
+ self.groinBone = GroinBone(nameService=self.name, animService=self.anim, constraintService=self.constraint, boneService=self.bone, helperService=self.helper)
73
75
  self.autoClavicle = AutoClavicle(nameService=self.name, animService=self.anim, helperService=self.helper, boneService=self.bone, constraintService=self.constraint, bipService=self.bip)
74
- self.volumePreserveBone = VolumePreserveBone(nameService=self.name, animService=self.anim, constService=self.constraint, boneService=self.bone, helperService=self.helper)
76
+ self.volumeBone = VolumeBone(nameService=self.name, animService=self.anim, constraintService=self.constraint, boneService=self.bone, helperService=self.helper)
77
+ self.kneeBone = KneeBone(nameService=self.name, animService=self.anim, constraintService=self.constraint, boneService=self.bone, helperService=self.helper, volumeBoneService=self.volumeBone)
78
+ self.hip = Hip(nameService=self.name, animService=self.anim, helperService=self.helper, boneService=self.bone, constraintService=self.constraint)
75
79
 
76
80
  self.morph = Morph()
77
81
 
78
82
  self.tools = []
83
+
84
+ def update_nameConifg(self, configPath):
85
+ """
86
+ 이름 설정을 업데이트합니다.
87
+
88
+ Args:
89
+ configPath: ConfigPath 인스턴스
90
+ """
91
+ self.name.load_from_config_file(configPath)
92
+
93
+ def add_tool(self, tool):
94
+ """
95
+ 도구를 추가합니다.
96
+
97
+ Args:
98
+ tool: 추가할 도구
99
+ """
100
+ if tool in self.tools:
101
+ self.tools.remove(tool)
102
+
103
+ self.tools.append(tool)
79
104
 
80
105
  # 모듈 레벨에서 전역 인스턴스 생성
81
- jal = Header.get_instance()
106
+ _pyjallibmaxheader = Header.get_instance()
107
+
108
+ def get_pyjallibmaxheader():
109
+ """
110
+ jal 인스턴스를 반환합니다.
111
+
112
+ Returns:
113
+ Header 인스턴스
114
+ """
115
+ return _pyjallibmaxheader
pyjallib/max/helper.py CHANGED
@@ -93,30 +93,12 @@ class Helper:
93
93
  찾은 Type namePart 값
94
94
  """
95
95
  typePart = self.name.get_name_part("Type")
96
- predefinedValues = typePart.get_predefined_values()
97
96
  firstTypeValue = typePart.get_value_by_min_weight()
98
97
 
98
+ helperTypeName = self.name.get_name_part_value_by_description("Type", helperType)
99
+ if helperTypeName != "":
100
+ return helperTypeName
99
101
 
100
- # 헬퍼 타입 패턴 정의
101
- helperNamePatterns = {
102
- "Dummy": ["dum", "Dum", "Dummy", "Helper", "Hpr", "Dmy"],
103
- "IK": ["ik", "IK", "Ik"],
104
- "Target": ["Tgt", "Target", "TG", "Tg", "T"],
105
- "Parent": ["Prn", "PRN", "Parent", "P"],
106
- "ExposeTm": ["Exp", "Etm", "EXP", "ETM"]
107
- }
108
-
109
- # 타입 패턴 가져오기
110
- patterns = helperNamePatterns.get(helperType, [])
111
- if not patterns:
112
- return firstTypeValue
113
-
114
- # 패턴과 일치하는 값 찾기
115
- for value in predefinedValues:
116
- if value in patterns:
117
- return value
118
-
119
- # 일치하는 값이 없으면 기본값 반환
120
102
  return firstTypeValue
121
103
 
122
104
  def gen_helper_name_from_obj(self, inObj, make_two=False, is_exp=False):