posted by cimple 2017. 6. 16. 11:17

참고링크 :

http://discourse.techart.online/t/undo-in-maya-mel-python-execution/2431/7


Maya 의 Undo 는 Queue 에 순차적으로 작업을 쌓는다. 그런데 Undo 를 수행했을 때 Undo 를 여러번 누르는 것이 아니라 Ctrl+Z 한번에 Undo 되기를 원하는 작업이 있을 수 있다. 예를 들어 오브젝트를 한 백개쯤 복사했다던가.... 이럴 때 Undo 를 100번을 눌러야 한다면 그닥 유쾌한 일이 아닐 것이다.


Maya command 의 undoInfo() 가 해당 기능을 가지고 있다.

import maya.cmds as mc
mc.undoinfo(openChunk=True)
#Code Code Code
mc.undoinfo(closeChunk=True)

위 #Code Code Code 에 해당하는 부분을 한방에 Undo 시켜 주는 것이다.

그런데 openChunk 기능은 maya 의 UndoQueue 를 직접 건드리는 상당히 위험한 기능이기 때문에 안전하게 사용할 필요가 있다. 그래서 열고 닫기가 확실하게 진행될 수 있도록


mc.undoInfo(openChunk=True)
try:
    #CODE CODE CODE
finally:
    mc.undoInfo(closeChunk=True)

위와 같은 방식으로 작성하는 것이 안전하다.

또는 다음과 같이 context class 를 만들어서


class UndoContext(object):
    def __enter__(self):
        mc.undoInfo(openChunk=True)
    def __exit__(self, *exc_info):
        mc.undoInfo(closeChunk=True)

with UndoContext():
    ... your code here....

UndoChunk 가 안전하게 열고 닫히도록 할 수도 있다.

posted by cimple 2016. 12. 13. 17:55

Maya 에서 Object 들의 Transform 을 얻어오는 방식에 대해서 정리한다.

이것이 중요한 이유는 어플리케이션을 만들 때 get 하는 일이 많이 있는데, 만약 애니메이션 전체에 대해서 빈번하게 발생할 경우 효율적인 계산이 필요하기 때문이다.



Maya Command

xform : 대부분의 transform 정보를 가져올 수 있으나, '현재' 오브젝트에만 접근 가능하다. 즉, 애니메이션 오브젝트의 정보를 가져오려면 currentTime 커맨드와 함께 사용해야만 하는 단점이 있다. 이러면 많이 느려진다.

getAttr: time flag가 있어서 각 애니메이션된 오브젝트들의 attribute 데이터에 빠르게 접근할 수 있다. 그러나 attribute 가 움직이지 않는 데이터(ex. IK chain에서 조인트의 translateXYZ 정보) 등은 받아올 수가 없다.

position 을 확인하기 위한 하나의 꼼수(!) 는 다른 object 에 constraint 를 걸고 이 값을 받아오는 것이다.


 import maya.cmds as mc

import time

def xform_per_frame(object, start_frame, end_frame):
posList = []
for i in range(start_frame, end_frame):
mc.currentTime(i)
pos = mc.xform(object, t=True, q=True, ws=True)
posList.append(pos)
return posList

def getAttr_test(object, start_frame, end_frame):
posList = []
for i in range(start_frame, end_frame):
posX = mc.getAttr(object+'.translateX', t=i)
posY = mc.getAttr(object+'.translateY', t=i)
posZ = mc.getAttr(object+'.translateZ', t=i)
posList.append([posX, posY, posZ])
return posList



t00 = time.time()
xform_list = xform_per_frame('locator1', 1, 100)
t01 = time.time()
getAttr_list = getAttr_test('locator1', 1, 100)
t02 = time.time()

print 'xform time : ', t01-t00
print 'getAttr time : ', t02-t01

위 코드는 xform 과 getAttr 의 시간차이를 나타내주는 코드이다. locator1 에 100프레임의 애니메이션을 주고 position 값을 얻는 동일한 기능을 수행한다.

시간 차이는

xform time :  0.328000068665

getAttr time :  0.0789999961853

로 4~5배정도 차이가 나는 것을 확인할 수 있다. scene 이 무거울수록 currentTime 으로 frame 을 변화시킬 때 발생하는 딜레이 현상은 더 심해진다. 


NOTE

