max export 6. 드디어 Animation !!!!

반응형


요즘 새로운 준비 때문에 고민도 많고, 그래서 마음이 급해져서
이리저리 준비하려하다보니 제풀에 지쳐서 힘들어하게 된다..
이럴 때 일수록 하고있던 것들을 완벽하게 마무리 해야지...


ㅇㅇ 좀 짱인듯
Graph Editors를 보면 Entities을 선택해서 볼 수 있다.
1. Base Objects를 선택하면 Cylinder, Box, Pyramid와 같은 Object 정보가 나온다.
2. Modifier Stack를 선택하면 Modified Object가 있을 경우 표시를 해주고 UVW Mapping 표시를 해준다.
    위의 그림에서는 Wheel이 이 경우에 속한다.
3. Controllers를 선택하면 Position, Rotation, Scale을 표시해 준다.

이 Graph Editors 정보를 보면서 export를 만들면 나름 편안.ㅇㅇ

max에서의 시간
1. max에서는 TimeValue를 사용하는데 이는 maxtype.h에 들어있다.
2. 각각의 증가단위는 tick이라고 부른다.
3. tick는 max에서 가장 작은 증가단위이다.
4. tick들은 TicksToSec()함수를 사용해서 second들로 변환할 수 있다.
5. second들 또한 SecToTicks()함수를 사용해서 tick들로 변환할 수 있다.
6. tick들은 GetTicksPerFrame()함수와의 곱셈에 의해 frame들로 변환된다.

애니메이션을 취급하기 위해서는 특정 시간 지점과 특정 시간 간격을 지정할 필요가 있다.
즉, Time(시간)과 Interval(간격)의 개념이 필요하다.
max상에서 기본 시간단위는 1/4800초이며 이 시간 길이를 TimeValue라는 데이터형으로 만들었다.
Interval은 보통 오브젝트가 변경되지 않은 시간 간격을 정의하는데 사용된다.
만약 애니메이션되는 플러그인이 그것이 변경되지 않은 간격이 얼마인지를 지정할 수 있다면,
3ds max는 그 시간동안에 그 오브젝트를 재평가할 필요가 없을을 알 수 있기 때문이다.
Interval은 SDK에 정의된 클래스로서 시작시간과 끝시간 사이의 시간간격에 대한 클래스이다.
시작시간과 끝 시간을 설정하거나 검색하고, 간격을 계산하고 지정된 시간이 인터벌안에 있는지 검사한다.

간단하게 Animation을 위한 Interval 시간과 PRS 변환정보만을 출력해보자.
void MgExport2::ExportAnimation(INode* node, int treeDepth)
{
  /*
 이 노드가 애니메이트된건지 아는 방법은?
  한가지 방법은 validity interval들을 사용하는 것이다.
  만약 transform이 valid forever이라면 결코 변하지 않는다.
 */
 Interval nodeValid = FOREVER;
 node->GetNodeTM(0, &nodeValid);
 if(FOREVER == nodeValid)
  return;

 // max상의 화면에서 time range를 얻는다. - ani 간격 (애니메이션의 시작과 끝 정보)
 Interval animRange = GetCOREInterface()->GetAnimRange();

 // max상의 1초는 4800 tick.
 // TIME_TICKSPERSEC 이 4800으로 define되어 있음.
 // #define SetToTicks(sec)((TimeValue)(secs*TIME_TICKSPERSEC)).
 const int sampleFPS = 5;
 TimeValue increment = SecToTicks(1.0f / sampleFPS); // 1.0/5.0 = 0.2초. 0.2초마다 샘플링.
                      
 // animation들의 지속시간을 출력
 Write(treeDepth, " PRS Anim Start : %fs, Anim End : %fs", TicksToSec(animRange.Start()), TicksToSec(animRange.End()));

 // 애니메이션 범위동안 노드 샘플링 정보를 출력.
 for(TimeValue t = animRange.Start(); t < animRange.End(); t += increment)
 {
  Write(treeDepth+1, "SampleTime: %fs", TicksToSec(t));
  ExportPRS(node, treeDepth+1, t);
 }
}


얼추 이런식이다.

export 1~6까를 보자면....
1. scene의 node들을 순회하는 방법.  - 자식 노드를 얻어 순회
   INode::NumberOfChildren() : 자식 노드의 갯수 얻기.
   INode::GetChildNode() : 자식 노드 얻기

2.  Node들이 포함하는 object들에 접근과 사용방법.
     object들은 Geometries, Light, Cameras 등이 될 수 있다.
    INode::GetObjectRef() : object 얻기
    Object::ConvertToType() : 원하는 타입으로 변환해서 사용

3. affine matrices의 사용.
    AffineParts : 3ds Max에서 사용하는 구조체, (이동, 회전, 스케일회전, 스케일, 부호)값.
    decomp_affine : AffineParts 구조체 값을 얻음.

4. Node들은 주어진 시간에 어디에 있는지를 정의하는 PRS(position, rotation, scale)정보가 있다.
    PRS 데이터를 사용하기 위해 행렬을 구한다.
    Matrix3 tmWorld  = node->GetNodeTM(timeValue);
    Matrix3 tmParent = node->GetParentTM(timeValue);
    Matrix3 tmLocal  = tmWorld * Inverse(tmParent);

   위 정보들을 사용해서 3번에서 구한 affine 데이터로 PRS 정보를 획득.
   Write(indent, "PRS: P (%f, %f, %f", affine.t.x, affine.t.y, affine.t.z);
   Write(indent, "PRS: R (%f, %f, %f", rotEuler[0], rotEuler[1], rotEuler[2]);
   Write(indent, "PRS: S (%f, %f, %f", affine.k.x, affine.k.y, affine.k.z);

5. TimeValue라는 시간 간격 타입이 있다.
    Interval nodeValid;

6. 어떻게 animation을 resample하는가?
    GetAnimRange() : 애니메이션 시작과 끝정보를 위해 얻음.
    TimeValue increment = SecToTicks(1.0f / sampleFPS) : 샘플링 주기 설정.
    TicksToSec(animRange.Start()), TicksToSec(animRange.End()) : 애니메이션 시작과 끝 정보
    for(TimeValue t = animRange.Start(); t < animRange.End(); t += increment) :
   {
      Write(treeDepth+1, "SampleTime: %fs", TicksToSec(t));
      ExportPRS(node, treeDepth+1, t);
   }

7. AffineParts는 sample matrices로부터 PRS 데이터를 추출하는데 쓰인다.

요기까지인듯...좀 더 열심히!!!

TAGS.

Comments