410 likes | 856 Views
Export 제작. 목 차. 소개 Export 사용 과정 Export 데이터의 이용 Maya API Export 작성 Export 설치 Export 설치 확인 Export 구현 Mesh Skeleton Skeleton Animation Skinning Q & A. 소 개. Export 란 기존의 3D Tool 에서 작업된 3D 데이터를 원하는 형식의 데이터로 가공 , 저장하는 것을 말합니다 .
E N D
목 차 • 소개 • Export 사용 과정 • Export 데이터의 이용 • Maya API • Export 작성 • Export 설치 • Export 설치 확인 • Export 구현 • Mesh • Skeleton • Skeleton Animation • Skinning • Q & A
소 개 • Export 란 기존의 3D Tool에서 작업된 3D 데이터를 원하는 형식의 데이터로 가공, 저장하는 것을 말합니다. • Maya는 그 기능을 외부에서 쉽게 확장할 수 있도록 API를 제공하고 있습니다. • Maya API를 사용하여, Mesh, Skeleton, Skeleton Animation 정보를 Export하는 Plug-in 제작 방법을 설명합니다.
Export 사용과정 • Maya로 제작된 캐릭터
Export 사용과정 • 제작한 Plug-in 로드
Export 사용과정 • Skin, Skeleton, Skeleton Animation 데이터를 각각 Export 합니다.
Export 사용과정 • Skin 데이터 로드
Export 사용과정 • Skeleton 데이터 로드
Export 사용과정 • Animation 데이터 로드
Maya API • C++ 인터페이스 • 구성 개체 종류 • Wrappers • 간단한 object. (수학, Container) • Objects • curves, sufaces, DAG nodes, dependency graph nodes, lights, shaders, textures 등등 • MObject • Maya Object를 접근하기 위한 handle object • Function Sets • Object에 대한 기능 인터페이스 • Proxies • 새로운 Maya object를 생성하기 위해 사용되는 object.
Maya API • Naming Conventions • MFn • Function set class • MIt • MObject의 반복자. • 반복자 요소에 대한 Function set 기능. • MPx • Proxies class • M • Wrapper class
DG Node (mesh) MObject Handle Fuction Set Maya API • Object와 FunctionSet (mesh 조작예) Select API를 이용, 특정 mesh에 대한 Handle을 얻음 Maya mesh function set과 object를 연결시킨후 function set의 함수 호출을 통해 작업
Maya API • DAG (Directed Acyclic Graph) • Geometry의 위치, 방향, 크기를 결정하는 Graph • Node • Transform Node : 변환 정보, 계층 정보 • Shape Node : Geometry 정보
Maya API • DAG Path • 특정 Node로의 경로 | group1 | pCone1 | pConeShape1 | group1 | pCone2 | pConeShape1 • 변환 (Transformation) 정보 계산시 사용
Maya API • DG (Dependency Graph) • Maya의 핵심 • 모든 Object들이 Node의 연결로서 생성됨
Maya API • DG : Triangulate 적용 후
Export 작성 • Project 생성 (vc++ 7.0 기준) • File > New > Project • New Project 대화 상자 • Project Types : Visual C++ Project > Win32 • Template : Win32 Console Project • 이름 / 위치 설정 • Win32 Application Wizard 대화상자 • Application type : ‘DLL’ 체크 • Additional options : ‘Empty project’ 체크
Export 작성 • Project Property 설정 • Configuration Properties > C/C++ > • Preprocessor • Preprocessor Definitions : • ‘NT_PLUGIN;REQUIRE_IOSTREAM’ 추가 • General • Additional Include Directories : • Maya 설치폴더\include폴더 추가 • Configuration Properties > Linker > • Input • Additional Dependencies : Maya Library들을 추가 • Foundation.lib OpenMaya.lib OpenMayaAnim.lib OpenMayaUI.lib OpenMayaAnim.lib OpenMayaFX.lib OpenMayaRender.lib • General • Additional Library Directories : • Maya 설치 폴더\lib폴더 추가 • Output File : • *.mll로 확장자 변경 • Command Line • Additional Options : • ‘/export:initializePlugin /export:uninitializePlugin’추가
Export 작성 • ExportMesh Class 작성 • <MPxFileTranslator> Class • Maya에 자신의 Export (FileTranslator)를 추가하기 위해서 상속받아야 하는 Proxy class. • 읽어들이는 기능을 구현할 때는 아래의 두 함수를 Override 한다. • virtual MStatus reader ( const MFileObject& file, const MString& optionsString, FileAccessMode mode) • 파일을 읽어, Maya에 반영시키는 코드를 작성한다. • virtual bool haveReadMethod () const • ‘true’를 반환하도록 한다. • 파일로 출력하는 기능을 구현할 때는 아래의 두 함수를 Override한다. • virtual MStatus writer ( const MFileObject& file, const MString& optionsString, FileAccessMode mode) • Maya의 정보를 File에 쓰는 코드를 작성한다. • virtual bool haveWriteMethod () const • ‘true’를 반환하도록 한다.
Export 작성 • 생성 함수 • 자신의 개체를 생성하는 static 함수를 제공한다. • void* creator () • 자신의 개체를 생성, 반환하도록한다. • Export는 보통 출력하는 기능만을 구현한다.
Export 작성 • ExportMesh Class 선언 예제 #include <maya/MPxFileTranslator.h> #include <maya/MString.h> class ExportMesh : public MPxFileTranslator { public: static const MString name_; MStatus writer (const MFileObject& file, const MString& options, FileAccessMode mode); bool haveWriteMethod () const { return true; } static void* creator () { return new ExportMesh (); } };
Export 작성 • Plugin 등록 / 해제 부분 작성 • <MFnPlugin> Class • plug-in 등록 및 해제 기능 • initializePlugin 및 uninitializePlugin 함수 내부에서 사용 • 주요 함수 MFnPlugin (MObject& obj, const char* vendor, const char* version, const char* requiredApiVersion, MStatus* returnStatus) MStatus registerFileTranslator (const MString& translatorName, char* pixmapName, MCreatorFunction creatorFunction, char* optionsScriptName, char* defaultOptionsString, bool requiresFullMel ) MStatus deregisterFileTranslator (const MString& translatorName) • MStatus initializePlugin (MObject obj)함수 작성 • MStatus uninitializePlugin (MObject obj)함수 작성
Export 작성 • Plug-in 등록 / 해제부분 작성 #include <maya/MFnPlugin.h> #include "ExportMesh.h“ MStatus initializePlugin (MObject obj) { MFnPlugin pluginFn (obj, “제작회사", "1.0"); return pluginFn.registerFileTranslator (ExportMesh::name_, NULL, ExportMesh::creator); } MStatus uninitializePlugin (MObject obj) { MFnPlugin pluginFn (obj); return pluginFn.deregisterFileTranslator (ExportMesh::name_); }
Export 작성 • plug-in의 구성 Proxy Class (Maya에서 사용하는 인터페이스) CMExport.mll plugin 등록 MPxFileTranslator initializePlugin uninitializePlugin ExportMesh plugin 해제 추가하는 Export Service
Export 설치 • 환경 변수 MAYA_PLUG_IN_PATH에 자신의 Plug-in 폴더 추가 • Window > Settings / Preferences > Plug-in Manager.. • loaded를 체크하면, initializePlugin이 호출되어 plugin이 등록되고, 이후부터 plugin 기능 사용 가능. • loaded의 체크를 해제하면, uninitializePlugin이 호출되어 plugin이 해제됨.
Export 설치 확인 설치 전 설치 후 • File > Export All > Option box
Export 구현: Mesh • 선택 목록 얻기 • MGlobal::getActiveSelectionList () • 현재 선택 개체 목록을 얻는 함수. • MSelectionList • 선택 개체 목록을 저장, 편집 • MItSelectionList • 선택 개체 목록을 필터링 순환. • 구현 코드 • 선택된 mesh 개체 목록 얻기 MSelectionList selList; MGlobal::getActiveSelectionList (selList); MItSelectionList iterMeshList (selList, MFn::kMesh); for (iterMeshList.reset (); !iterMeshList.isDone (); iterMeshList.next ()) { MDagPath path; iterMeshList.getDagPath (path); }
Export 구현: Mesh • Shape 노드 얻기 • <MFnMesh> 에 연결하기 • 구현 코드 for (iterMeshList.reset (); !iterMeshList.isDone (); iterMeshList.next ()) { MDagPath path; iterMeshList.getDagPath (path); path.extendToShape (); MFnMesh fnMesh; fnMesh.setObject (path); }
Export 구현: Mesh • 정점 목록 얻기 (vertex list) MPointArray vertexList; fnMesh.getPoints (vertexList, MSpace::kWorld); • 텍스쳐 좌표 목록 얻기 (uv list) MString uvSetName; fnMesh.getCurrentUVSetName (uvSetName); MFloatArray uList; MFloatArray vList; fnMesh.getUVs (uList, vList, &uvSetName); • 정점 법선 목록 얻기 (normal list) MFloatVectorArray normalList; int numberOfVertices = vertexList.length (); for (int vIndex = 0; vIndex < numberOfVertices; ++vIndex) { MVector vecNormal; fnMesh.getVertexNormal (vIndex, vecNormal, MSpace::kWorld); }
Export 구현: Mesh • Mesh 정보 얻기 (vertex index, uv index per triangle) int instanceNumber = 0; if ( path.isInstanced () ) instanceNumber = path.instanceNumber (); // Mesh를 구성하는 Set과 해당 Set의 Component 얻기 fnMesh.getConnectedSetsAndMembers(instanceNumber, setList, compList, true);
Export 구현: Mesh • 메쉬 정보 얻기 (vertex index, uv index per triangle) // Mesh를 구성하는 Set을 순환. for (unsigned int index = 0; index < setList.length (); ++index) { MItMeshPolygon iterPolygon (path, compList [index]); unsigned int triCount = iterPolygon.count (); for (iterPolygon.reset ();!iterPolygon.isDone (); iterPolygon.next ()) { int faceIndex = iterPolygon.index (); MIntArray vertexIndex; fnMesh.getPolygonVertices (faceIndex, faceIndex); for (int fvIndex = 0; fvIndex < 3; ++fvIndex) { int uvid; fnMesh.getPolygonUVid (faceIndex, fvIndex, uvid, &uvSetName); } } }
Export 구현: Mesh • 텍스쳐 파일 이름 얻기 – Shader 얻기 MFnDependencyNode fnNode (set); MPlug plugShader = fnNode.findPlug ("surfaceShader"); MPlugArray connectedPlugs; // connectedTo (MPlugArray& array, bool asDst, bool asSrc) plugShader.connectedTo (connectedPlugs, true, false); MObject shaderObj = connectedPlugs [0].node ();
Export 구현: Mesh • 텍스쳐 파일 이름 얻기 MPlug plugColor = MFnDependencyNode (shaderObj).findPlug ("color"); MItDependencyGraph iterDG (plugColor, MFn::kFileTexture, MItDependencyGraph::kUpstream, MItDependencyGraph::kBreadthFirst, MItDependencyGraph::kNodeLevel); MString textureName; MObject objTexture = iterDG.thisNode (); MPlug plugName = MFnDependencyNode (objTexture).findPlug ("fileTextureName"); plugName.getValue (textureName);
Export 구현: Skeleton • Root Joint 선택이 필요 • 선택 목록 얻기 MSelectionList selList; MGlobal::getActiveSelectionList (selList); MItSelectionList iterJointList (selList, MFn::kJoint);
Export 구현: Skeleton • Skeleton에 속하는 Joint들을 모으기 • Joint는 Transformation 정보를 가지고 있으므로, Joint에 대한 DagPath를 모은다. iterJointList.reset (); MDagPath dpRoot; iterJointList.getDagPath (dpRoot); MDagPathArray dpSkeleton; traverse (dpSkeleton, dpRoot); void traverse (MDagPathArray& dpSkeleton, const MDagPath& dpJoint) { dpSkeleton.append (dpJoint); unsigned int childCount = dpJoint.childCount (); for (int childIndex = 0; childIndex < childCount; ++childIndex) { MDagPath dpChild; MFnDagNode (dpJoint.child (childIndex)).getPath (dpChild); if ( dpChild.hasFn (MFn::kJoint) ) traverse (dpSkeleton, dpChild); } }
Export 구현: Skeleton • Joint 정보 출력 • 위치 / 회전 / Joint 이름 / 부모 Joint 이름 unsigned int jointCount = dpSkeleton.length (); for (unsigned int jIndex = 0; jIndex < jointCount; ++jIndex) { MDagPath dpJoint (dpSkeleton [jIndex]); MString strJointName = dpJoint.partialPathName (); MTransformationMatrix matTransform (dpJoint.inclusiveMatrix ()); MVector vTranslation = matTransform.translation (MSpace::kWorld); double qx, qy, qz, qw; matTransform.getRotationQuaternion (qx, qy, qz, qw); MString strParentJointName; // root : parent = empty if ( jIndex != 0 ) { dpJoint.pop (); strParentJointName = dpJoint.partialPathName (); } }
Export 구현: Skeleton Animation • Skeleton Animation 정보 얻기 unsigned int jointCount = dpSkeleton.length (); for (unsigned int frame = aStartFrame; frame <= aEndFrame; ++frame) { MTime curFrame; curFrame.setValue (frame); MGlobal::viewFrame (curFrame); for (unsigned int jIndex = 0; jIndex < jointCount; ++jIndex) { MDagPath dpJoint (dpSkeleton [jIndex]); MTransformationMatrix matTransform; If ( jIndex == 0 ) matTransform = dpJoint.inclusiveMatrix (); else { MMatrix matExcInv = dpJoint.exclusiveMatrixInverse (); MMatrix matInc = dpJoint.inclusiveMatrix (); MMatrix result = matInc * matExcInv; matTransform = result; } MVector vTranslation = matTransform.translation (MSpace::kTransform); matTransform.getRotationQuaternion (qx, qy, qz, qw); } 애니매이션 진행 부모로부터의 상대 변환
Export 구현:Skinning • Skinning 정보 얻기 • 연결된 SkinCluster 노드 찾기 • <MFnSkinCluster>에 연결후 작업
Export 구현:Skinning • Skinning 정보 얻기 // SkinCluster 노드 찾기 MItDependencyGraph DGIterator (dpMeshShape.node (), MFn::kSkinClusterFilter, MItDependencyGraph::kUpstream, MItDependencyGraph::kDepthFirst, MItDependencyGraph::kNodeLevel); MObject objSkinCluster = DGIterator.thisNode (); // 연결 및 작업 MFnSkinCluster fnSkinCluster (objSkinCluster); MDagPathArray dpInfluences; unsigned int numberOfInfluences = fnSkinCluster.influenceObjects (dpInfluences); for (unsigned int iIndex = 0; iIndex < numberOfInfluences; ++iIndex) { MDagPath dpInfluence = dpInfluences [iIndex]; MFloatArray weights; MSelectionList influencedList; fnSkinCluster.getPointsAffectedByInfluence (dpInfluence, influencedList, weights); // Vetex 정보 얻기 unsigned int size = influencedList.length (); for (unsigned int index = 0; index < size; ++index) { MDagPath dpMesh; MObject component; influecedList.getDagPath (index, dpMesh, component); MItMeshVertex iterMeshVertex (dpMesh, component); } }
Q&A ?
Demo • id software의 DOOM 3 Character • 자체 제작 Graphics 엔진