맥스스크립트 심화

'selectKeys'의 응용

스크립팅하는애님 2023. 1. 18. 02:14
728x90
반응형

안녕하세요.

애니메이터가 들려주는 맥스 스크립트의 스크립팅하는 애님입니다.

 

이야~~ 아주 오래간만에 뵙습니다.

다들 건강하시고 새해 복 많이 받으세요.

 

오늘 이렇게 글을 올리게된 이유는 '배울것이 너무 많아'님이 올리신 질문 때문인데요.

질문의 내용은 내가 선택한 키 이후(이전)부터 타임 슬라이더바 까지의 키들을 모두 선택하고 싶다였습니다.

 

기본적인 명령어는 '맥스스크립트 기본'의 'Controller Key Functions' 게시물을 찾아보시면 나오니 명령어에 대한 세세한 설명은 넘어가도록 하겠습니다.

본격적인 설명 전에 사전 설명을 하나 해야겠는데요.

맥스의 키 관련 작업을 하시는 분은 잘 아시겠지만 타임슬라이더에 있는 키가 같은 곳에서 보일 뿐이지 모두 동일한 키가 아닙니다.

컨스트레인의 키, 트랜스폼의 키, 커맨드 패널에서 작동하는 키 등등 여러 가지 형태의 키가 존재합니다.

이것들은 성격이 다른 키 이기 때문에 접근하는 방식이 같은 경우도 있지만 모두 다르다고 생각하시는 게 건강에 좋습니다.

'selectKeys $.controller....' 와같은 명령어로는 접근할 수가 없습니다.

심지어 같은 'transform'에 포함되어있는 'postion, rotation, scale'조차도 각각 접근이 다릅니다.

selectKeys $.pos.controller....
selectKeys $.rotation.controller....
selectKeys $.scale.controller....

해당하는 접근 방법을 확인하시고 작업을 진행하셔야 합니다.

'타임슬라이더'에 키가 있으면 다 같이 컨트롤할 수 있는 방법이 있지 않을까?'라는 생각을 저도 한때 했었는데, 도무지 한 번에 묶어서 컨트롤할 수 있는 방법을 못 찾겠네요.

경우의 수를 생각하면 스크립트가 무한히 길어질 수 있기 때문에 가장 기본적인 형태로 진행하겠습니다.

(열공하셔서 원하시는 기능을 하나씩 추가해 보세요.ㅎㅎ)

사전설명은 여기까지 하고 본론으로 넘어가겠습니다.

이번 작업은 박스의 기본 transform을 이용하여 작업을 했기 때문에 다른 형태의 transform(예 TCB 등)에서는 작동하지 않습니다.

 

스크립트의 기본 골자는

1 여러 개의 키 중 하나가 선택되어 있다.

2 타임슬라이더 바를 선택된 키보다 앞쪽의 프레임이나 뒤쪽의 프레임으로 이동시킨다.

3 if문을 이용하여 '선택된 키'와 '타임슬라이더 바의 프레임'중 낮은 값과 높은 값을 구별하여 저장한다.

4 저장된 값을 범위로 지정하여 해당 키만 선택한다.

입니다.

 

1번과 2번은 스크립트로 작업하는 것이 아니라 사용자가 직접 키를 선택해 주는 것이기 때문에 스크립트 작업은 없습니다.

3번의 내용을 알아봅시다.

1
2
3
4
5
6
7
8
9
keysCount = numKeys $.pos.controller
 
for i = 1 to keysCount do
(
    if((isKeySelected $.pos.controller i) == true) do
    (
        selectKeyFrame = getKeyTime  $.pos.controller i
    )
)
cs

1번 라인은 선택한 오브젝트의 Postion키가 몇 개나 있는지 확인하여 그 수를 'KeysCount'에 저장합니다.

물론 Rotation이나 Scale의 키도 고려해서 확인해야 하지만 단순하게 Postion, Rotation, Scale에 모두 동일하게 키가 있다고 하겠습니다.

3번 라인은 여기서 구한 키의 개수를 이용하여 for문을 돌립니다.

for문을 돌리는 동안 5번 라인의 if문을 이용하여 선택된 키를 확인하고,

선택되었다면 있다면 if문 안쪽의 내용을 실행해 selectKeyFrame변수에 해당 키의 프레임을 저장합니다.

만약 복수개의 키를 선택했다면, 마지막 키만 저장됩니다.

(이런저런 로직을 짜 넣으면 첫 번째 키를 저장하거나 조건에 따라 다르게 결과가 나오게 할 수 있지만 패스하겠습니다.)

위 스크립트는 현재 선택한 키의 프레임을 구할 수 있습니다.

타임슬라이더 바는 'sliderTime'라는 명령어를 사용하면 바로 구할 수 있으므로 우리는 범위 지정용 시작프레임과 끝 프레임을 구할 수 있습니다.

하지만 안타깝게 도, 선택한 키의 프레임보다 타임슬라이더 바가 더 뒤에 있는다는 보장은 없습니다.

반대로 타임슬라이더 바가 더 앞에 있을 수 있습니다.

그리고 여기서 '배울것이 너무 많아'님이 '선택한 키는 빼달라'는 조건이 있었습니다.

그렇기 때문에 실제 범위는 선택한 키보다 한 프레임 크거나(타임슬라이더 바 값이 더 큰 경우) 혹은 한 프레임 작아야(타임슬라이더 바 값이 더 작은 경우) 합니다.

