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. 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에 찍히는 값이 나온다.

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


posted by cimple 2017. 7. 11. 15:45

참고링크 : http://www.marcogiordanotd.com/blog/maya/maya-api-tip-creating-compound-vs-point-attribute


position 과 vector 와 같은 multiple attribute를 Maya API 에서 넘겨주는 방법에는 다음과 같은 방법이 있다.


1) Compound attribute

//Output vector attribute
//Creating 3 single attributes  vectorX,Y,Z
MFnNumericAttribute oVecXAttr;
oVecX= oVecXAttr.create("vectorX","vx",MFnNumericData::kFloat);
addAttribute(oVecX);
 
MFnNumericAttribute oVecYAttr;
oVecY= oVecYAttr.create("vectorY","vy",MFnNumericData::kFloat);
addAttribute(oVecY);
 
MFnNumericAttribute oVecZAttr;
oVecZ= oVecZAttr.create("vectorZ","vZ",MFnNumericData::kFloat);
addAttribute(oVecZ);
 
//Output vector compound attribute
//Group them togheter with a compound attribute
MFnCompoundAttribute FoVec;
oVec= FoVec.create("outputVector","ov");
 
//use addChild method to add our attributes to the compound attribute
FoVec.addChild(oVecX);
FoVec.addChild(oVecY);
FoVec.addChild(oVecZ);
addAttribute(oVec);


2) Point attribute

//Create a numeric attribute function set
 
MFnNumericAttribute originFn;
 
&nbsp;
 
// instead using create() we will use createPoint()
origin=originFn.createPoint("origin","o");
addAttribute(origin);

그런데 이 경우 dataHandle 로 받아서 .asDouble3() 으로 받으면 제대로 값이 들어오지 않는다. .asVector() 도 Double 과 동일하다.

dataHandle.asFloat3() 으로 받아야 제대로 값이 들어온다.

compound attribute 를 사용할 경우 반대로 .asFloat() 을 쓰면 제대로 값이 들어오지 않고 .asDouble3() 을 사용해야 한다.

왜 이런지는 Autodesk 에 직접 문의해보아야 할 듯.


3) Compound attribute with different style

pointXAttrFn = om.MFnNumericAttribute()
lightFollicleLocator.aPositionX = pointXAttrFn.create("positionX", "px", om.MFnNumericData.kDouble, 0.0)
om.MPxNode.addAttribute(lightFollicleLocator.aPositionX)

pointYAttrFn = om.MFnNumericAttribute()
lightFollicleLocator.aPositionY = pointYAttrFn.create("positionY", "py", om.MFnNumericData.kDouble, 0.0)
om.MPxNode.addAttribute(lightFollicleLocator.aPositionY)

pointZAttrFn = om.MFnNumericAttribute()
lightFollicleLocator.aPositionZ = pointZAttrFn.create("positionZ", "pz", om.MFnNumericData.kDouble, 0.0)
om.MPxNode.addAttribute(lightFollicleLocator.aPositionZ)

pointAttrFn = om.MFnNumericAttribute()
lightFollicleLocator.aPosition = pointAttrFn.create("position", "p", lightFollicleLocator.aPositionX, lightFollicleLocator.aPositionY, lightFollicleLocator.aPositionZ)
om.MPxNode.addAttribute(lightFollicleLocator.aPosition)


그리고 이 경우, compute function 에서 plug==attribute 에 해당하는 부분에 attribute 를 그대로 compound attribute 이름을 넣으면 안된다. plug 에서 자동적으로 compound 하위 attribute 들을 plug 로 가져오기 때문이다.

custom 하게 만들어진 attribute들의 경우에는 각각의 경우를 넣으면 되겠지만, createPoint 로 attribute를 만들었을 경우에는 해당 plug 이름에 직접 접근하기가 애매하므로 plug.parent() 가 내가 만든 compound attribute 이름이 맞다면 compute 해라 라고 만들어주면 된다.


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



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

posted by cimple 2013. 8. 24. 14:41

C++ 과 Python 문법이 다르기에 Python 에서 Maya API 를 사용하는데 항상 헷갈린다.


몇 개의 예제를 통해서 사용법을 좀 알아보도록 하자.


Note : Maya Python API 2.0 이 출시되었는데, (maya.api.OpenMaya 로 import) 아직까지 지원 안되는 함수도 많은 것 같고 Document 도 엉망이고 좀 문제가 많은것같다.

안정화될때까지는 old version 의 Python API 를 사용하는게 맞을듯.



1. 선택한 Object 의 Dagpath 받아오기


import maya.OpenMaya as om  #import OpenMaya module

sList = om.MSelectionList()  #MSelectionList instance
om.MGlobal.getActiveSelectionList(sList)  #get the selection object list
dagPath = om.MDagPath()  #Dagpath instance
sList.getDagPath(0, dagPath)  #get the dagpath from 1st object of selection list


2. 여기에 이어 Camera 의 view direction 받아오기


camFn = om.MFnCamera(dagPath)  #MFnCamera instance
viewDirection = om.MVector()  #MVector instance
mspace = om.MSpace()  #MSpace instance
viewDirection = camFn.viewDirection(mspace.kWorld)  #Camera view direction in world space
print viewDirection.x, ' ',viewDirection.y,' ', viewDirection.z


간단한 예제들을 추가하면서, 사용방법에 대해 더 익숙해져 보도록 하자.

(그런데 Python2.0 에서는 문법자체가 다른것같은데...)

posted by cimple 2012. 12. 26. 22:11

Maya plug-in 개발 환경을 구축할 때, Plug-in wizard 를 사용하는 방법이 일반적이었지만, Maya version 및 Visual Studio version 에 따라 제대로 만들어지지 않는 등의 많은 문제가 있었다.


CG Circuit 의 Maya API 강좌를 참고해서 Maya Plug-in 개발환경 구축을 설명한다.



1. File > New Project > Win32 Project


2. DLL Project ,Empty project


3. Project properties


4. Configuration 탭다운 메뉴에서 All Configurations 선택


5. Linker > General > Output file 의 확장자를 .mll 로 변경


$(OutDir)\$(ProjectName).mll



6. C++ source code 추가


7. C/C++ > General > Additional include directory 에 Maya Include 디렉토리 추가


8. Preprocessor > Preprocessor Definitions 에


WIN32; NDEBUG;_WINDOWS;NT_PLUGIN;REQUIRE_IOSTREAM 


9. Linker > General > Additional library directory 에 Maya lin 디렉토리 추가


10. Input > Additional Dependencies 에


Foundation.lib OpenMaya.lib OpenMayaUI.lib OpenMayaAnim.lib 

OpenMayaFX.lib OpenMayaRender.lib Image.lib opengl32.lib glu32.lib


11. Command Line > Additional options :


/export:initializePlugin /export:uninitializePlugin


12. 상단의 Configuration 에서 x64로 변경 (64bit 의 경우)


Linker> Advanced 에서 target machine 확인