pyjallib 0.1.7__tar.gz → 0.1.8__tar.gz
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-0.1.7 → pyjallib-0.1.8}/PKG-INFO +1 -1
- {pyjallib-0.1.7 → pyjallib-0.1.8}/pyproject.toml +1 -1
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/__init__.py +1 -1
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/ConfigFiles/3DSMaxNamingConfig.json +2 -2
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/__init__.py +8 -1
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/constraint.py +39 -2
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/header.py +6 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/helper.py +6 -0
- pyjallib-0.1.8/src/pyjallib/max/morph.py +406 -0
- pyjallib-0.1.8/src/pyjallib/max/ui/Container.py +153 -0
- pyjallib-0.1.8/src/pyjallib/max/volumePreserveBone.py +171 -0
- pyjallib-0.1.8/tests/morph.ms +217 -0
- pyjallib-0.1.8/tests/volumePreserveBoneTest.py +35 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/uv.lock +1 -1
- {pyjallib-0.1.7 → pyjallib-0.1.8}/.gitignore +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/.python-version +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/README.md +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/.nojekyll +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/index.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/max.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/namePart.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/nameToPath.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/naming.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/namingConfig.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/perforce.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/pymxs.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/docs/reloadModules.html +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/ConfigFiles/namingConfig.json +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/align.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/anim.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/autoClavicle.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/bip.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/bone.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/groinBone.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/layer.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/link.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/macro/jal_macro_align.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/macro/jal_macro_bone.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/macro/jal_macro_constraint.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/macro/jal_macro_helper.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/macro/jal_macro_link.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/macro/jal_macro_select.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/mirror.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/name.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/select.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/skin.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/max/twistBone.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/namePart.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/nameToPath.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/naming.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/namingConfig.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/perforce.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/py.typed +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/src/pyjallib/reloadModules.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/tests/autoclavicle.ms +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/tests/autoclavicleTest.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/tests/globalVarTest.py +0 -0
- {pyjallib-0.1.7 → pyjallib-0.1.8}/tests/moduleImportTest.py +0 -0
@@ -34,8 +34,8 @@
|
|
34
34
|
{
|
35
35
|
"name": "Type",
|
36
36
|
"predefinedValues": [
|
37
|
-
"P",
|
38
37
|
"Dum",
|
38
|
+
"P",
|
39
39
|
"Exp",
|
40
40
|
"IK",
|
41
41
|
"T",
|
@@ -57,8 +57,8 @@
|
|
57
57
|
],
|
58
58
|
"type": "PREFIX",
|
59
59
|
"descriptions": [
|
60
|
-
"Parent",
|
61
60
|
"Dummy",
|
61
|
+
"Parent",
|
62
62
|
"ExposeTM",
|
63
63
|
"IK",
|
64
64
|
"Target",
|
@@ -24,10 +24,14 @@ from .link import Link
|
|
24
24
|
|
25
25
|
from .bip import Bip
|
26
26
|
from .skin import Skin
|
27
|
+
from .morph import Morph
|
27
28
|
|
28
29
|
from .twistBone import TwistBone
|
29
30
|
from .groinBone import GroinBone
|
30
31
|
from .autoClavicle import AutoClavicle
|
32
|
+
from .volumePreserveBone import VolumePreserveBone
|
33
|
+
|
34
|
+
from .ui.Container import Container
|
31
35
|
|
32
36
|
# 모듈 내보내기
|
33
37
|
__all__ = [
|
@@ -44,7 +48,10 @@ __all__ = [
|
|
44
48
|
'Link',
|
45
49
|
'Bip',
|
46
50
|
'Skin',
|
51
|
+
'Morph',
|
47
52
|
'TwistBone',
|
48
53
|
'GroinBone',
|
49
|
-
'AutoClavicle'
|
54
|
+
'AutoClavicle',
|
55
|
+
'VolumePreserveBone',
|
56
|
+
'Container'
|
50
57
|
]
|
@@ -212,6 +212,8 @@ class Constraint:
|
|
212
212
|
"""
|
213
213
|
for item in inTargetArray:
|
214
214
|
self.assign_pos_const(inObj, item, keepInit=keepInit)
|
215
|
+
|
216
|
+
return self.get_pos_const(inObj)
|
215
217
|
|
216
218
|
def add_target_to_pos_const(self, inObj, inTarget, inWeight):
|
217
219
|
"""
|
@@ -251,8 +253,36 @@ class Constraint:
|
|
251
253
|
posList = self.assign_pos_list(inObj)
|
252
254
|
|
253
255
|
# Position_XYZ 컨트롤러 할당
|
254
|
-
|
256
|
+
posXYZ = rt.Position_XYZ()
|
257
|
+
rt.setPropertyController(posList, "Available", posXYZ)
|
258
|
+
posList.setActive(posList.count)
|
259
|
+
|
260
|
+
return posXYZ
|
261
|
+
|
262
|
+
def assign_pos_script_controller(self, inObj):
|
263
|
+
"""
|
264
|
+
객체에 스크립트 기반 위치 컨트롤러를 할당.
|
265
|
+
|
266
|
+
Args:
|
267
|
+
inObj: 컨트롤러를 할당할 객체
|
268
|
+
|
269
|
+
Returns:
|
270
|
+
None
|
271
|
+
"""
|
272
|
+
# 위치 컨트롤러가 리스트 형태가 아니면 변환
|
273
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
274
|
+
if rt.classOf(pos_controller) != rt.Position_list:
|
275
|
+
rt.setPropertyController(inObj.controller, "Position", rt.Position_list())
|
276
|
+
|
277
|
+
# 위치 리스트 컨트롤러 가져오기
|
278
|
+
posList = self.assign_pos_list(inObj)
|
279
|
+
|
280
|
+
# 스크립트 기반 위치 컨트롤러 할당
|
281
|
+
scriptPos = rt.Position_Script()
|
282
|
+
rt.setPropertyController(posList, "Available", scriptPos)
|
255
283
|
posList.setActive(posList.count)
|
284
|
+
|
285
|
+
return scriptPos
|
256
286
|
|
257
287
|
def get_rot_list_controller(self, inObj):
|
258
288
|
"""
|
@@ -392,6 +422,8 @@ class Constraint:
|
|
392
422
|
"""
|
393
423
|
for item in inTargetArray:
|
394
424
|
self.assign_rot_const(inObj, item, keepInit=keepInit)
|
425
|
+
|
426
|
+
return self.get_rot_const(inObj)
|
395
427
|
|
396
428
|
def add_target_to_rot_const(self, inObj, inTarget, inWeight):
|
397
429
|
"""
|
@@ -431,8 +463,11 @@ class Constraint:
|
|
431
463
|
rotList = self.assign_rot_list(inObj)
|
432
464
|
|
433
465
|
# Euler_XYZ 컨트롤러 할당
|
434
|
-
|
466
|
+
eulerXYZ = rt.Euler_XYZ()
|
467
|
+
rt.setPropertyController(rotList, "Available", eulerXYZ)
|
435
468
|
rotList.setActive(rotList.count)
|
469
|
+
|
470
|
+
return eulerXYZ
|
436
471
|
|
437
472
|
def get_lookat(self, inObj):
|
438
473
|
"""
|
@@ -528,6 +563,8 @@ class Constraint:
|
|
528
563
|
"""
|
529
564
|
for item in inTargetArray:
|
530
565
|
self.assign_lookat(inObj, item, keepInit=keepInit)
|
566
|
+
|
567
|
+
return self.get_lookat(inObj)
|
531
568
|
|
532
569
|
def assign_lookat_flipless(self, inObj, inTarget):
|
533
570
|
"""
|
@@ -27,6 +27,9 @@ from .skin import Skin
|
|
27
27
|
from .twistBone import TwistBone
|
28
28
|
from .groinBone import GroinBone
|
29
29
|
from .autoClavicle import AutoClavicle
|
30
|
+
from .volumePreserveBone import VolumePreserveBone
|
31
|
+
|
32
|
+
from .morph import Morph
|
30
33
|
|
31
34
|
class Header:
|
32
35
|
"""
|
@@ -68,6 +71,9 @@ class Header:
|
|
68
71
|
self.twistBone = TwistBone(nameService=self.name, animService=self.anim, constService=self.constraint, bipService=self.bip, boneService=self.bone)
|
69
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)
|
70
73
|
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)
|
75
|
+
|
76
|
+
self.morph = Morph()
|
71
77
|
|
72
78
|
self.tools = []
|
73
79
|
|
@@ -264,6 +264,7 @@ class Helper:
|
|
264
264
|
부모 헬퍼 생성
|
265
265
|
"""
|
266
266
|
# 선택된 객체가 있는 경우에만 처리
|
267
|
+
returnHelpers = []
|
267
268
|
if rt.selection.count > 0:
|
268
269
|
selArray = rt.getCurrentSelection()
|
269
270
|
|
@@ -297,6 +298,11 @@ class Helper:
|
|
297
298
|
# 부모 헬퍼로 이름 변경
|
298
299
|
finalName = self.name.replace_name_part("Type", genPoint.name, self.get_name_by_type("Parent"))
|
299
300
|
rt.setProperty(genPoint, "name", finalName)
|
301
|
+
|
302
|
+
returnHelpers.append(genPoint)
|
303
|
+
|
304
|
+
return returnHelpers
|
305
|
+
|
300
306
|
|
301
307
|
def create_exp_tm(self):
|
302
308
|
"""
|
@@ -0,0 +1,406 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
모프(Morph) 모듈 - 3ds Max용 모프 타겟 관련 기능 제공
|
6
|
+
원본 MAXScript의 morph.ms를 Python으로 변환하였으며, pymxs 모듈 기반으로 구현됨
|
7
|
+
"""
|
8
|
+
|
9
|
+
from dataclasses import dataclass
|
10
|
+
from pymxs import runtime as rt
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass
|
14
|
+
class MorphChannel:
|
15
|
+
"""
|
16
|
+
모프 채널 정보를 저장하는 데이터 클래스
|
17
|
+
"""
|
18
|
+
index: int = 0
|
19
|
+
name: str = ""
|
20
|
+
hasData: bool = False
|
21
|
+
|
22
|
+
|
23
|
+
class Morph:
|
24
|
+
"""
|
25
|
+
모프(Morph) 관련 기능을 제공하는 클래스.
|
26
|
+
MAXScript의 _Morph 구조체 개념을 Python으로 재구현한 클래스이며,
|
27
|
+
3ds Max의 기능들을 pymxs API를 통해 제어합니다.
|
28
|
+
"""
|
29
|
+
|
30
|
+
def __init__(self):
|
31
|
+
"""클래스 초기화"""
|
32
|
+
self.channelMaxViewNum = 100
|
33
|
+
|
34
|
+
def get_modifier_index(self, inObj):
|
35
|
+
"""
|
36
|
+
객체에서 Morpher 모디파이어의 인덱스를 찾음
|
37
|
+
|
38
|
+
Args:
|
39
|
+
inObj: 검색할 객체
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
Morpher 모디파이어의 인덱스 (없으면 0)
|
43
|
+
"""
|
44
|
+
returnVal = 0
|
45
|
+
if len(inObj.modifiers) > 0:
|
46
|
+
for i in range(len(inObj.modifiers)):
|
47
|
+
if rt.classOf(inObj.modifiers[i]) == rt.Morpher:
|
48
|
+
returnVal = i + 1 # MaxScript는 1부터 시작하므로 +1 추가
|
49
|
+
|
50
|
+
return returnVal
|
51
|
+
|
52
|
+
def get_modifier(self, inObj):
|
53
|
+
"""
|
54
|
+
객체에서 Morpher 모디파이어를 찾음
|
55
|
+
|
56
|
+
Args:
|
57
|
+
inObj: 검색할 객체
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
Morpher 모디파이어 (없으면 None)
|
61
|
+
"""
|
62
|
+
returnVal = None
|
63
|
+
modIndex = self.get_modifier_index(inObj)
|
64
|
+
if modIndex > 0:
|
65
|
+
returnVal = inObj.modifiers[modIndex - 1] # Python 인덱스는 0부터 시작하므로 -1 조정
|
66
|
+
|
67
|
+
return returnVal
|
68
|
+
|
69
|
+
def get_channel_num(self, inObj):
|
70
|
+
"""
|
71
|
+
객체의 Morpher에 있는 채널 수를 반환
|
72
|
+
|
73
|
+
Args:
|
74
|
+
inObj: 검색할 객체
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
모프 채널 수
|
78
|
+
"""
|
79
|
+
returnVal = 0
|
80
|
+
morphMod = self.get_modifier(inObj)
|
81
|
+
if morphMod is not None:
|
82
|
+
morphChannelExistance = True
|
83
|
+
morphChannelCounter = 0
|
84
|
+
|
85
|
+
while morphChannelExistance:
|
86
|
+
for i in range(morphChannelCounter + 1, morphChannelCounter + self.channelMaxViewNum + 1):
|
87
|
+
if not rt.WM3_MC_HasData(morphMod, i):
|
88
|
+
returnVal = i - 1
|
89
|
+
morphChannelExistance = False
|
90
|
+
break
|
91
|
+
|
92
|
+
morphChannelCounter += self.channelMaxViewNum
|
93
|
+
|
94
|
+
return returnVal
|
95
|
+
|
96
|
+
def get_all_channel_info(self, inObj):
|
97
|
+
"""
|
98
|
+
객체의 모든 모프 채널 정보를 가져옴
|
99
|
+
|
100
|
+
Args:
|
101
|
+
inObj: 검색할 객체
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
MorphChannel 객체의 리스트
|
105
|
+
"""
|
106
|
+
returnVal = []
|
107
|
+
morphMod = self.get_modifier(inObj)
|
108
|
+
|
109
|
+
if morphMod is not None:
|
110
|
+
channelNum = self.get_channel_num(inObj)
|
111
|
+
if channelNum > 0:
|
112
|
+
for i in range(1, channelNum + 1):
|
113
|
+
tempChannel = MorphChannel()
|
114
|
+
tempChannel.index = i
|
115
|
+
tempChannel.hasData = rt.WM3_MC_HasData(morphMod, i)
|
116
|
+
tempChannel.name = rt.WM3_MC_GetName(morphMod, i)
|
117
|
+
returnVal.append(tempChannel)
|
118
|
+
|
119
|
+
return returnVal
|
120
|
+
|
121
|
+
def add_target(self, inObj, inTarget, inIndex):
|
122
|
+
"""
|
123
|
+
특정 인덱스에 모프 타겟 추가
|
124
|
+
|
125
|
+
Args:
|
126
|
+
inObj: 모프를 적용할 객체
|
127
|
+
inTarget: 타겟 객체
|
128
|
+
inIndex: 채널 인덱스
|
129
|
+
|
130
|
+
Returns:
|
131
|
+
성공 여부 (True/False)
|
132
|
+
"""
|
133
|
+
returnVal = False
|
134
|
+
morphMod = self.get_modifier(inObj)
|
135
|
+
|
136
|
+
if morphMod is not None:
|
137
|
+
rt.WM3_MC_BuildFromNode(morphMod, inIndex, inTarget)
|
138
|
+
returnVal = rt.WM3_MC_HasData(morphMod, inIndex)
|
139
|
+
|
140
|
+
return returnVal
|
141
|
+
|
142
|
+
def add_targets(self, inObj, inTargetArray):
|
143
|
+
"""
|
144
|
+
여러 타겟 객체를 순서대로 모프 채널에 추가
|
145
|
+
|
146
|
+
Args:
|
147
|
+
inObj: 모프를 적용할 객체
|
148
|
+
inTargetArray: 타겟 객체 배열
|
149
|
+
"""
|
150
|
+
morphMod = self.get_modifier(inObj)
|
151
|
+
|
152
|
+
if morphMod is not None:
|
153
|
+
for i in range(len(inTargetArray)):
|
154
|
+
rt.WM3_MC_BuildFromNode(morphMod, i + 1, inTargetArray[i])
|
155
|
+
|
156
|
+
def get_all_channel_name(self, inObj):
|
157
|
+
"""
|
158
|
+
객체의 모든 모프 채널 이름을 가져옴
|
159
|
+
|
160
|
+
Args:
|
161
|
+
inObj: 검색할 객체
|
162
|
+
|
163
|
+
Returns:
|
164
|
+
채널 이름 리스트
|
165
|
+
"""
|
166
|
+
returnVal = []
|
167
|
+
channelArray = self.get_all_channel_info(inObj)
|
168
|
+
|
169
|
+
if len(channelArray) > 0:
|
170
|
+
returnVal = [item.name for item in channelArray]
|
171
|
+
|
172
|
+
return returnVal
|
173
|
+
|
174
|
+
def get_channel_name(self, inObj, inIndex):
|
175
|
+
"""
|
176
|
+
특정 인덱스의 모프 채널 이름을 가져옴
|
177
|
+
|
178
|
+
Args:
|
179
|
+
inObj: 검색할 객체
|
180
|
+
inIndex: 채널 인덱스
|
181
|
+
|
182
|
+
Returns:
|
183
|
+
채널 이름 (없으면 빈 문자열)
|
184
|
+
"""
|
185
|
+
returnVal = ""
|
186
|
+
channelArray = self.get_all_channel_info(inObj)
|
187
|
+
|
188
|
+
try:
|
189
|
+
if len(channelArray) > 0:
|
190
|
+
returnVal = channelArray[inIndex - 1].name
|
191
|
+
except:
|
192
|
+
returnVal = ""
|
193
|
+
|
194
|
+
return returnVal
|
195
|
+
|
196
|
+
def get_channelIndex(self, inObj, inName):
|
197
|
+
"""
|
198
|
+
채널 이름으로 모프 채널 인덱스를 가져옴
|
199
|
+
|
200
|
+
Args:
|
201
|
+
inObj: 검색할 객체
|
202
|
+
inName: 채널 이름
|
203
|
+
|
204
|
+
Returns:
|
205
|
+
채널 인덱스 (없으면 0)
|
206
|
+
"""
|
207
|
+
returnVal = 0
|
208
|
+
channelArray = self.get_all_channel_info(inObj)
|
209
|
+
|
210
|
+
if len(channelArray) > 0:
|
211
|
+
for item in channelArray:
|
212
|
+
if item.name == inName:
|
213
|
+
returnVal = item.index
|
214
|
+
break
|
215
|
+
|
216
|
+
return returnVal
|
217
|
+
|
218
|
+
def get_channel_value_by_name(self, inObj, inName):
|
219
|
+
"""
|
220
|
+
채널 이름으로 모프 채널 값을 가져옴
|
221
|
+
|
222
|
+
Args:
|
223
|
+
inObj: 검색할 객체
|
224
|
+
inName: 채널 이름
|
225
|
+
|
226
|
+
Returns:
|
227
|
+
채널 값 (0.0 ~ 100.0)
|
228
|
+
"""
|
229
|
+
returnVal = 0.0
|
230
|
+
channelIndex = self.get_channelIndex(inObj, inName)
|
231
|
+
morphMod = self.get_modifier(inObj)
|
232
|
+
|
233
|
+
if channelIndex > 0:
|
234
|
+
try:
|
235
|
+
returnVal = rt.WM3_MC_GetValue(morphMod, channelIndex)
|
236
|
+
except:
|
237
|
+
returnVal = 0.0
|
238
|
+
|
239
|
+
return returnVal
|
240
|
+
|
241
|
+
def get_channel_value_by_index(self, inObj, inIndex):
|
242
|
+
"""
|
243
|
+
인덱스로 모프 채널 값을 가져옴
|
244
|
+
|
245
|
+
Args:
|
246
|
+
inObj: 검색할 객체
|
247
|
+
inIndex: 채널 인덱스
|
248
|
+
|
249
|
+
Returns:
|
250
|
+
채널 값 (0.0 ~ 100.0)
|
251
|
+
"""
|
252
|
+
returnVal = 0
|
253
|
+
morphMod = self.get_modifier(inObj)
|
254
|
+
|
255
|
+
if morphMod is not None:
|
256
|
+
try:
|
257
|
+
returnVal = rt.WM3_MC_GetValue(morphMod, inIndex)
|
258
|
+
except:
|
259
|
+
returnVal = 0
|
260
|
+
|
261
|
+
return returnVal
|
262
|
+
|
263
|
+
def set_channel_value_by_name(self, inObj, inName, inVal):
|
264
|
+
"""
|
265
|
+
채널 이름으로 모프 채널 값을 설정
|
266
|
+
|
267
|
+
Args:
|
268
|
+
inObj: 모프를 적용할 객체
|
269
|
+
inName: 채널 이름
|
270
|
+
inVal: 설정할 값 (0.0 ~ 100.0)
|
271
|
+
|
272
|
+
Returns:
|
273
|
+
성공 여부 (True/False)
|
274
|
+
"""
|
275
|
+
returnVal = False
|
276
|
+
morphMod = self.get_modifier(inObj)
|
277
|
+
channelIndex = self.get_channelIndex(inObj, inName)
|
278
|
+
|
279
|
+
if channelIndex > 0:
|
280
|
+
try:
|
281
|
+
rt.WM3_MC_SetValue(morphMod, channelIndex, inVal)
|
282
|
+
returnVal = True
|
283
|
+
except:
|
284
|
+
returnVal = False
|
285
|
+
|
286
|
+
return returnVal
|
287
|
+
|
288
|
+
def set_channel_value_by_index(self, inObj, inIndex, inVal):
|
289
|
+
"""
|
290
|
+
인덱스로 모프 채널 값을 설정
|
291
|
+
|
292
|
+
Args:
|
293
|
+
inObj: 모프를 적용할 객체
|
294
|
+
inIndex: 채널 인덱스
|
295
|
+
inVal: 설정할 값 (0.0 ~ 100.0)
|
296
|
+
|
297
|
+
Returns:
|
298
|
+
성공 여부 (True/False)
|
299
|
+
"""
|
300
|
+
returnVal = False
|
301
|
+
morphMod = self.get_modifier(inObj)
|
302
|
+
|
303
|
+
if morphMod is not None:
|
304
|
+
try:
|
305
|
+
rt.WM3_MC_SetValue(morphMod, inIndex, inVal)
|
306
|
+
returnVal = True
|
307
|
+
except:
|
308
|
+
returnVal = False
|
309
|
+
|
310
|
+
return returnVal
|
311
|
+
|
312
|
+
def set_channel_name_by_name(self, inObj, inTargetName, inNewName):
|
313
|
+
"""
|
314
|
+
채널 이름을 이름으로 검색하여 변경
|
315
|
+
|
316
|
+
Args:
|
317
|
+
inObj: 모프를 적용할 객체
|
318
|
+
inTargetName: 대상 채널의 현재 이름
|
319
|
+
inNewName: 설정할 새 이름
|
320
|
+
|
321
|
+
Returns:
|
322
|
+
성공 여부 (True/False)
|
323
|
+
"""
|
324
|
+
returnVal = False
|
325
|
+
channelIndex = self.get_channelIndex(inObj, inTargetName)
|
326
|
+
morphMod = self.get_modifier(inObj)
|
327
|
+
|
328
|
+
if channelIndex > 0:
|
329
|
+
rt.WM3_MC_SetName(morphMod, channelIndex, inNewName)
|
330
|
+
returnVal = True
|
331
|
+
|
332
|
+
return returnVal
|
333
|
+
|
334
|
+
def set_channel_name_by_index(self, inObj, inIndex, inName):
|
335
|
+
"""
|
336
|
+
채널 이름을 인덱스로 검색하여 변경
|
337
|
+
|
338
|
+
Args:
|
339
|
+
inObj: 모프를 적용할 객체
|
340
|
+
inIndex: 대상 채널 인덱스
|
341
|
+
inName: 설정할 이름
|
342
|
+
|
343
|
+
Returns:
|
344
|
+
성공 여부 (True/False)
|
345
|
+
"""
|
346
|
+
returnVal = False
|
347
|
+
morphMod = self.get_modifier(inObj)
|
348
|
+
|
349
|
+
if morphMod is not None:
|
350
|
+
try:
|
351
|
+
rt.WM3_MC_SetName(morphMod, inIndex, inName)
|
352
|
+
returnVal = True
|
353
|
+
except:
|
354
|
+
returnVal = False
|
355
|
+
|
356
|
+
return returnVal
|
357
|
+
|
358
|
+
def reset_all_channel_value(self, inObj):
|
359
|
+
"""
|
360
|
+
모든 모프 채널 값을 0으로 리셋
|
361
|
+
|
362
|
+
Args:
|
363
|
+
inObj: 리셋할 객체
|
364
|
+
"""
|
365
|
+
totalChannelNum = self.get_channel_num(inObj)
|
366
|
+
|
367
|
+
if totalChannelNum > 0:
|
368
|
+
for i in range(1, totalChannelNum + 1):
|
369
|
+
self.set_channel_value_by_index(inObj, i, 0.0)
|
370
|
+
|
371
|
+
def extract_morph_channel_geometry(self, obj, _feedback_=False):
|
372
|
+
"""
|
373
|
+
모프 채널의 기하학적 형태를 추출하여 개별 객체로 생성
|
374
|
+
|
375
|
+
Args:
|
376
|
+
obj: 추출 대상 객체
|
377
|
+
_feedback_: 피드백 메시지 출력 여부
|
378
|
+
|
379
|
+
Returns:
|
380
|
+
추출된 객체 배열
|
381
|
+
"""
|
382
|
+
extractedObjs = []
|
383
|
+
morphMod = self.get_modifier(obj)
|
384
|
+
|
385
|
+
if rt.IsValidMorpherMod(morphMod):
|
386
|
+
# 데이터가 있는 모든 채널 인덱스 수집
|
387
|
+
channels = [i for i in range(1, rt.WM3_NumberOfChannels(morphMod) + 1)
|
388
|
+
if rt.WM3_MC_HasData(morphMod, i)]
|
389
|
+
|
390
|
+
for i in channels:
|
391
|
+
channelName = rt.WM3_MC_GetName(morphMod, i)
|
392
|
+
rt.WM3_MC_SetValue(morphMod, i, 100.0)
|
393
|
+
|
394
|
+
objSnapshot = rt.snapshot(obj)
|
395
|
+
objSnapshot.name = channelName
|
396
|
+
extractedObjs.append(objSnapshot)
|
397
|
+
|
398
|
+
rt.WM3_MC_SetValue(morphMod, i, 0.0)
|
399
|
+
|
400
|
+
if _feedback_:
|
401
|
+
print(f" - FUNCTION - [ extract_morph_channel_geometry ] - Extracted ---- {objSnapshot.name} ---- successfully!!")
|
402
|
+
else:
|
403
|
+
if _feedback_:
|
404
|
+
print(f" - FUNCTION - [ extract_morph_channel_geometry ] - No valid morpher found on ---- {obj.name} ---- ")
|
405
|
+
|
406
|
+
return extractedObjs
|