XML Exporter: 하드웨어 스킨 애니메이션2

앞장에서는 EHardwareBoneMesh에서 스킨이 들어간 본메쉬와  스킨이 없는 뼈대의 본메쉬를 같이 처리했다. 스킨이 없는것과 있는 것을 분리하는 것이 코드의 가독성이 좋기 때문에 두 개로 분리하기로 하였다.

두 개를 분리하기 위해서 맥스 플러그인에 본인지 아닌지 속성을 추가 하였다. 본이면 뼈대가 있는 메쉬로 스킨이 없다. 본이 아닌 경우 메시가 있다면 스킨 정보가 포함된 메쉬이다.

< 맥스 플러그인에 본인지 아닌지 추가 >

애니메이션 정보를 Xml 파일에 설정할 때, 본인지 아닌지 속성을 추가한다. 본이면 애니메이션 정보를 Xml에 추가 하지만 아니면 리턴한다.

XmlExp* Export::WriteAnimation(INode* pNode, XmlExp* pParentXML)

{

    if( IsBone( pNode ) == false )

    {

        pParentXML->AddAttribute( "bone", "false" );

        return NULL;

    }

    pParentXML->AddAttribute( "bone", "true" );

    .................

}

< 하드웨어 스킨 뷰어 >

1. 엔진노드 생성:
앞에서도 이야기 했지만 OnXmlToENode() 메서드에서 Xml노드에서 엔진노드로 변환 한다고 하였다.
현재 노드가 본이면 EHardwareBone 갟체를 생성하고 본이 아니면(스킨 정보가 포함 되어 있으면) EHardwareBoneMesh 객체를 생성한다.

ENode* XmlMesh::OnXmlToENode( ENode* pParent )

{

    ............

    std::string* boneStr =  this->GetAttribute( "bone" );

    bool bBone = false;

    if( boneStr )

        bBone = ToBool( *boneStr );

 

    if( m_vertexArr.size() > 0 )

    {

        if( bBone )

        {

            EHardwareBone* pMesh = new EHardwareBone( g_d3d_Device );

            ..............       

        }

        else

        {

            EHardwareBoneMesh* pMesh = new EHardwareBoneMesh( g_d3d_Device );

            ..............

        }

    }

    .............

}

2. 팔레트 행렬 셋팅

EHardwareBoneMesh, EHardwareBone 두 객체 모두 같은 코드이지만 EHardwareBoneMesh는 애니메이션 정보가 없기 때문에 항상 단위행렬만 들어갈 것이다.
EHardwareBone의 경우에는 애니메이션가 있기 때문에 애니메이션 배열에서 값을 읽어서 팔레트 행렬을 셋팅 할 것이다.

void EHardwareBone::OnFrameMove()

{

    if( this->m_nAniSize > 0 )

    {

        int nFrame = GameTime::GetFrame();   

        m_matWorld = m_aniArray[nFrame];   

    }

    else

        D3DXMatrixIdentity(&m_matWorld);

 

    if( m_id >= 0 )

        m_matBlend[m_id] = m_matWorld;

}

3. 렌더링

EHardwareBone의 경우에는 스킨정보가 없기 때문에 일반적인 Rigid 메쉬를 처리 하는것처럼 하면 된다.
스킨 정보가 포함 되어 있는 EHardwareBoneMesh를 렌더링 할려면 가중치와 참조하는 인덱스를 팔레트 행렬을 셋팅해야 한다.

하드웨어 팔레트 행렬을 제대로 지원하는 그래픽 카드가 없기 때문에 소프트웨어 정점 처리로 바꾼다. 렌더 상태 D3DRS_INDEXEDVERTEXBLENDENABLE, D3DRS_VERTEXBLEND를 설정한다.
팔레트 행렬을 셋팅한다.
자세한건 XML Exporter: 하드웨어 스킨 애니메이션를 참조한다.

int    EHardwareBone::OnRender()

{

    ..................

    m_pDevice->SetTransform(D3DTS_WORLD, &(m_matBlend[m_id] * scaleMat));

    m_pDevice->SetFVF( HardwareBoneVertex::FVF );

    m_pDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST,

        0, m_nVertex, m_nTriangle, m_pIndex, D3DFMT_INDEX16, m_pBoneVerts, sizeof(HardwareBoneVertex) );

    ..................

}

 

int EHardwareBoneMesh::OnRender()

{

    ..................

    m_pDevice->SetSoftwareVertexProcessing( TRUE );

    m_pDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE );

    m_pDevice->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS );

 

    for(int k = 0; k < MAX_BLEND; ++k)

        m_pDevice->SetTransform( D3DTS_WORLDMATRIX(k), &( m_matBlend[k] * scaleMat ) );

    ..................

    m_pDevice->SetFVF( HardwareBlendVertex::FVF );

    m_pDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST,

        0, m_nVertex, m_nTriangle, m_pIndex, D3DFMT_INDEX16, m_pMeshVerts, sizeof(HardwareBlendVertex) );

    ..................

}

버그 수정:  "Mesh" 정보를 상위노드에 저장
XmlMesh 노드의 이름이 "Mesh"일때 ConvertMeshInfo()가 불린다. 즉 현재노드 이름이 "Mesh"이다. 메시 정보는 상위노드에서 가지고 있어야 하므로 정점과 인덱스, 참조 본 인덱스, 본 가중치를 현재노드가 아니라 상위 노드에 저장하는걸로 버그를 수정 하엿다.

void XmlMesh::ConvertMeshInfo()

{

    ..........

    pXmlMesh->FetchVertex( GetParent()->m_vertexArr );

    ..........

    pXmlMesh->FetchFace( GetParent()->m_indexArr );

    ..........

    pXmlMesh->FetchBoneIndex( GetParent()->m_vertexArr );

    ..........

    pXmlMesh->FetchBoneWeight( GetParent()->m_vertexArr );

    ..........

}

프로젝트:

맥스 플러그인 :  maxProject_bone.zip

뷰어: viewer_hardware.zip