Max Export - 2

반응형


노드를 얻어오는 방법과 필요없는 노드를 분별하는 방법을 알았으니
이제 노드로부터 원하는 정보를 뽑아낼 필요가 있다.

우선 mesh 정보를 뽑아내기 위한 과정을 보자.
맥스에서 Mesh정보를 담고 있는 Mesh 클래스가 준비되어 있는데
Node로 부터 이 Mesh 클래스 정보를 얻을 수 있다.
전반적인 과정은 INode -> ObjectState -> TriObject -> Mesh 이다.

INode로부터 ObjectState 얻기.
ObjectState os = node->EvalWorldState(currentTime_);

ObjectState의 Object가 TriObject로 변환가능한지 체크.
if(!os.obj->CanConvertToType(triObjectClassID))
  return (TREE_CONTINUE);

ObjectState의 object를 TriObject로 변환.
TriObject* triObject = (TriObject*)object->ConvertToType(currentTime_, triObjectClassID);

TriObject의 Mesh정보 얻기.
Mesh* mesh = &triObject->mesh;

위와 같이 하면 Mesh 정보를 얻어 올 수 있다.



월드 행렬을 구하는 방법.
정점들을 월드 변환하기 위해 월드 행렬이 필요하다.
Matrix3 mat3Object = node->GetObjectTM(currentTime_); 

미러된 본을 쓰는지 검사.
BOOL negScale = TMNegParity(mat3Object);


ObjectTM : 오브젝트의 한 점을 월드좌표계로 변환하기 위한 TM을 의미.
                 부모TM, NodeTM, ObjectOffsetTM을 모두 포함.
ObjectTM = Offset Scale * Offset Rotation * Offset Position *
             Controller Scale * Controller Rotation * Controllers Position *
             Parent Transformation

이제 노드에서 얻은 메시로 정보를 좀 뽑아 봐야 겠다.
삼각형 단위로 정보를 보자면...
int cntFace = mesh->getNumFaces();    매시를 이루는 삼각형의 갯수.