그래서 찾아낸 값을 한번 가공하도록 하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(selectKeyFrame > -9999) do
(
    if(selectKeyFrame > sliderTime) then
    (
        firstTime = sliderTime
        secondTime = selectKeyFrame - 1
        selKey_fn()
    )
    else if(selectKeyFrame < sliderTime) do
    (
        firstTime = selectKeyFrame + 1
        secondTime = sliderTime
        selKey_fn()
    )
)
cs

이 스크립트는 이전의 스크립트 다음의 내용입니다.

먼저 1번 라인은 이전 스크립트에서 선택된 키가 있다면 다음 스크립트를 실행하라는 내용입니다.

selectKeyFrame변수의 선언이 있어야 하는데 설명을 우선시하기 위해 그 부분이 지금은 빠져 있습니다.

selectKeyFrame는 선언할 때 '-9999'값을 주는데 이는 실제 애니메이션 작업을 할 때는 -9999 프레임에 키를 주는일이 없기 때문입니다.

만약에 -9999프레임에 키가 들어간다면 이전 스크립트에서 if문안에 false로 선언된 Bool타입 변수에 true를 주어 그것으로 확인하는 방법도 있습니다.

3번 라인의 내용은 선택된 키 프레임이 타임슬라이더 바의 키 프레임보다 클 경우로

키 선택 범위의 시작 프레임은 타임슬라이더 바의 프레임이고

키 선택 범위의 끝 프레임은 현재 선택된 키의 프레임보다 한 프레임 작은 값입니다.

9번 라인의 내용은 그 반대의 경우입니다.

키 선택 범위의 시작 프레임은 현재 선택된 키의 프레임보다 한프레임 큰 값이고,

키 선택 범위의 끝 프레임은 타임슬라이더 바의 프레임입니다.

두 if문 안에 공통적으로 있는  7, 13라인의 'selKey_fn()'는 함수 호출 명령입니다. 공통적으로 실행해야 하는 명령들이 있다는 뜻이죠. 그 함수의 내용을 보겠습니다.

 

1
2
3
4
5
6
7
8
9
fn selKey_fn =
(
    deselectKeys $.pos.controller(interval animationRange.start animationRange.end)
    deselectKeys $.rotation.controller(interval animationRange.start animationRange.end)
    deselectKeys $.scale.controller(interval animationRange.start animationRange.end)
    selectKeys $.pos.controller (interval firstTime secondTime)
    selectKeys $.rotation.controller (interval firstTime secondTime)
    selectKeys $.scale.controller (interval firstTime secondTime)
)
cs

내용은 크게 2가지입니다.

첫 번째는 3 ~ 5번 라인인 선택한 키를 해제하라(deselectKeys) 입니다.

두 번째는 6 ~ 8번 라인인 해당 범위의 키를 선택하라(selectKeys) 입니다.

(이전 스크립트에서 선택 범위 안에 선택된 키 프레임이 빠져 있습니다.)

'selectKeys'를 했을 때 이전에 선택한 키를 포함하여 선택을 하기 때문에 이전 키를 해제하기 위해 'deselectKeys'를 사용합니다.

그리고 'deselectKeys'와 'selectKeys' 둘다에 'position, rotation, scale'의 'controll'이 설정되는데 이는 각각의 'controll'모두 선택하거나 해제해야만 정확하게 해당 키가 선택되고 해제되기 때문입니다.

이것은 'Track view'의 'Doop Sheet..'를 선택한 후에 'position, rotation, scale'을 각각 선택하거나 해제해보면 확실히 이해할 수 있습니다.

트랙마다 각각의 키가 따로 존재한다.

 

아직 빠진 것이 있는데 변수의 선언부입니다.

1
2
3
4
keysCount = 0
selectKeyFrame = -9999
firstTime = 0
secondTime = 0
cs

이것이 없으면 나머지 부분을 가지고 실행해도 에러가 나거나 다른 결과가 나올 것입니다.

 

이모두를 합치면 다음과 같은 스크립트가 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
keysCount = 0
selectKeyFrame = -9999
firstTime = 0
secondTime = 0
 
fn selKey_fn =
(
    deselectKeys $.pos.controller(interval animationRange.start animationRange.end)
    deselectKeys $.rotation.controller(interval animationRange.start animationRange.end)
    deselectKeys $.scale.controller(interval animationRange.start animationRange.end)
    selectKeys $.pos.controller (interval firstTime secondTime)
    selectKeys $.rotation.controller (interval firstTime secondTime)
    selectKeys $.scale.controller (interval firstTime secondTime)
)
 
keysCount = numKeys $.pos.controller
 
for i = 1 to keysCount do
(
    if((isKeySelected $.pos.controller i) == true) do
    (
        selectKeyFrame = getKeyTime  $.pos.controller i
    )
)
if(selectKeyFrame > -1) do
(
    if(selectKeyFrame > sliderTime) then
    (
        firstTime = sliderTime
        secondTime = selectKeyFrame - 1
        selKey_fn()
    )
    else if(selectKeyFrame < sliderTime) do
    (
        firstTime = selectKeyFrame + 1
        secondTime = sliderTime
        selKey_fn()
    )
)
cs

 

키를 하나 선택하고, 타임슬라이더 바를 위치시킨 후 스크립트를 실행하면

이렇게 타임슬라이더 바가 앞프레임에 있으면
처음에 선택한 키를 날리고 범위 선택을 하고
반대의 경우에도
잘 선택이 됩니다.

 

만족스럽게 작동합니다.

여기에 기능을 더 추가하면 복잡한 상황이나 특이 케이스에서도 잘 작동할 수 있습니다.

 

오늘은 여기까지 알아보겠습니다.

수고하셨어요.

728x90
반응형