posted by cimple 2019. 9. 2. 17:52

Maya API 에서 기본적으로 Mesh 를 다루는 class 는 MFnMesh 이다.

또한 Maya 는 polygon, edge, vertex 등 특별한 component 를 대상으로 iterator 를 제공한다. MItMeshPolygon, MItMeshEdge, MItMeshVertex.

만약 mesh vertex 를 에디팅하고 싶다면, 다음 두 가지 방식은 같은 일을 수행한다.

mesh_fn = om.MFnMesh(mesh_obj)
num_vtx = mesh_fn.numVertices
for ids in range(num_vtx):
	mesh_fn.setPoint(idx, om.MPoint([0., 0., 0.]))    
mesh_vtx_it = om.MItMeshVertex(mesh_obj)
mesh_vtx_it.reset()
while not mesh_vtx_it.isDone():
	mesh_vtx_it.setPosition(om.MPoint([0., 0., 0.]))
    mesh_vtx_it.next()

그래서 이 때, 왜 iterator 가 필요한지, 그리고 속도는 무엇이 더 빠른지에 대한 궁금함이 있을 수 있다.

결론적으로, Python API 에서는 for i in range(x) 형식의 loop 를 도는 것 보다. iterator 를 사용하는 것이 더 빠르다고 알려져 있다.

또한, 꼭 Maya API 의 iterator 뿐만 아니라, 기본적으로 iterator 를 사용하는 철학에 담긴 장점들이 곧 Maya API 의 iterator 를 사용하는 장점이라고 할 수 있다. 

iterator 는 컨테이너 안에 담긴 요소들에 대한 연산을 안정적이면서 효율적으로 수행하기 위한 여러 장점들을 가지고 있다. 가장 간단하게는 자료의 크기를 잘못 참조 (out of range) 할 염려가 없다는 것에서부터, 자료구조와 그 자료구조를 탐색하는 영역을 분리시킴으로써 보다 안전한 코드 작성이 가능하다는 등의 장점이 그것이다. 

posted by cimple 2019. 9. 2. 17:17

Maya 의 node attribute data 에 접근할 때, MPlug 와 MDataHandle 을 사용하는 방법이 있다. 언뜻 보면 두 방법 다 동일해 보인다. 

하지만 두 방식을 선택할 때에는 주의할 사항이 있다.

한 가지 기억해야 할 Rule 은, Custom node 의 MPxNode::compute() function 안에서 연산이 이루어질 떄에는 compute() 에 넘겨진 MDataBlock 으로부터 만들어진 MDataHandle 을 통해서 접근해야 한다는 것이다. 이 밖에는 MPlug() 를 사용해야 한다.

MPlug 로 compute() function 과 같은 곳에서 데이터에 접근하는 것은 DG가 정확하게 업데이트 되지 않을 수 있다는 위험성을 가지고 있다. 

반대로 compute() function 바깥에서는 MPxNode::forCache() 와 같은 함수를 이용해서 MDataBlock/MDataHandle 을 사용할 수 있는데, 이 경우 plug 가 dirty 되더라도 update 된 데이터를 보장하지 않을 수 있다.

 

간단하게 두 방식을 요약하면 다음과 같다.

MPlug 의 장점:

1. 모든 dirty propagation 을 제공한다.

2. 필요한 노드 업데이트 연산을 자동으로 수행한다.

3. multi element 가 필요할 때 자동으로 생성한다.

MDataBlock/MDataHandle 의 장점:

1. MPlug 보다 빠르다.

2. dirty plug 의 현재 값을 노드 업데이트를 force 하지 않고도 가져올 수 있다.

 

 

이 글은 다음 글에 기반하여 작성되었다.

https://around-the-corner.typepad.com/adn/2015/03/evaluating-node-attribute.html

 

posted by cimple 2019. 8. 28. 15:52

Maya Blendshape Node 에 대한 분석의 결과물을 정리해 보려고 한다.