Face* face
for( cntFace만큼)
{   
   face 구하기
   face = &mesh->faces[index];      

   face를 이루는 세 정점의 인덱스 구하기
   DWORD  vertexIdx[3];
   vertexIdx[0] = face->getVert(0);
   vertexIdx[1] = face->getVert(1);
   vertexIdx[2] = face->getVert(2);

   vertexIdx로 Vertex(x,ym,z) 구하기.
   Point3 vertex[3]
   vertex[0] = mesh->getVert(vertexIdx[0]);
   vertex[1] = mesh->getVert(vertexIdx[1]);
   vertex[2] = mesh->getVert(vertexIdx[2]);

   vertex에 월드 tm을 곱해서 월드 버텍스를 구한다.
   Point3 vertexWorld[3];
   vertexWorld[0] = vertex[0] * mat3Object;
   vertexWorld[1] = vertex[1] * mat3Object;
   vertexWorld[2] = vertex[2] * mat3Object;

   노말값 구하기
   normal이 face에 여러개인 경우 smoothgroup사용.
   DWORD smoothingGroup = face->getSmGroup();
   if(smoothingGroup)
  {
     vertex index로 RVertex 얻음
     RVertex* rvertex[3];
     rvertex[0] = mesh->getRVertPtr(vertexIdx[0]);
     rvertex[1] = mesh->getRVertPtr(vertexIdx[1]);
     rvertex[2] = mesh->getRVertPtr(vertexIdx[2]);

     for(rvertex[0~2]
    {
         edit normal로 수정된 normal 값을 뽑아 낸다
         MeshNormalSpec* meshNormalSpec = mesh->GetSpecifiedNormals();
         int cntNormal = rvertex->rFlags & NORCT_MASK; 

         if(1 == cntNormal)
            return rvertex->rn.getNormal();

         for(irn = 0; irn<cntNormal; irn++)
        {
            if(rvertex->ern[irn].getSmGroup() & smGroup)
            break;
        }
   }
   else
   {
       smooth group가 없는 경우 노말은 그냥 하나니까 (플랫 셰이딩) 그냥 쓰면 된다.
    }

RVertex : rFlages, pos, rn, ern을 인자로가진다.
      노말은 위치가 같아도 다른 방향이 있을 수 있기 때문에 이를 위해 이 구제체를 사용.
      rFlag는 rFlags&NORTC_MASK 처럼 사용하여 실제 pos 하나에 존재하는 normal 갯수를 알 수 있고
      rn은 RVertex가 가지는 normal이 단 한개일 때의 normal이고,
      ern두개 이상일 때의 normal 이다.

  노말 변환 방법
  Matrix3 matObjectNoScale = mat3Object;
  matObjectNoScale.NoScale();    
  normal[0] = VectorTransform(matObjectNoScale, normal[0]);
  normal[1] = VectorTransform(matObjectNoScale, normal[1]);
  normal[2] = VectorTransform(matObjectNoScale, normal[2]);

이렇게 해서 노드에서 Mesh를 얻고 이 메시로 부터 폴리곤을 얻고,
폴리곤을 이루고 있는 정점들을 얻고, 정점들의 pos, normal 값들을 얻었다.

이젠 material을 얻는 방법을 알아보자.
 BOOL hasMtl = TRUE;
 Mtl* mtlNode = node->GetMtl();
맥스에서는 하나의 노드에 하나의 재질만이 존재한다.
위의 예를 보면 GetMtl()을 사용하여 해당 재질 클래스의 인스턴스를 얻는 것을 볼 수 있다.

이 노드가 가지고 있는 material이 sub-material인지, 단일 material인지 분류해야 한다.
Texmap* pTexmap;
 Face* pFace = &mesh->faces[faceIdx];

if(!(Class_ID(MULTI_CLASS_ID, 0) == mtlNode->ClassID() && mtlNode->IsMultiMtl()))
{
   단일 재질인 경우
   pTexmap = mtlNode->GetSubTexmap( maxTexMapIndex );
}
else
{
   다중 재질인 경우
   MtlID mtlidFace = pFace->getMatID();
   Mtl *pmtlFace = mtlNode->GetSubMtl( mtlidFace);  서브 머티리얼 얻기

  if ( Class_ID( MULTI_CLASS_ID, 0) == pmtlFace->ClassID() && pmtlFace->IsMultiMtl())
  { 
      pmtlFace = pmtlFace->GetSubMtl( mtlidFace);
   }

   StdMat *pStdMtlFace = ( StdMat*)pmtlFace;                                   기본 재질에 설정
   pTexmap = pStdMtlFace->GetSubTexmap( maxTexMapIndex );
}

위와 같이 하여 TexMap을 얻는데 TexMap은 가상 텍스쳐 맵 인터페이스 이다.

TexMap이 Bitmap인지 검사는 아래와 같다.
if ( Class_ID( BMTEX_CLASS_ID, 0) == pTexmap->ClassID())

이렇게 해서 텍스쳐도 얻어왔고....
텍스쳐 얻어오면 이 텍스쳐를 쓰기 위해 텍스쳐 좌표도 있어야 하겠지...
텍스쳐 좌표를 얻기 위해선 UVVert와 TVFace를 이용해야 한다.
UVVert는 텍스쳐 버텍스 배열, UVW 좌표를 저장하며 Point3이다.
TVFace는 UVW와 색깔 verts 둘 다에 사용되는 자료형인데 이는 맥스에서
UVVert 배열이 배열과 완전히 독립적이라서 일대일 대응이 안되는 대신에
사용할 수 있는 별도의 배열이라고 볼 수 있다.
모든 면이 하나의 TVFace를 가지고 하나의 TVFace는 UVVert를 가리키는 세개의
인덱스가 필요한데 이렇게 번거롭게 만든 이유는 개발자로 하여금
매핑에 따라 완전히 다른 토폴로지를 적용할 수 있도록 하기 위함이다.
UVVert uvVert[3];
DWORD tvertexIdx[3];

TVFace* tvface = &mesh->tvFace[faceIdx];
tvertexIdx[0] = tvface->getTVert(0);
tvertexIdx[1] = tvface->getTVert(1);
tvertexIdx[2] = tvface->getTVert(2);

uvVert[0] = mesh->getTVert(tvertexIdx[0]);
uvVert[1] = mesh->getTVert(tvertexIdx[1]);
uvVert[2] = mesh->getTVert(tvertexIdx[2]);

uv를 위한 TVFace와 TVFace를 구하기 위한 TVert(index)가 있다는 것을 눈여겨 봐야 겠다.
이로써 uv까지 구했다..아자아자~!!!!

정점의 칼라를 구하는 방법은 아래와 같다.
tvertexIndex = tvFace[faceIdx].t[i];
VertColor* vc = &vtxColor[tvertexIndex];
BYTE r = (BYTE)(vc->x * 255.0f);
BYTE g = (BYTE)(vc->y * 255.0f);
BYTE b = (BYTE)(vc->z * 255.0f);
vtxColor2[i] = 0xff000000 | (DWORD)(r<<16) | (DWORD)(g<<8) | (DWORD)(b);

요정도면 대충 애니메이션이 없는 모델 뽑는데 필요한 정보 다인듯....
 
기하 파이프라인 시스템 
: http://blog.naver.com/lifeisforu?Redirect=Log&logNo=80022419420

max exporter에서 edit normal 값 뽑아내기
: http://narew.net/xe/4067

MaxExporterPlug-In
: http://kin3d.tistory.com/entry/MaxExporterPlug-In

Accessing Material Property
: http://blog.naver.com/lifeisforu/80023639369

3ds max sdk & script 팁
: http://zho.pe.kr/view.html?file_name=doc/maxsdk.txt

Working with Mesh
: http://blog.naver.com/bastard9/140069080440

MaxExport 3D Data 추출과 렌더링
: http://blog.naver.com/hkn10004/20104751231

SDK 일반용어
: http://blog.naver.com/lifeisforu/80022418588

'Study > Character' 카테고리의 다른 글

Max Export - 4  (1) 2012.01.06
Max Export - 3  (0) 2012.01.05
Max Export - 1  (0) 2012.01.01
유용한 링크들  (0) 2012.01.01
max importer만들기 exporter 만큼이나 쉬운 importer  (0) 2011.05.27
TAGS.

Comments