그러나 getAttr 에도 중요한 버그(?) 가 있는데, 만약 해당 object 의 attribute 가 setKeyframe 이나 setAttr 등으로 인하여 변했을 경우, getAttr 을 하면 실제 attribute 가 바뀌었는데도 기존 값이 그대로 들어오는것을 볼 수 있다. 심지어 타임 슬라이더를 왔다갔다 하거나 카메라를 움직이거나 하는 등 씬을 새로고침해도 이 값이 변화하지 않음을 알 수 있다.

의아하게도 getAttr 로 다른 프레임의 값을 한번 읽은 다음 다시 내가 원하는 프레임의 값을 읽으면 정상적으로 값을 불러들여옴을 확인할 수 있다. 이건 버그성이 있는 것 같다.


keyframe: keyframe 을 가진 object 라면 keyframe 커맨드를 통해서 value 를 알아낼 수 있다. 꼭 keyframe 에 해당하는 frame 의 value 뿐만 아니라, key 가 없는 frame 의 value 도 알아낼 수 있다.

print mc.keyframe('ikHandle1.translateX', q=True, ev=True, t=(40,40)) 

getAttr 과는 다르게 중간에 값이 변화하더라도 즉각즉각 변화된 값을 잘 반환해준다.

그러나 아쉽게도 key 값이 없는 object 에 대해서는 값을 반환하지 않는다. 아마도 key 가 생기면 면 animation curve 가 생성되게 되고, keyframe 커맨드는 이 그래프의 값을 반환하는 것으로 생각된다. 


Maya API 를 활용하는 방법

http://cimple.tistory.com/428

해당 포스트를 참조


posted by cimple 2016. 8. 19. 15:22

Hair simulation 을 위하여 Nurbs curve 를 nHair 의 Make Selected Curve Dynamic 으로 만들어 줄 때,


기존의 curve 가 Maya2016 버전에서는 null node 형태로 보이게 된다.


이는 해당 curve 의 shape 노드에 들어가 보면, object display 메뉴에서 Intermediate Object 로 체크가 된 상태로 바뀌기 때문이다.


해당 체크를 풀면 다시 보통 nurbs curve 가 되고 이 curve 를 복사해서 blendshape 을 쓰거나 cluster 를 적용해서 디폼시키는 등의 활용이 가능하다.

posted by cimple 2016. 4. 18. 17:23


(위 이미지는 참고링크에서 가져온 것)


참고링크

http://forums.autodesk.com/t5/maya-general/joints-display-broken-viewport-2-0/td-p/6053740



엔비디아 그래픽카드 드라이버 업데이트 후, Maya viewport 2.0 에서 조인트가 깨져보이는 현상이 발생하는데,


참고 링크에서 답을 찾을 수 있었다. 


Windows -> Settings/Preferences -> Preferences -> DisplayWindows -> Settings/Preferences -> Preferences -> Display


에 들어가서


Viewport 2.0 의 엔진을 OpenGL 에서 DirectX 로 변경...




posted by cimple 2016. 3. 31. 16:57

Maya 에서 특정 프레임 f 에서 object 의 world position 을 얻는 가장 간단한 방법은 이것이다.


import maya.cmds as mc
mc.currentTime(f)  # f is specific frame
mc.xform(obj, q=True, t=True, ws=True), #obj is specific object

그러나, 이 방식의 경우 'currentTime()' 커맨드로 특정 프레임으로 이동한 다음 계산하므로 씬이 전체적으로 업데이트 되어야 해서 만약 다수의 프레임에 대해 처리를 해야 할 경우 속도가 매우 느리다.


'currentTime()' 커맨드를 쓰지 않고 위치정보를 받아올 수 있는 다른 방법으로는 'getAttr()' 커맨드를 이용하는 방식이 있는데, 이 방식은 말그대로 attribute 의 값을 가져올 뿐이므로, object 의 world position 같은 정보를 직접적으로 얻어올 수는 없다.


이를 위하여, 아래는 Maya Python API 2.0 을 활용하여 특정 ojbect 의 world position 을 내가 원하는 frame 에서 찾는 Python Script 이다.


import maya.cmds as mc
import maya.api.OpenMaya as om