1. Blendshape node 의 생성

mesh 1, mesh 2, mesh 3 을 차례로 선택하고 blendshape 을 생성하면, 가장 마지막에 선택한 mesh 3 이 base mesh(neutral shape) 이 되면서 blendshape node 가 생성된다.

2. Blendshape node 의 연결

- Blendshape 의 input 으로 base mesh 는 입력되지 않는다. Blendshape node 의 output geometry attribute 가 base  mesh 의 inMesh 에 연결된다. base mesh 의 기본 정보는 커맨드 형태로 Blendshape node 에 입력되는 것을 보인다.

- Blendshape 에 target mesh 들은 input 에 직접 입력된다. 이 때, BlendshapeNode.InputTarget[0].InputTargetGroup[0].InputTargetItem[6000].InputGetomTarget 이라는 복잡한 과정을 거쳐서 mesh 데이터를 입력받는다. 상위의 attribute 들은 모두 compound attribute.

-Target shape 이 늘어날 때마다, BlendshapeNode.InputTarget[0], BlendshapeNode.InputTarget[1] ... 이런 식으로 Array attribute 형태로 붙게 된다. 이 array attribute 를 직접 attribute editor 나 channel box 에서 확인할 수는 없다. 

- Array attribute 의 특성상, node 내부에 미리 정해진 저장 공간을 할당하고 거기에 target shape 들을 연결한다. 만약 initial 로 3개의 target 을 연결했다면, 3개의 target mesh 를 받을수 있는 attribute 공간이 생성되고, node 연결을 끊더라도 이 공간 크기는 유지된다. 만약 새로운 공간을 더 확보하고 싶다면 Maya 에서도 Add blendshape 버튼을 제공하듯이, node 저장공간을 더 할당하고 Blendshape node 를 꽂아넣는 과정이 필요하다.

3. Shape 의 구성

- Blendshape 을 연결하면, base mesh object 에 orig shape 이 추가로 생성된다. orig shape 은 blendshape 에만 생성되는 것은 아니고, maya deformer 를 설치하면 자동으로 생성된다.

- base mesh 의 transform 에 종속되어 포함된다. 그러나 outliner 나 viewport 에서 바로 확인할 수는 없는데, 이는 이 오브젝트가 intermediate object 이면서 hidden in outliner 속성이 적용되어 있기 때문이다. Node editor 같은 곳에서 이 orig shape 을 선택한 다음, attribute editor 에서 Intermediate object 항목을 체크 해제해 주면 viewport 상에서 해당 shape 을 볼 수 있고, Hidden in Outliner 항목을 체크 해제해주면 Outliner 에서 해당 Mesh 의 Transfrom 에 child 로 들어 있는 Orig shape 을 확인할 수 있다.

- 만약 Intermediate object 를 보고 싶어서 항목을 체크 해제하면, 해당 오브젝트의 History 를 지워서 Blendshape node 를 지운다고 해도 이 OrigShape 은 남아있게 된다. 체크가 되어 있으면 history 를 지우면 intermediate object 도 함께 사라지게 된다.

posted by cimple 2017. 9. 26. 17:15

Custom orient constrain node & command 를 구현하였다.


CustomOrientConstrain.py

setCustomOrientConstrain.py




위 파일로 다운로드 받으면 된다.



Warning


Maya 2017 에서 버그를 발견하였다. (내 버그가 아니라 Maya 버그)

노드를 생성하고 연결하는 CustomOrientConstrainCmd.py 에서,

현재 코드처럼 custom node 를 생성한 다음 MSelectionList 에서 dagPath 를 받으면 argument 가 부족하다는 에러가 뜬다.

에러 메시지를 뜯어보니 아마도 Maya Python API 1.0 에 있는 MSelectionList_getDagPath 가 호출되는 것으로 보이는데 이유는 불명이다.


