pyjallib 0.1.0__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 +17 -0
- pyjallib/max/__init__.py +46 -0
- pyjallib/max/align.py +112 -0
- pyjallib/max/anim.py +594 -0
- pyjallib/max/bip.py +508 -0
- pyjallib/max/bone.py +910 -0
- pyjallib/max/constraint.py +973 -0
- pyjallib/max/header.py +57 -0
- pyjallib/max/helper.py +433 -0
- pyjallib/max/layer.py +262 -0
- pyjallib/max/link.py +78 -0
- pyjallib/max/macro/jal_macro_align.py +155 -0
- pyjallib/max/macro/jal_macro_bone.py +358 -0
- pyjallib/max/macro/jal_macro_constraint.py +140 -0
- pyjallib/max/macro/jal_macro_helper.py +321 -0
- pyjallib/max/macro/jal_macro_link.py +55 -0
- pyjallib/max/macro/jal_macro_select.py +91 -0
- pyjallib/max/mirror.py +388 -0
- pyjallib/max/name.py +521 -0
- pyjallib/max/select.py +278 -0
- pyjallib/max/skin.py +996 -0
- pyjallib/max/twistBone.py +418 -0
- pyjallib/namePart.py +633 -0
- pyjallib/nameToPath.py +113 -0
- pyjallib/naming.py +1066 -0
- pyjallib/namingConfig.py +844 -0
- pyjallib/perforce.py +735 -0
- pyjallib/reloadModules.py +33 -0
- pyjallib-0.1.0.dist-info/METADATA +28 -0
- pyjallib-0.1.0.dist-info/RECORD +32 -0
- pyjallib-0.1.0.dist-info/WHEEL +5 -0
- pyjallib-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,973 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
제약(Constraint) 모듈 - 3ds Max용 제약 관련 기능 제공
|
6
|
+
원본 MAXScript의 constraint.ms를 Python으로 변환하였으며, pymxs 모듈 기반으로 구현됨
|
7
|
+
"""
|
8
|
+
|
9
|
+
from pymxs import runtime as rt
|
10
|
+
import textwrap
|
11
|
+
|
12
|
+
# Import necessary service classes for default initialization
|
13
|
+
from .name import Name
|
14
|
+
from .helper import Helper
|
15
|
+
|
16
|
+
|
17
|
+
class Constraint:
|
18
|
+
"""
|
19
|
+
제약(Constraint) 관련 기능을 제공하는 클래스.
|
20
|
+
MAXScript의 _Constraint 구조체 개념을 Python으로 재구현한 클래스이며,
|
21
|
+
3ds Max의 기능들을 pymxs API를 통해 제어합니다.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self, nameService=None, helperService=None):
|
25
|
+
"""
|
26
|
+
클래스 초기화.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
nameService: 이름 처리 서비스 (제공되지 않으면 새로 생성)
|
30
|
+
helperService: 헬퍼 객체 관련 서비스 (제공되지 않으면 새로 생성)
|
31
|
+
"""
|
32
|
+
self.name = nameService if nameService else Name()
|
33
|
+
self.helper = helperService if helperService else Helper(nameService=self.name) # Pass the potentially newly created nameService
|
34
|
+
|
35
|
+
def collapse(self, inObj):
|
36
|
+
"""
|
37
|
+
비 Biped 객체의 트랜스폼 컨트롤러를 기본 컨트롤러로 초기화하고 현재 변환 상태 유지.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
inObj: 초기화할 대상 객체
|
41
|
+
|
42
|
+
Returns:
|
43
|
+
None
|
44
|
+
"""
|
45
|
+
if rt.classOf(inObj) != rt.Biped_Object:
|
46
|
+
# 현재 변환 상태 백업
|
47
|
+
tempTransform = rt.getProperty(inObj, "transform")
|
48
|
+
|
49
|
+
# 기본 컨트롤러로 위치, 회전, 스케일 초기화
|
50
|
+
rt.setPropertyController(inObj.controller, "Position", rt.Position_XYZ())
|
51
|
+
rt.setPropertyController(inObj.controller, "Rotation", rt.Euler_XYZ())
|
52
|
+
rt.setPropertyController(inObj.controller, "Scale", rt.Bezier_Scale())
|
53
|
+
|
54
|
+
# 백업한 변환 상태 복원
|
55
|
+
rt.setProperty(inObj, "transform", tempTransform)
|
56
|
+
|
57
|
+
def set_active_last(self, inObj):
|
58
|
+
"""
|
59
|
+
객체의 위치와 회전 컨트롤러 리스트에서 마지막 컨트롤러를 활성화.
|
60
|
+
|
61
|
+
Args:
|
62
|
+
inObj: 대상 객체
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
None
|
66
|
+
"""
|
67
|
+
# 위치 컨트롤러가 리스트 형태면 마지막 컨트롤러 활성화
|
68
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
69
|
+
if rt.classOf(pos_controller) == rt.Position_list:
|
70
|
+
pos_controller.setActive(pos_controller.count)
|
71
|
+
|
72
|
+
# 회전 컨트롤러가 리스트 형태면 마지막 컨트롤러 활성화
|
73
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
74
|
+
if rt.classOf(rot_controller) == rt.Rotation_list:
|
75
|
+
rot_controller.setActive(rot_controller.count)
|
76
|
+
|
77
|
+
def get_pos_list_controller(self, inObj):
|
78
|
+
"""
|
79
|
+
객체의 위치 리스트 컨트롤러를 반환.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
inObj: 대상 객체
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
위치 리스트 컨트롤러 (없으면 None)
|
86
|
+
"""
|
87
|
+
returnPosListCtr = None
|
88
|
+
|
89
|
+
# 위치 컨트롤러가 리스트 형태인지 확인
|
90
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
91
|
+
if rt.classOf(pos_controller) == rt.Position_list:
|
92
|
+
returnPosListCtr = pos_controller
|
93
|
+
|
94
|
+
return returnPosListCtr
|
95
|
+
|
96
|
+
def assign_pos_list(self, inObj):
|
97
|
+
"""
|
98
|
+
객체에 위치 리스트 컨트롤러를 할당하거나 기존 것을 반환.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
inObj: 대상 객체
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
위치 리스트 컨트롤러
|
105
|
+
"""
|
106
|
+
returnPosListCtr = None
|
107
|
+
|
108
|
+
# 현재 위치 컨트롤러 확인
|
109
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
110
|
+
|
111
|
+
# 리스트 형태가 아니면 새로 생성
|
112
|
+
if rt.classOf(pos_controller) != rt.Position_list:
|
113
|
+
returnPosListCtr = rt.Position_list()
|
114
|
+
rt.setPropertyController(inObj.controller, "Position", returnPosListCtr)
|
115
|
+
return returnPosListCtr
|
116
|
+
|
117
|
+
# 이미 리스트 형태면 그대로 반환
|
118
|
+
if rt.classOf(pos_controller) == rt.Position_list:
|
119
|
+
returnPosListCtr = pos_controller
|
120
|
+
|
121
|
+
return returnPosListCtr
|
122
|
+
|
123
|
+
def get_pos_const(self, inObj):
|
124
|
+
"""
|
125
|
+
객체의 위치 제약 컨트롤러를 찾아 반환.
|
126
|
+
|
127
|
+
Args:
|
128
|
+
inObj: 대상 객체
|
129
|
+
|
130
|
+
Returns:
|
131
|
+
위치 제약 컨트롤러 (없으면 None)
|
132
|
+
"""
|
133
|
+
returnConst = None
|
134
|
+
|
135
|
+
# 위치 컨트롤러가 리스트 형태인 경우
|
136
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
137
|
+
if rt.classOf(pos_controller) == rt.Position_list:
|
138
|
+
lst = pos_controller
|
139
|
+
constNum = lst.getCount()
|
140
|
+
activeNum = lst.getActive()
|
141
|
+
|
142
|
+
# 리스트 내 모든 컨트롤러 검사
|
143
|
+
for i in range(constNum):
|
144
|
+
sub_controller = lst[i].controller
|
145
|
+
if rt.classOf(sub_controller) == rt.Position_Constraint:
|
146
|
+
returnConst = sub_controller
|
147
|
+
# 현재 활성화된 컨트롤러면 즉시 반환
|
148
|
+
if activeNum == i:
|
149
|
+
return returnConst
|
150
|
+
|
151
|
+
# 위치 컨트롤러가 직접 Position_Constraint인 경우
|
152
|
+
elif rt.classOf(pos_controller) == rt.Position_Constraint:
|
153
|
+
returnConst = pos_controller
|
154
|
+
|
155
|
+
return returnConst
|
156
|
+
|
157
|
+
def assign_pos_const(self, inObj, inTarget, keepInit=False):
|
158
|
+
"""
|
159
|
+
객체에 위치 제약 컨트롤러를 할당하고 지정된 타겟을 추가.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
inObj: 제약을 적용할 객체
|
163
|
+
inTarget: 타겟 객체
|
164
|
+
keepInit: 기존 변환 유지 여부 (기본값: False)
|
165
|
+
|
166
|
+
Returns:
|
167
|
+
위치 제약 컨트롤러
|
168
|
+
"""
|
169
|
+
# 위치 컨트롤러가 리스트 형태가 아니면 변환
|
170
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
171
|
+
if rt.classOf(pos_controller) != rt.Position_list:
|
172
|
+
rt.setPropertyController(inObj.controller, "Position", rt.Position_list())
|
173
|
+
|
174
|
+
# 기존 위치 제약 컨트롤러 확인
|
175
|
+
targetPosConstraint = self.get_pos_const(inObj)
|
176
|
+
|
177
|
+
# 위치 제약 컨트롤러가 없으면 새로 생성
|
178
|
+
if targetPosConstraint is None:
|
179
|
+
targetPosConstraint = rt.Position_Constraint()
|
180
|
+
pos_list = self.get_pos_list_controller(inObj)
|
181
|
+
rt.setPropertyController(pos_list, "Available", targetPosConstraint)
|
182
|
+
pos_list.setActive(pos_list.count)
|
183
|
+
|
184
|
+
# 타겟 추가 및 가중치 조정
|
185
|
+
targetNum = targetPosConstraint.getNumTargets()
|
186
|
+
targetWeight = 100.0 / (targetNum + 1)
|
187
|
+
targetPosConstraint.appendTarget(inTarget, targetWeight)
|
188
|
+
|
189
|
+
# 기존 타겟이 있으면 가중치 재조정
|
190
|
+
if targetNum > 0:
|
191
|
+
newWeightScale = 100.0 - targetWeight
|
192
|
+
for i in range(1, targetNum + 1): # Maxscript는 1부터 시작
|
193
|
+
newWeight = targetPosConstraint.GetWeight(i) * 0.01 * newWeightScale
|
194
|
+
targetPosConstraint.SetWeight(i, newWeight)
|
195
|
+
|
196
|
+
# 상대적 모드 설정
|
197
|
+
targetPosConstraint.relative = keepInit
|
198
|
+
|
199
|
+
return targetPosConstraint
|
200
|
+
|
201
|
+
def assign_pos_const_multi(self, inObj, inTargetArray, keepInit=False):
|
202
|
+
"""
|
203
|
+
객체에 여러 타겟을 가진 위치 제약 컨트롤러를 할당.
|
204
|
+
|
205
|
+
Args:
|
206
|
+
inObj: 제약을 적용할 객체
|
207
|
+
inTargetArray: 타겟 객체 배열
|
208
|
+
keepInit: 기존 변환 유지 여부 (기본값: False)
|
209
|
+
|
210
|
+
Returns:
|
211
|
+
None
|
212
|
+
"""
|
213
|
+
for item in inTargetArray:
|
214
|
+
self.assign_pos_const(inObj, item, keepInit=keepInit)
|
215
|
+
|
216
|
+
def add_target_to_pos_const(self, inObj, inTarget, inWeight):
|
217
|
+
"""
|
218
|
+
기존 위치 제약 컨트롤러에 새 타겟을 추가하고 지정된 가중치 설정.
|
219
|
+
|
220
|
+
Args:
|
221
|
+
inObj: 제약이 적용된 객체
|
222
|
+
inTarget: 추가할 타겟 객체
|
223
|
+
inWeight: 적용할 가중치 값
|
224
|
+
|
225
|
+
Returns:
|
226
|
+
None
|
227
|
+
"""
|
228
|
+
# 위치 제약 컨트롤러에 타겟 추가
|
229
|
+
targetPosConst = self.assign_pos_const(inObj, inTarget)
|
230
|
+
|
231
|
+
# 마지막 타겟에 특정 가중치 적용
|
232
|
+
targetNum = targetPosConst.getNumTargets()
|
233
|
+
targetPosConst.SetWeight(targetNum, inWeight)
|
234
|
+
|
235
|
+
def assign_pos_xyz(self, inObj):
|
236
|
+
"""
|
237
|
+
객체에 위치 XYZ 컨트롤러를 할당.
|
238
|
+
|
239
|
+
Args:
|
240
|
+
inObj: 컨트롤러를 할당할 객체
|
241
|
+
|
242
|
+
Returns:
|
243
|
+
None
|
244
|
+
"""
|
245
|
+
# 위치 컨트롤러가 리스트 형태가 아니면 변환
|
246
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
247
|
+
if rt.classOf(pos_controller) != rt.Position_list:
|
248
|
+
rt.setPropertyController(inObj.controller, "Position", rt.Position_list())
|
249
|
+
|
250
|
+
# 위치 리스트 컨트롤러 가져오기
|
251
|
+
posList = self.assign_pos_list(inObj)
|
252
|
+
|
253
|
+
# Position_XYZ 컨트롤러 할당
|
254
|
+
rt.setPropertyController(posList, "Available", rt.Position_XYZ())
|
255
|
+
posList.setActive(posList.count)
|
256
|
+
|
257
|
+
def get_rot_list_controller(self, inObj):
|
258
|
+
"""
|
259
|
+
객체의 회전 리스트 컨트롤러를 반환.
|
260
|
+
|
261
|
+
Args:
|
262
|
+
inObj: 대상 객체
|
263
|
+
|
264
|
+
Returns:
|
265
|
+
회전 리스트 컨트롤러 (없으면 None)
|
266
|
+
"""
|
267
|
+
returnRotListCtr = None
|
268
|
+
|
269
|
+
# 회전 컨트롤러가 리스트 형태인지 확인
|
270
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
271
|
+
if rt.classOf(rot_controller) == rt.Rotation_list:
|
272
|
+
returnRotListCtr = rot_controller
|
273
|
+
|
274
|
+
return returnRotListCtr
|
275
|
+
|
276
|
+
def assign_rot_list(self, inObj):
|
277
|
+
"""
|
278
|
+
객체에 회전 리스트 컨트롤러를 할당하거나 기존 것을 반환.
|
279
|
+
|
280
|
+
Args:
|
281
|
+
inObj: 대상 객체
|
282
|
+
|
283
|
+
Returns:
|
284
|
+
회전 리스트 컨트롤러
|
285
|
+
"""
|
286
|
+
returnRotListCtr = None
|
287
|
+
|
288
|
+
# 현재 회전 컨트롤러 확인
|
289
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
290
|
+
|
291
|
+
# 리스트 형태가 아니면 새로 생성
|
292
|
+
if rt.classOf(rot_controller) != rt.Rotation_list:
|
293
|
+
returnRotListCtr = rt.Rotation_list()
|
294
|
+
rt.setPropertyController(inObj.controller, "Rotation", returnRotListCtr)
|
295
|
+
return returnRotListCtr
|
296
|
+
|
297
|
+
# 이미 리스트 형태면 그대로 반환
|
298
|
+
if rt.classOf(rot_controller) == rt.Rotation_list:
|
299
|
+
returnRotListCtr = rot_controller
|
300
|
+
|
301
|
+
return returnRotListCtr
|
302
|
+
|
303
|
+
def get_rot_const(self, inObj):
|
304
|
+
"""
|
305
|
+
객체의 회전 제약 컨트롤러를 찾아 반환.
|
306
|
+
|
307
|
+
Args:
|
308
|
+
inObj: 대상 객체
|
309
|
+
|
310
|
+
Returns:
|
311
|
+
회전 제약 컨트롤러 (없으면 None)
|
312
|
+
"""
|
313
|
+
returnConst = None
|
314
|
+
|
315
|
+
# 회전 컨트롤러가 리스트 형태인 경우
|
316
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
317
|
+
if rt.classOf(rot_controller) == rt.Rotation_list:
|
318
|
+
lst = rot_controller
|
319
|
+
constNum = lst.getCount()
|
320
|
+
activeNum = lst.getActive()
|
321
|
+
|
322
|
+
# 리스트 내 모든 컨트롤러 검사
|
323
|
+
for i in range(constNum): # Maxscript는 1부터 시작
|
324
|
+
sub_controller = lst[i].controller
|
325
|
+
if rt.classOf(sub_controller) == rt.Orientation_Constraint:
|
326
|
+
returnConst = sub_controller
|
327
|
+
# 현재 활성화된 컨트롤러면 즉시 반환
|
328
|
+
if activeNum == i:
|
329
|
+
return returnConst
|
330
|
+
|
331
|
+
# 회전 컨트롤러가 직접 Orientation_Constraint인 경우
|
332
|
+
elif rt.classOf(rot_controller) == rt.Orientation_Constraint:
|
333
|
+
returnConst = rot_controller
|
334
|
+
|
335
|
+
return returnConst
|
336
|
+
|
337
|
+
def assign_rot_const(self, inObj, inTarget, keepInit=False):
|
338
|
+
"""
|
339
|
+
객체에 회전 제약 컨트롤러를 할당하고 지정된 타겟을 추가.
|
340
|
+
|
341
|
+
Args:
|
342
|
+
inObj: 제약을 적용할 객체
|
343
|
+
inTarget: 타겟 객체
|
344
|
+
keepInit: 기존 변환 유지 여부 (기본값: False)
|
345
|
+
|
346
|
+
Returns:
|
347
|
+
회전 제약 컨트롤러
|
348
|
+
"""
|
349
|
+
# 회전 컨트롤러가 리스트 형태가 아니면 변환
|
350
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
351
|
+
if rt.classOf(rot_controller) != rt.Rotation_list:
|
352
|
+
rt.setPropertyController(inObj.controller, "Rotation", rt.Rotation_list())
|
353
|
+
|
354
|
+
# 기존 회전 제약 컨트롤러 확인
|
355
|
+
targetRotConstraint = self.get_rot_const(inObj)
|
356
|
+
|
357
|
+
# 회전 제약 컨트롤러가 없으면 새로 생성
|
358
|
+
if targetRotConstraint is None:
|
359
|
+
targetRotConstraint = rt.Orientation_Constraint()
|
360
|
+
rot_list = self.get_rot_list_controller(inObj)
|
361
|
+
rt.setPropertyController(rot_list, "Available", targetRotConstraint)
|
362
|
+
rot_list.setActive(rot_list.count)
|
363
|
+
|
364
|
+
# 타겟 추가 및 가중치 조정
|
365
|
+
targetNum = targetRotConstraint.getNumTargets()
|
366
|
+
targetWeight = 100.0 / (targetNum + 1)
|
367
|
+
targetRotConstraint.appendTarget(inTarget, targetWeight)
|
368
|
+
|
369
|
+
# 기존 타겟이 있으면 가중치 재조정
|
370
|
+
if targetNum > 0:
|
371
|
+
newWeightScale = 100.0 - targetWeight
|
372
|
+
for i in range(1, targetNum + 1): # Maxscript는 1부터 시작
|
373
|
+
newWeight = targetRotConstraint.GetWeight(i) * 0.01 * newWeightScale
|
374
|
+
targetRotConstraint.SetWeight(i, newWeight)
|
375
|
+
|
376
|
+
# 상대적 모드 설정
|
377
|
+
targetRotConstraint.relative = keepInit
|
378
|
+
|
379
|
+
return targetRotConstraint
|
380
|
+
|
381
|
+
def assign_rot_const_multi(self, inObj, inTargetArray, keepInit=False):
|
382
|
+
"""
|
383
|
+
객체에 여러 타겟을 가진 회전 제약 컨트롤러를 할당.
|
384
|
+
|
385
|
+
Args:
|
386
|
+
inObj: 제약을 적용할 객체
|
387
|
+
inTargetArray: 타겟 객체 배열
|
388
|
+
keepInit: 기존 변환 유지 여부 (기본값: False)
|
389
|
+
|
390
|
+
Returns:
|
391
|
+
None
|
392
|
+
"""
|
393
|
+
for item in inTargetArray:
|
394
|
+
self.assign_rot_const(inObj, item, keepInit=keepInit)
|
395
|
+
|
396
|
+
def add_target_to_rot_const(self, inObj, inTarget, inWeight):
|
397
|
+
"""
|
398
|
+
기존 회전 제약 컨트롤러에 새 타겟을 추가하고 지정된 가중치 설정.
|
399
|
+
|
400
|
+
Args:
|
401
|
+
inObj: 제약이 적용된 객체
|
402
|
+
inTarget: 추가할 타겟 객체
|
403
|
+
inWeight: 적용할 가중치 값
|
404
|
+
|
405
|
+
Returns:
|
406
|
+
None
|
407
|
+
"""
|
408
|
+
# 회전 제약 컨트롤러에 타겟 추가
|
409
|
+
targetRotConstraint = self.assign_rot_const(inObj, inTarget)
|
410
|
+
|
411
|
+
# 마지막 타겟에 특정 가중치 적용
|
412
|
+
targetNum = targetRotConstraint.getNumTargets()
|
413
|
+
targetRotConstraint.SetWeight(targetNum, inWeight)
|
414
|
+
|
415
|
+
def assign_euler_xyz(self, inObj):
|
416
|
+
"""
|
417
|
+
객체에 오일러 XYZ 회전 컨트롤러를 할당.
|
418
|
+
|
419
|
+
Args:
|
420
|
+
inObj: 컨트롤러를 할당할 객체
|
421
|
+
|
422
|
+
Returns:
|
423
|
+
None
|
424
|
+
"""
|
425
|
+
# 회전 컨트롤러가 리스트 형태가 아니면 변환
|
426
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
427
|
+
if rt.classOf(rot_controller) != rt.Rotation_list:
|
428
|
+
rt.setPropertyController(inObj.controller, "Rotation", rt.Rotation_list())
|
429
|
+
|
430
|
+
# 회전 리스트 컨트롤러 가져오기
|
431
|
+
rotList = self.assign_rot_list(inObj)
|
432
|
+
|
433
|
+
# Euler_XYZ 컨트롤러 할당
|
434
|
+
rt.setPropertyController(rotList, "Available", rt.Euler_XYZ())
|
435
|
+
rotList.setActive(rotList.count)
|
436
|
+
|
437
|
+
def get_lookat(self, inObj):
|
438
|
+
"""
|
439
|
+
객체의 LookAt 제약 컨트롤러를 찾아 반환.
|
440
|
+
|
441
|
+
Args:
|
442
|
+
inObj: 대상 객체
|
443
|
+
|
444
|
+
Returns:
|
445
|
+
LookAt 제약 컨트롤러 (없으면 None)
|
446
|
+
"""
|
447
|
+
returnConst = None
|
448
|
+
|
449
|
+
# 회전 컨트롤러가 리스트 형태인 경우
|
450
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
451
|
+
if rt.classOf(rot_controller) == rt.Rotation_list:
|
452
|
+
lst = rot_controller
|
453
|
+
constNum = lst.getCount()
|
454
|
+
activeNum = lst.getActive()
|
455
|
+
|
456
|
+
# 리스트 내 모든 컨트롤러 검사
|
457
|
+
for i in range(constNum):
|
458
|
+
sub_controller = lst[i].controller
|
459
|
+
if rt.classOf(sub_controller) == rt.LookAt_Constraint:
|
460
|
+
returnConst = sub_controller
|
461
|
+
# 현재 활성화된 컨트롤러면 즉시 반환
|
462
|
+
if activeNum == i:
|
463
|
+
return returnConst
|
464
|
+
|
465
|
+
# 회전 컨트롤러가 직접 LookAt_Constraint인 경우
|
466
|
+
elif rt.classOf(rot_controller) == rt.LookAt_Constraint:
|
467
|
+
returnConst = rot_controller
|
468
|
+
|
469
|
+
return returnConst
|
470
|
+
|
471
|
+
def assign_lookat(self, inObj, inTarget, keepInit=False):
|
472
|
+
"""
|
473
|
+
객체에 LookAt 제약 컨트롤러를 할당하고 지정된 타겟을 추가.
|
474
|
+
|
475
|
+
Args:
|
476
|
+
inObj: 제약을 적용할 객체
|
477
|
+
inTarget: 타겟 객체
|
478
|
+
keepInit: 기존 변환 유지 여부 (기본값: False)
|
479
|
+
|
480
|
+
Returns:
|
481
|
+
LookAt 제약 컨트롤러
|
482
|
+
"""
|
483
|
+
# 회전 컨트롤러가 리스트 형태가 아니면 변환
|
484
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
485
|
+
if rt.classOf(rot_controller) != rt.Rotation_list:
|
486
|
+
rt.setPropertyController(inObj.controller, "Rotation", rt.Rotation_list())
|
487
|
+
|
488
|
+
# 기존 LookAt 제약 컨트롤러 확인
|
489
|
+
targetRotConstraint = self.get_lookat(inObj)
|
490
|
+
|
491
|
+
# LookAt 제약 컨트롤러가 없으면 새로 생성
|
492
|
+
if targetRotConstraint is None:
|
493
|
+
targetRotConstraint = rt.LookAt_Constraint()
|
494
|
+
rot_list = self.get_rot_list_controller(inObj)
|
495
|
+
rt.setPropertyController(rot_list, "Available", targetRotConstraint)
|
496
|
+
rot_list.setActive(rot_list.count)
|
497
|
+
|
498
|
+
# 타겟 추가 및 가중치 조정
|
499
|
+
targetNum = targetRotConstraint.getNumTargets()
|
500
|
+
targetWeight = 100.0 / (targetNum + 1)
|
501
|
+
targetRotConstraint.appendTarget(inTarget, targetWeight)
|
502
|
+
|
503
|
+
# 기존 타겟이 있으면 가중치 재조정
|
504
|
+
if targetNum > 0:
|
505
|
+
newWeightScale = 100.0 - targetWeight
|
506
|
+
for i in range(1, targetNum + 1): # Maxscript는 1부터 시작
|
507
|
+
newWeight = targetRotConstraint.GetWeight(i) * 0.01 * newWeightScale
|
508
|
+
targetRotConstraint.SetWeight(i, newWeight)
|
509
|
+
|
510
|
+
# 상대적 모드 설정
|
511
|
+
targetRotConstraint.relative = keepInit
|
512
|
+
|
513
|
+
targetRotConstraint.lookat_vector_length = 0
|
514
|
+
|
515
|
+
return targetRotConstraint
|
516
|
+
|
517
|
+
def assign_lookat_multi(self, inObj, inTargetArray, keepInit=False):
|
518
|
+
"""
|
519
|
+
객체에 여러 타겟을 가진 LookAt 제약 컨트롤러를 할당.
|
520
|
+
|
521
|
+
Args:
|
522
|
+
inObj: 제약을 적용할 객체
|
523
|
+
inTargetArray: 타겟 객체 배열
|
524
|
+
keepInit: 기존 변환 유지 여부 (기본값: False)
|
525
|
+
|
526
|
+
Returns:
|
527
|
+
None
|
528
|
+
"""
|
529
|
+
for item in inTargetArray:
|
530
|
+
self.assign_lookat(inObj, item, keepInit=keepInit)
|
531
|
+
|
532
|
+
def assign_lookat_flipless(self, inObj, inTarget):
|
533
|
+
"""
|
534
|
+
플립 없는 LookAt 제약 컨트롤러를 스크립트 기반으로 구현하여 할당.
|
535
|
+
부모가 있는 객체에만 적용 가능.
|
536
|
+
|
537
|
+
Args:
|
538
|
+
inObj: 제약을 적용할 객체 (부모가 있어야 함)
|
539
|
+
inTarget: 바라볼 타겟 객체
|
540
|
+
|
541
|
+
Returns:
|
542
|
+
None
|
543
|
+
"""
|
544
|
+
# 객체에 부모가 있는 경우에만 실행
|
545
|
+
if inObj.parent is not None:
|
546
|
+
# 회전 스크립트 컨트롤러 생성
|
547
|
+
targetRotConstraint = rt.Rotation_Script()
|
548
|
+
|
549
|
+
# 스크립트에 필요한 노드 추가
|
550
|
+
targetRotConstraint.AddNode("Target", inTarget)
|
551
|
+
targetRotConstraint.AddNode("Parent", inObj.parent)
|
552
|
+
|
553
|
+
# 객체 위치 컨트롤러 추가
|
554
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
555
|
+
targetRotConstraint.AddObject("NodePos", pos_controller)
|
556
|
+
|
557
|
+
# 회전 계산 스크립트 설정
|
558
|
+
script = textwrap.dedent(r'''
|
559
|
+
theTargetVector=(Target.transform.position * Inverse Parent.transform)-NodePos.value
|
560
|
+
theAxis=Normalize (cross theTargetVector [1,0,0])
|
561
|
+
theAngle=acos (dot (Normalize theTargetVector) [1,0,0])
|
562
|
+
Quat theAngle theAxis
|
563
|
+
''')
|
564
|
+
targetRotConstraint.script = script
|
565
|
+
|
566
|
+
# 회전 컨트롤러가 리스트 형태가 아니면 변환
|
567
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
568
|
+
if rt.classOf(rot_controller) != rt.Rotation_list:
|
569
|
+
rt.setPropertyController(inObj.controller, "Rotation", rt.Rotation_list())
|
570
|
+
|
571
|
+
# 회전 리스트에 스크립트 컨트롤러 추가
|
572
|
+
rot_list = self.get_rot_list_controller(inObj)
|
573
|
+
rt.setPropertyController(rot_list, "Available", targetRotConstraint)
|
574
|
+
rot_list.setActive(rot_list.count)
|
575
|
+
|
576
|
+
def assign_rot_const_scripted(self, inObj, inTarget):
|
577
|
+
"""
|
578
|
+
스크립트 기반 회전 제약을 구현하여 할당.
|
579
|
+
ExposeTransform을 활용한 고급 회전 제약 구현.
|
580
|
+
|
581
|
+
Args:
|
582
|
+
inObj: 제약을 적용할 객체
|
583
|
+
inTarget: 회전 참조 타겟 객체
|
584
|
+
|
585
|
+
Returns:
|
586
|
+
생성된 회전 스크립트 컨트롤러
|
587
|
+
"""
|
588
|
+
# 회전 스크립트 컨트롤러 생성
|
589
|
+
targetRotConstraint = rt.Rotation_Script()
|
590
|
+
|
591
|
+
# 회전 컨트롤러 리스트에 추가
|
592
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
593
|
+
if rt.classOf(rot_controller) != rt.Rotation_list:
|
594
|
+
rt.setPropertyController(inObj.controller, "Rotation", rt.Rotation_list())
|
595
|
+
|
596
|
+
rot_list = self.get_rot_list_controller(inObj)
|
597
|
+
rt.setPropertyController(rot_list, "Available", targetRotConstraint)
|
598
|
+
rot_list.setActive(rot_list.count)
|
599
|
+
|
600
|
+
# 헬퍼 객체 이름 생성
|
601
|
+
if self.name:
|
602
|
+
rotPointName = self.name.replace_Type(inObj.name, self.name.get_dummy_value())
|
603
|
+
rotMeasurePointName = self.name.increase_index(rotPointName, 1)
|
604
|
+
rotExpName = self.name.replace_Type(inObj.name, self.name.get_exposeTm_value())
|
605
|
+
rotExpName = self.name.replace_Index(rotExpName, "0")
|
606
|
+
|
607
|
+
print(f"dumStr: {self.name.get_dummy_value()}")
|
608
|
+
print(f"exposeTmStr: {self.name.get_exposeTm_value()}")
|
609
|
+
print(f"rotPointName: {rotPointName}, rotMeasurePointName: {rotMeasurePointName}, rotExpName: {rotExpName}")
|
610
|
+
else:
|
611
|
+
# name 서비스가 없는 경우 기본 이름 사용
|
612
|
+
base_name = rt.getProperty(inObj, "name")
|
613
|
+
rotPointName = f"dum_{base_name}"
|
614
|
+
rotMeasurePointName = f"dum_{base_name}_01"
|
615
|
+
rotExpName = f"exp_{base_name}_0"
|
616
|
+
|
617
|
+
# 헬퍼 객체 생성
|
618
|
+
if self.helper:
|
619
|
+
rotPoint = self.helper.create_point(rotPointName, size=2, boxToggle=True, crossToggle=False)
|
620
|
+
rotMeasuerPoint = self.helper.create_point(rotMeasurePointName, size=3, boxToggle=True, crossToggle=False)
|
621
|
+
rotExpPoint = rt.ExposeTm(name=rotExpName, size=3, box=False, cross=True, wirecolor=rt.Color(14, 255, 2))
|
622
|
+
else:
|
623
|
+
# 직접 헬퍼 객체 생성
|
624
|
+
rotPoint = rt.Point(name=rotPointName, size=2, box=True, cross=False)
|
625
|
+
rotMeasuerPoint = rt.Point(name=rotMeasurePointName, size=3, box=True, cross=False)
|
626
|
+
rotExpPoint = rt.ExposeTm(name=rotExpName, size=3, box=False, cross=True, wirecolor=rt.Color(14, 255, 2))
|
627
|
+
|
628
|
+
# 초기 변환 설정
|
629
|
+
rt.setProperty(rotPoint, "transform", rt.getProperty(inObj, "transform"))
|
630
|
+
rt.setProperty(rotMeasuerPoint, "transform", rt.getProperty(inObj, "transform"))
|
631
|
+
rt.setProperty(rotExpPoint, "transform", rt.getProperty(inObj, "transform"))
|
632
|
+
|
633
|
+
# 부모 관계 설정
|
634
|
+
rotPoint.parent = inTarget
|
635
|
+
rotMeasuerPoint.parent = inTarget.parent
|
636
|
+
rotExpPoint.parent = inTarget
|
637
|
+
|
638
|
+
# ExposeTm 설정
|
639
|
+
rotExpPoint.exposeNode = rotPoint
|
640
|
+
rotExpPoint.useParent = False
|
641
|
+
rotExpPoint.localReferenceNode = rotMeasuerPoint
|
642
|
+
|
643
|
+
# 회전 스크립트 생성
|
644
|
+
rotScript = textwrap.dedent(r'''
|
645
|
+
local targetRot = rot.localEuler
|
646
|
+
local rotX = (radToDeg targetRot.x)
|
647
|
+
local rotY = (radToDeg targetRot.y)
|
648
|
+
local rotZ = (radToDeg targetRot.z)
|
649
|
+
local result = eulerAngles rotX rotY rotZ
|
650
|
+
eulerToQuat result
|
651
|
+
''')
|
652
|
+
|
653
|
+
# 스크립트에 노드 추가 및 표현식 설정
|
654
|
+
targetRotConstraint.AddNode("rot", rotExpPoint)
|
655
|
+
targetRotConstraint.SetExpression(rotScript)
|
656
|
+
|
657
|
+
return targetRotConstraint
|
658
|
+
|
659
|
+
def assign_scripted_lookat(self, inOri, inTarget):
|
660
|
+
"""
|
661
|
+
스크립트 기반 LookAt 제약을 구현하여 할당.
|
662
|
+
여러 개의 헬퍼 객체를 생성하여 복잡한 LookAt 제약 구현.
|
663
|
+
|
664
|
+
Args:
|
665
|
+
inOri: 제약을 적용할 객체
|
666
|
+
inTarget: 바라볼 타겟 객체 배열
|
667
|
+
|
668
|
+
Returns:
|
669
|
+
None
|
670
|
+
"""
|
671
|
+
oriObj = inOri
|
672
|
+
oriParentObj = inOri.parent
|
673
|
+
targetObjArray = inTarget
|
674
|
+
|
675
|
+
# 객체 이름 생성
|
676
|
+
if self.name:
|
677
|
+
objName = self.name.get_string(oriObj.name)
|
678
|
+
indexNum = self.name.get_index_as_digit(oriObj.name)
|
679
|
+
dummyName = self.name.add_prefix_to_real_name(objName, self.name.get_dummy_value())
|
680
|
+
|
681
|
+
lookAtPointName = self.name.replace_Index(dummyName, str(indexNum))
|
682
|
+
lookAtMeasurePointName = self.name.replace_Index(dummyName, str(indexNum+1))
|
683
|
+
lookAtExpPointName = dummyName + self.name.get_exposeTm_value()
|
684
|
+
lookAtExpPointName = self.name.replace_Index(lookAtExpPointName, "0")
|
685
|
+
|
686
|
+
# 헬퍼 객체 생성
|
687
|
+
if self.helper:
|
688
|
+
lookAtPoint = self.helper.create_point(lookAtPointName, size=2, boxToggle=True, crossToggle=False)
|
689
|
+
lookAtMeasurePoint = self.helper.create_point(lookAtMeasurePointName, size=3, boxToggle=True, crossToggle=False)
|
690
|
+
lookAtExpPoint = rt.ExposeTm(name=lookAtExpPointName, size=3, box=False, cross=True, wirecolor=rt.Color(14, 255, 2))
|
691
|
+
|
692
|
+
# 초기 변환 설정
|
693
|
+
rt.setProperty(lookAtPoint, "transform", rt.getProperty(oriObj, "transform"))
|
694
|
+
rt.setProperty(lookAtMeasurePoint, "transform", rt.getProperty(oriObj, "transform"))
|
695
|
+
rt.setProperty(lookAtExpPoint, "transform", rt.getProperty(oriObj, "transform"))
|
696
|
+
|
697
|
+
# 부모 관계 설정
|
698
|
+
rt.setProperty(lookAtPoint, "parent", oriParentObj)
|
699
|
+
rt.setProperty(lookAtMeasurePoint, "parent", oriParentObj)
|
700
|
+
rt.setProperty(lookAtExpPoint, "parent", oriParentObj)
|
701
|
+
|
702
|
+
# ExposeTm 설정
|
703
|
+
lookAtExpPoint.exposeNode = lookAtPoint
|
704
|
+
lookAtExpPoint.useParent = False
|
705
|
+
lookAtExpPoint.localReferenceNode = lookAtMeasurePoint
|
706
|
+
|
707
|
+
# LookAt 제약 설정
|
708
|
+
lookAtPoint_rot_controller = rt.LookAt_Constraint()
|
709
|
+
rt.setPropertyController(lookAtPoint.controller, "Rotation", lookAtPoint_rot_controller)
|
710
|
+
|
711
|
+
# 타겟 추가
|
712
|
+
target_weight = 100.0 / len(targetObjArray)
|
713
|
+
for item in targetObjArray:
|
714
|
+
lookAtPoint_rot_controller.appendTarget(item, target_weight)
|
715
|
+
|
716
|
+
# 오일러 XYZ 컨트롤러 생성
|
717
|
+
rotControl = rt.Euler_XYZ()
|
718
|
+
|
719
|
+
x_controller = rt.Float_Expression()
|
720
|
+
y_controller = rt.Float_Expression()
|
721
|
+
z_controller = rt.Float_Expression()
|
722
|
+
|
723
|
+
# 스칼라 타겟 추가
|
724
|
+
x_controller.AddScalarTarget("rotX", rt.getPropertyController(lookAtExpPoint, "localEulerX"))
|
725
|
+
y_controller.AddScalarTarget("rotY", rt.getPropertyController(lookAtExpPoint, "localEulerY"))
|
726
|
+
z_controller.AddScalarTarget("rotZ", rt.getPropertyController(lookAtExpPoint, "localEulerZ"))
|
727
|
+
|
728
|
+
# 표현식 설정
|
729
|
+
x_controller.SetExpression("rotX")
|
730
|
+
y_controller.SetExpression("rotY")
|
731
|
+
z_controller.SetExpression("rotZ")
|
732
|
+
|
733
|
+
# 각 축별 회전에 Float_Expression 컨트롤러 할당
|
734
|
+
rt.setPropertyController(rotControl, "X_Rotation", x_controller)
|
735
|
+
rt.setPropertyController(rotControl, "Y_Rotation", y_controller)
|
736
|
+
rt.setPropertyController(rotControl, "Z_Rotation", z_controller)
|
737
|
+
|
738
|
+
# 회전 컨트롤러 목록 확인 또는 생성
|
739
|
+
rot_controller = rt.getPropertyController(oriObj.controller, "Rotation")
|
740
|
+
if rt.classOf(rot_controller) != rt.Rotation_list:
|
741
|
+
rt.setPropertyController(oriObj.controller, "Rotation", rt.Rotation_list())
|
742
|
+
|
743
|
+
# 회전 리스트에 오일러 컨트롤러 추가
|
744
|
+
rot_list = self.get_rot_list_controller(oriObj)
|
745
|
+
rt.setPropertyController(rot_list, "Available", rotControl)
|
746
|
+
|
747
|
+
# 컨트롤러 이름 설정
|
748
|
+
rot_controller_num = rot_list.count
|
749
|
+
rot_list.setname(rot_controller_num, "Script Rotation")
|
750
|
+
|
751
|
+
# 컨트롤러 업데이트
|
752
|
+
x_controller.Update()
|
753
|
+
y_controller.Update()
|
754
|
+
z_controller.Update()
|
755
|
+
|
756
|
+
def assign_attachment(self, inPlacedObj, inSurfObj, bAlign=False, shiftAxis=(0, 0, 1), shiftAmount=3.0):
|
757
|
+
"""
|
758
|
+
객체를 다른 객체의 표면에 부착하는 Attachment 제약 컨트롤러 할당.
|
759
|
+
|
760
|
+
Args:
|
761
|
+
inPlacedObj: 부착될 객체
|
762
|
+
inSurfObj: 표면 객체
|
763
|
+
bAlign: 표면 법선에 맞춰 정렬할지 여부
|
764
|
+
shiftAxis: 레이 방향 축 (기본값: Z축)
|
765
|
+
shiftAmount: 레이 거리 (기본값: 3.0)
|
766
|
+
|
767
|
+
Returns:
|
768
|
+
생성된 Attachment 컨트롤러 또는 None (실패 시)
|
769
|
+
"""
|
770
|
+
# 현재 변환 행렬 백업 및 시작 위치 계산
|
771
|
+
placedObjTm = rt.getProperty(inPlacedObj, "transform")
|
772
|
+
rt.preTranslate(placedObjTm, rt.Point3(shiftAxis[0], shiftAxis[1], shiftAxis[2]) * (-shiftAmount))
|
773
|
+
dirStartPos = placedObjTm.pos
|
774
|
+
|
775
|
+
# 끝 위치 계산
|
776
|
+
placedObjTm = rt.getProperty(inPlacedObj, "transform")
|
777
|
+
rt.preTranslate(placedObjTm, rt.Point3(shiftAxis[0], shiftAxis[1], shiftAxis[2]) * shiftAmount)
|
778
|
+
dirEndPos = placedObjTm.pos
|
779
|
+
|
780
|
+
# 방향 벡터 및 레이 생성
|
781
|
+
dirVec = dirEndPos - dirStartPos
|
782
|
+
dirRay = rt.ray(dirEndPos, -dirVec)
|
783
|
+
|
784
|
+
# 레이 교차 검사
|
785
|
+
intersectArr = rt.intersectRayEx(inSurfObj, dirRay)
|
786
|
+
|
787
|
+
# 교차점이 있으면 Attachment 제약 생성
|
788
|
+
if intersectArr is not None:
|
789
|
+
# 위치 컨트롤러 리스트 생성 또는 가져오기
|
790
|
+
posListConst = self.assign_pos_list(inPlacedObj)
|
791
|
+
|
792
|
+
# Attachment 컨트롤러 생성
|
793
|
+
attConst = rt.Attachment()
|
794
|
+
rt.setPropertyController(posListConst, "Available", attConst)
|
795
|
+
|
796
|
+
# 제약 속성 설정
|
797
|
+
attConst.node = inSurfObj
|
798
|
+
attConst.align = bAlign
|
799
|
+
|
800
|
+
# 부착 키 추가
|
801
|
+
attachKey = rt.attachCtrl.addNewKey(attConst, 0)
|
802
|
+
attachKey.face = intersectArr[2] - 1 # 인덱스 조정 (MAXScript는 1부터, Python은 0부터)
|
803
|
+
attachKey.coord = intersectArr[3]
|
804
|
+
|
805
|
+
return attConst
|
806
|
+
else:
|
807
|
+
return None
|
808
|
+
|
809
|
+
def get_pos_controllers_name_from_list(self, inObj):
|
810
|
+
"""
|
811
|
+
객체의 위치 컨트롤러 리스트에서 각 컨트롤러의 이름을 가져옴.
|
812
|
+
|
813
|
+
Args:
|
814
|
+
inObj: 대상 객체
|
815
|
+
|
816
|
+
Returns:
|
817
|
+
컨트롤러 이름 배열
|
818
|
+
"""
|
819
|
+
returnNameArray = []
|
820
|
+
|
821
|
+
# 위치 컨트롤러가 리스트 형태인지 확인
|
822
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
823
|
+
if rt.classOf(pos_controller) == rt.Position_list:
|
824
|
+
posList = pos_controller
|
825
|
+
|
826
|
+
# 각 컨트롤러의 이름을 배열에 추가
|
827
|
+
for i in range(1, posList.count + 1): # MAXScript는 1부터 시작
|
828
|
+
returnNameArray.append(posList.getName(i))
|
829
|
+
|
830
|
+
return returnNameArray
|
831
|
+
|
832
|
+
def get_pos_controllers_weight_from_list(self, inObj):
|
833
|
+
"""
|
834
|
+
객체의 위치 컨트롤러 리스트에서 각 컨트롤러의 가중치를 가져옴.
|
835
|
+
|
836
|
+
Args:
|
837
|
+
inObj: 대상 객체
|
838
|
+
|
839
|
+
Returns:
|
840
|
+
컨트롤러 가중치 배열
|
841
|
+
"""
|
842
|
+
returnWeightArray = []
|
843
|
+
|
844
|
+
# 위치 컨트롤러가 리스트 형태인지 확인
|
845
|
+
pos_controller = rt.getPropertyController(inObj.controller, "Position")
|
846
|
+
if rt.classOf(pos_controller) == rt.Position_list:
|
847
|
+
posList = pos_controller
|
848
|
+
|
849
|
+
# 가중치 배열 가져오기
|
850
|
+
returnWeightArray = list(posList.weight)
|
851
|
+
|
852
|
+
return returnWeightArray
|
853
|
+
|
854
|
+
def set_pos_controllers_name_in_list(self, inObj, inLayerNum, inNewName):
|
855
|
+
"""
|
856
|
+
객체의 위치 컨트롤러 리스트에서 특정 컨트롤러의 이름을 설정.
|
857
|
+
|
858
|
+
Args:
|
859
|
+
inObj: 대상 객체
|
860
|
+
inLayerNum: 컨트롤러 인덱스 (1부터 시작)
|
861
|
+
inNewName: 새 이름
|
862
|
+
|
863
|
+
Returns:
|
864
|
+
None
|
865
|
+
"""
|
866
|
+
# 위치 컨트롤러 리스트 가져오기
|
867
|
+
listCtr = self.get_pos_list_controller(inObj)
|
868
|
+
|
869
|
+
# 리스트가 있으면 이름 설정
|
870
|
+
if listCtr is not None:
|
871
|
+
listCtr.setName(inLayerNum, inNewName)
|
872
|
+
|
873
|
+
def set_pos_controllers_weight_in_list(self, inObj, inLayerNum, inNewWeight):
|
874
|
+
"""
|
875
|
+
객체의 위치 컨트롤러 리스트에서 특정 컨트롤러의 가중치를 설정.
|
876
|
+
|
877
|
+
Args:
|
878
|
+
inObj: 대상 객체
|
879
|
+
inLayerNum: 컨트롤러 인덱스 (1부터 시작)
|
880
|
+
inNewWeight: 새 가중치
|
881
|
+
|
882
|
+
Returns:
|
883
|
+
None
|
884
|
+
"""
|
885
|
+
# 위치 컨트롤러 리스트 가져오기
|
886
|
+
listCtr = self.get_pos_list_controller(inObj)
|
887
|
+
|
888
|
+
# 리스트가 있으면 가중치 설정
|
889
|
+
if listCtr is not None:
|
890
|
+
listCtr.weight[inLayerNum] = inNewWeight
|
891
|
+
|
892
|
+
def get_rot_controllers_name_from_list(self, inObj):
|
893
|
+
"""
|
894
|
+
객체의 회전 컨트롤러 리스트에서 각 컨트롤러의 이름을 가져옴.
|
895
|
+
|
896
|
+
Args:
|
897
|
+
inObj: 대상 객체
|
898
|
+
|
899
|
+
Returns:
|
900
|
+
컨트롤러 이름 배열
|
901
|
+
"""
|
902
|
+
returnNameArray = []
|
903
|
+
|
904
|
+
# 회전 컨트롤러가 리스트 형태인지 확인
|
905
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
906
|
+
if rt.classOf(rot_controller) == rt.Rotation_list:
|
907
|
+
rotList = rot_controller
|
908
|
+
|
909
|
+
# 각 컨트롤러의 이름을 배열에 추가
|
910
|
+
for i in range(1, rotList.count + 1): # MAXScript는 1부터 시작
|
911
|
+
returnNameArray.append(rotList.getName(i))
|
912
|
+
|
913
|
+
return returnNameArray
|
914
|
+
|
915
|
+
def get_rot_controllers_weight_from_list(self, inObj):
|
916
|
+
"""
|
917
|
+
객체의 회전 컨트롤러 리스트에서 각 컨트롤러의 가중치를 가져옴.
|
918
|
+
|
919
|
+
Args:
|
920
|
+
inObj: 대상 객체
|
921
|
+
|
922
|
+
Returns:
|
923
|
+
컨트롤러 가중치 배열
|
924
|
+
"""
|
925
|
+
returnWeightArray = []
|
926
|
+
|
927
|
+
# 회전 컨트롤러가 리스트 형태인지 확인
|
928
|
+
rot_controller = rt.getPropertyController(inObj.controller, "Rotation")
|
929
|
+
if rt.classOf(rot_controller) == rt.Rotation_list:
|
930
|
+
rotList = rot_controller
|
931
|
+
|
932
|
+
# 가중치 배열 가져오기
|
933
|
+
returnWeightArray = list(rotList.weight)
|
934
|
+
|
935
|
+
return returnWeightArray
|
936
|
+
|
937
|
+
def set_rot_controllers_name_in_list(self, inObj, inLayerNum, inNewName):
|
938
|
+
"""
|
939
|
+
객체의 회전 컨트롤러 리스트에서 특정 컨트롤러의 이름을 설정.
|
940
|
+
|
941
|
+
Args:
|
942
|
+
inObj: 대상 객체
|
943
|
+
inLayerNum: 컨트롤러 인덱스 (1부터 시작)
|
944
|
+
inNewName: 새 이름
|
945
|
+
|
946
|
+
Returns:
|
947
|
+
None
|
948
|
+
"""
|
949
|
+
# 회전 컨트롤러 리스트 가져오기
|
950
|
+
listCtr = self.get_rot_list_controller(inObj)
|
951
|
+
|
952
|
+
# 리스트가 있으면 이름 설정
|
953
|
+
if listCtr is not None:
|
954
|
+
listCtr.setName(inLayerNum, inNewName)
|
955
|
+
|
956
|
+
def set_rot_controllers_weight_in_list(self, inObj, inLayerNum, inNewWeight):
|
957
|
+
"""
|
958
|
+
객체의 회전 컨트롤러 리스트에서 특정 컨트롤러의 가중치를 설정.
|
959
|
+
|
960
|
+
Args:
|
961
|
+
inObj: 대상 객체
|
962
|
+
inLayerNum: 컨트롤러 인덱스 (1부터 시작)
|
963
|
+
inNewWeight: 새 가중치
|
964
|
+
|
965
|
+
Returns:
|
966
|
+
None
|
967
|
+
"""
|
968
|
+
# 회전 컨트롤러 리스트 가져오기
|
969
|
+
listCtr = self.get_rot_list_controller(inObj)
|
970
|
+
|
971
|
+
# 리스트가 있으면 가중치 설정
|
972
|
+
if listCtr is not None:
|
973
|
+
listCtr.weight[inLayerNum] = inNewWeight
|