def mayaTimeUnitTypeQuery():
    mayaTimeUnitDic = {'100fps':25, '10fps':18, '1200fps':38, '120fps':26, '125fps':27, '12fps':19, '1500fps':39, '150fps':28, '16fps':20, '2000fps':40, '200fps':29, '20fps':21, '240fps':30, '250fps':31, '2fps':12, '3000fps':41, '300fps':32, '375fps':13, '400fps':34, '40fps':22, '4fps':14, '500fps':35, '5fps':15, '6000fps':42, '600fps':36, '6fps':16, '750fps':37, '75fps':23, '80fps':24, '8fps':17, 'film':6, 'game':15, 'hour':1, 'millisec':4, 'sec':3, 'min':2, 'ntsc':8, 'ntscf':11, 'palf':10, 'pal':7, 'show':9} 
    curTimeUnit = mc.currentUnit(q=True, time=True)
    try:
        mayaTimeUnit = mayaTimeUnitDic[curTimeUnit]
    except:
        raise NameError('Invalid Maya time unit. %s is not in the Maya unit dictionary.'%(curTimeUnit))
    return mayaTimeUnit
    

def getWorldPosAtTime(obj, frame):
    sList = om.MSelectionList()
    sList.add(obj)
    dagPath = sList.getDagPath(0)
    transFn = om.MFnDagNode(dagPath)
    matrixPlugArr = transFn.findPlug('worldMatrix', 0)
    matrixPlugArr.evaluateNumElements()
    matrixPlug = matrixPlugArr.elementByPhysicalIndex(0)
    
    curTimeUnit = mayaTimeUnitTypeQuery()
    mayaTime = om.MTime(frame, unit=curTimeUnit)
    timeContext = om.MDGContext(mayaTime)
    
    plugObj = matrixPlug.asMObject(timeContext)   
    #print plugObj.apiTypeStr  #kMatrixData
    plugObjFn = om.MFnMatrixData(plugObj)
    worldMatrix = plugObjFn.transformation()
    worldPos = worldMatrix.translation(om.MSpace.kWorld)
    return worldPos

mayaTimeUnitTypeQuery() 함수는 현재 Maya 에 설정되어 있는 FPS 값을 미리 상수로 예약되어 있는 MayaTimeUnit 값으로 리턴해준다. Maya 에 예약된 모든 FPS 를 포함하는 함수이므로 유용할 것이다. 이 함수에서 오류가 난다면 버그가 있는 것이므로 제보바람.

getWorldPosAtTime() 함수가 우리가 원하는 일을 해 주는 함수인데, 위치를 알고싶은 obj 와 frame 을 입력하면 해당 frame 에서의 world position 을 반환해준다.
Object DagNode 의 worldMatrix plug 에서 matrix data 형태로 어떻게 가지고 오는지,
그리고 MTime 과 MDGContext timeContext 객체를 만들어 어떻게 특정 frame 에서의 value 를 retrieve 하는지가 주목할 만한 부분이다.



posted by cimple 2016. 3. 29. 17:26

Numpy 에 nonzero 라는 function 이 있다.


http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.nonzero.html#numpy.nonzero


document 를 봐도 헷갈리는 함수인데, non-zero 인 element 에 대하여 2D array 형태로 리턴하는 함수이다.


예를 들어

import numpy
arr = numpy.array([[1,0],[2,3]])
arr.nonzero()

이런 식으로 사용했을 때, 다음과 같은 결과를 얻게 될 것이다.

--> (array([0, 1, 1]), array([0, 0, 1]))

이 결과물이 낯설게 느껴질 수 있는데, input 으로 주어진 행렬에서 nonzero element 의 'index' 를 행과열을 각각 적은 것이다.


다시 말해서, input 으로 주어진 행렬(numpy array) 는 다음과 같다.


| 1   0 |

| 2   3 |


여기에서 0이 아닌 element 들의 행렬 index 는 다음과 같을 것이다. 행, 열의 성분을 보기 쉽도록 다른 색으로 표현했다.


(0,0), (1,0), (1,1)


numpy.nonzero 함수는 저 index 들에서 행은 행대로, 열은 열대로 따로 묶어서 리턴해주는 것이다. 


(0, 1, 1)

(0, 0, 1)


왜 이런 식으로 리턴하는가 하면, ([0,1,1], [0,0,1]) 형태의 튜플로 원래 array 에서 곧바로 element 를 뽑아올 수 있기 때문이다.


다시 말하면 위의 예제에서

arr[arr.nonzero()]
--> array([1, 2, 3])

이런 식으로 non-zero element 를 직접 접근할 수 있고, 이는

arr[[0,1,1],[0,0,1]]

로 직접 입력해 보면 같은 결과를 얻을 수 있음을 확인할 수 있을 것이다.





Numpy 의 where() 함수도 마찬가지이다.


http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.where.html


where() 함수는 condition 만 주어지면 condition 을 만족시키는 element 의 index 를 반환하는데, 이 때 반환하는 형식이 nonzero 함수와 동일하다.