그래서 순서를 일단 MSelectionList 에 dagPath 를 받은 다음 -> Custom node 를 생성하면 정상작동한다.



posted by cimple 2017. 9. 19. 18:55

thisNode = ClassName.thisMObject(self)


이렇게 하면 thisNode 에 만들어진 Maya Node 스스로를 얻어올 수 있다.

posted by cimple 2017. 9. 15. 13:30

1. Message attribute 의 개념에 대하여

Message attribute 의 개념에 대해서는 이 영상이 잘 설명해 주고 있다.

https://vimeo.com/45110586

Message attribute 가 하는 일은 "내가 누구다" 라고 inform 을 알려주는 일이 전부이다. 중요한 것은 어떠한 Data 도 실질적으로 전달되지 않는다는 것이다.


2. Message attribute 의 값 참조

Custom Node 에서 Message Attribute 를 만든 다음 getAttr() 로 들어있는 값을 참조해보려고 해도 되지 않는다. Message Attribute 에는 실질적으로 값이 들어있지는 않기 때문이다.

따라서 Maya Script 를 이용할 때도 그렇고, 노드 안에서 API 코드로 접근할 때도 그렇고 Message attribute 에 있는 값을 직접 읽어들이려고 해서는 안 된다. (API 의 경우 MDataHandle 로 attribute 를 읽어들인 후 type 체크를 해 보면 invalide 라고 뜨게 된다.)

따라서 Message attribute 에서는 connection 만을 확인해야 한다. 해당 attribute 에 무엇이 연결되어 있는지를 확인하는 용도이다.

python command 의 경우 mc.listConnections("MyMsgAttr") 하는 식으로 연결되어 있는 대상을 찾아야 한다.

API 경우 plug 에 connection 되어 있는 다른 node 들을 찾을 수 있을 것이다.


3. Message attribute 의 Array 의 활용

Message attribute 도 array 형태로 attribute 를 만들 수는 있다.

그러나 attribute editor 에서 array 형태의 message attribute 가 표시되지는 않는다. 지금 내 경우에는 src/tgt 의 정해진 갯수의 skeleton 만을 가지로 retarget node structure 를 구성하면 되므로 굳이 array 를 쓸 필요는 없을 것 같다.

posted by cimple 2017. 9. 12. 12:05
def compute_point_to_box_dist(minXYZ, maxXYZ, point):
    dx = max(minXYZ[0] - point[0], 0, point[0] - maxXYZ[0])
    dy = max(minXYZ[1] - point[1], 0, point[1] - maxXYZ[1])
    dz = max(minXYZ[2] - point[2], 0, point[2] - maxXYZ[2])
    return (dx*dx + dy*dy *dz*dz)**0.5


위 함수를 이용하면 axis-align 된 bondong box 와 point 사이의 distance 를 간단하게 구할 수 있다.

참고 : https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point

posted by cimple 2017. 9. 8. 11:12

다음과 같은 상황에 python 의 re(regex) 라이브러리를 활용하였다.


"pPlane1.v[10]"


이라는 string 정보를 Maya 로부터 입력받았을 때, 나는 여기에서 10 이라는 vertex 의 index 만 int 형태로 받고 싶다.

find 같은 명령어를 써서 10을 찾을 수도 있겠지만 re 라이브러리를 사용하면 1줄이면 가능하다.


import re

vtx_index = int(re.findall(r'\b\d+\b', "pPlane1.v[10]")[0])


자세한 사용법은 추후에 더 공부



posted by cimple 2017. 8. 31. 12:07

Maya Node 를 개발할 때, attribute 로 모든 데이터를 저장하기에는 무겁고 처음 한번만 initialize 하면 되는 경우, 별도의 멤버변수를 만들어서 저장해 줄 수 있다.

그러나 이 때, Scene 을 저장했다가 open 할 때 initilize 가 되어 있지 않아서 연산되지 않는 경우가 발생한다. 이를 위해 Scene 이 열릴 때 한 번 더 업데이트를 해주면 된다.