posted by cimple 2016. 3. 16. 12:24

Github 사용은 할때마다 조금씩 느는것 같긴 한데 계속 헷갈리는 부분이 있는것 같다.

논문 작성을 다른 멤버들과 같이하기 위해서 논문작성 자체를 Github 를 통해서 진행하려고 한다.


1. 논문 texfile 이 있는곳에 create repository 를 하면 git 저장소가 된다.

2. 일단 master branch 로 initial commit 했다.

3. 내가 수정할 local branch 를 만들고, 거기에서 수정을 한 다음, master 에 merge 할 수 있다. Window 용 github 프로그램에서 손쉽게 할 수 있는데, merge 를 당할(?) branch 에 간다음, 특정 branch 와 compare 하고, 충돌이 없으면 merge 할 수 있다. (ex. master 로 checkout -> songjaewon branch 와 비교 -> 충돌없으면 merge)


4. 협업을 위해서는 github상에서 merge 절차를 하는게 맞아보인다.

5. github 저장소에서 branch 를 만들어 줄 수 있다. 또는, 내 repository 를 fork 한 사람이 나름 local branch 를 만든 다음 push 할 수도 있을 것이다.

6. 내 branch 와 master branch 를 비교해서 pull request 를 보낼수 있다. 문제가 없으면 master 가 merge 시켜주면 해당 버전으로 최신 업데이트 되는 것이다.


7. 내 local 에서는 sync 를 하면 master 의 최신내용으로 업데이트된다. 


(알아야 할 것. 내 master 와 github 의 master 가 서로 다를 경우 sync 를 시키면 어디를 기준으로 최신업데이트가 이루어지는지 궁금하다)


(알아야 할 것. 다른 사람이 올린 branch 를 내 local repository 에 끌고올수는 없는지 궁금하다.)

posted by cimple 2015. 12. 13. 02:49



일단 위의 링크에서 몇 개의 example을 확인할 수 있다. 

posted by cimple 2015. 12. 11. 23:11

기본적으로 Maya Python Command 는 '실행해야' 동작하는 구조를 가지고 있다. 즉, 무언가 Maya 로부터 Active 하게 기능을 실행하는 데에는 주로 Node 를 활용해야 한다는 것이다.


가장 쉬운 예로, 내가 Maya 의 Time Slider 를 이리저리 왔다갔다 했을 때, 현재 프레임이 찍히도록 하고 싶다, 라고 하면 일단 난감하다. 기본적으로 Python command 는 'maya.cmds.currentTime(q=True)' 라는 명령어를 실행해야 현재 프레임을 받아올 수 있기 때문이다.


그러나, Active 한 기능을 비교적 쉽게 구현할 수 있다. 바로 마야에서 제공하는 Callback 함수를 이용하는 것이다.


위의 쉬운 예제를 코드로 짜면 다음과 같다.


import maya.cmds as mc
import maya.OpenMaya as om
def customFtn2(msg):
    print 'currentTime : ', int(mc.currentTime(q=True))
frameCallback = om.MEventMessage.addEventCallback('timeChanged', customFtn2)


이렇게 하면 타임 슬라이더바를 움직이는 것 만으로도 스크립트를 실행할 수 있다.

그러나 여기에서 유의할 것은 한번 연결해준 콜백 함수는 마야가 꺼질때까지 동작한다. 그러므로 더 이상 이 기능을 사용하고 싶지 않으면, 내가 연결해준 콜백 연결을 해제해야 한다. 이 해제는 콜백 넘버를 통해서 할 수 있는데, addEventCallback 함수가 리턴하는 것이 바로 이 콜백 넘버이다. 

그러므로 아래와 같이 콜백 연결을 삭제할 수 있다.


om.MEventMessage.removeCallback(frameCallback)



이렇게 해 주면 된다.





Maya command 중에 scriptjob 커맨드를 사용하면 이와 유사한 효과를 낼 수 있다.

그러나 api 를 사용하는 것과 달리, 명령이 종료한 후에 효과를 발휘한다.

쉽게 말해, 위의 예제에서 타임 슬라이더바를 움직이는 동안에는 효과가 없고, 마우스 버트를 놓는 순간부터 효과가 발휘된다는 뜻이다.



posted by cimple 2015. 11. 25. 20:29

File > Settings... > Project:  > Project Interpreter > 톱니바퀴 > More... > Show paths for the selected interpreter > Add path