이 때 사용되는 것이 MSceneManager 콜백 함수이다.

나는 다음과 같은 예제에서 활용하였다.


먼저 pluginMain.cpp 에

..

#include <maya/MSceneMessage.h>

MCallbackId openCallback;

..

MStatus initializePlugin(MObject obj){

...

openCallback = MSceneMessage::addCallback(MSceneMessage::kAfterOpen,  lightFollicleNode::sceneOpenSetup)

...

}

MStatus uninitializePlugin(MObject obj){

...

MSceneMessage::removeCallback(openCallback);

...

}


위와 같이 Plugin 에서 Callback 함수를 add 해 주고, Plugin 을 deregister 할 때 반드시 removeCallback 을 해주어야 한다.

이제 Scene 이 열렸을 때 sceneOpenSetup() 이라는 함수를 호출하게 된다.


void lightFollicleNode::sceneOpenSetup(void *data){

  cout << "***lightFollicleNode:scene open***" << endl;

  isSceneOpen = true;

}

위와 같이 단순하게 flag 를 바꾸어주는 함수이다. 이를 통해서 compute function 에서 간단하게 업데이트 컨트롤을 해 줄수 있다.

posted by cimple 2017. 8. 17. 14:17

Maya API 에서 outRotate 값을 array attribute 로 만들어 주려면  compound array attribute 를 활용하면 된다.


initialize(){

...

MFnUnitAttribute uAttrFn;

MFnCompoundAttribute cAttrFn;


aOutRotateX = uAttrFn.create("outRotateX", "orx", MFnUnitattribute::kAngle, 0.0);

addAttribute(aOutRotateX);

aOutRotateY = uAttrFn.create("outRotateY", "ory", MFnUnitattribute::kAngle, 0.0);

addAttribute(aOutRotateY);

aOutRotateZ = uAttrFn.create("outRotateZ", "orz", MFnUnitattribute::kAngle, 0.0);

addAttribute(aOutRotateZ);


aOutRotateArr = cAttrFn.create("outRotateArr", "orarr");

cAttrFn.addChild(aoutRotateX);

cAttrFn.addChild(aoutRotateY);

cAttrFn.addChild(aoutRotateZ);

cAttrFn.setArray(true);

cAttrFn.setUsesArrayDataBuilder(true);

addAttribute(aOutRotateArr);

...

}


compute(){

...

MArrayDataHandle outRotateHndArr = data.outputArrayValue(aOutRotateArr);

MarrayDataBuilder outRotateBldArr = outRotateHndArr.builder();

unsigned int nOutRotate = (int)outRotateHndArr.elementCount();

for (unsigned int i=0 ; i<nOutRotate < i++){

  MDataHandle outHandle = outRotateBldArr.addElement(i);

  outHandle.set3Double(outRotArr[i][0], outRotArr[i][1], outRotArr[i][2]);

}

outRotateHndArr.set(outRotateBldArr);

outRotateHndArr.setAllClean();

...

}


그런데, 여기에서 Rotate 를 set 하는 value 가 angle 임에 주목해야 한다.


현 재 작성한 node 에서 vector 와 vector 사이의 사잇각을 rotateTo() 를 사용해서 MQuaternion 으로 찾고 이를 다시 MEulerRotation 으로 변환, MVector 에 저장한 다음 outRotate Attribute 에 set 해 주었다.

그런데 이 때 log 를 찍어보면 MEulerRotation 의 x,y,z 값과, 이를 MVector에 저장한 다음 찍히는 x,y,z 값이 달랐는데, 이 MVector 를 outRotate 에 set 해 보면 Maya 에는 MVector 에 찍히는 값이 아니라 MEulerRotation에 찍히는 값이 나온다.

아마도 라디안 계산을 하는 것으로 보이는데 자세한 사항은 향후 수정바람