XML Exporter: 셰이더 스킨 애니메이션

하드웨어 스킨 애니메이션에 이어 셰이더 스킨 애니메이션을 구현해 보자.

이펙트와 HLSL은 자세히 설명하지 않겠다. 하드웨어 스키닝과 비교하여 바뀐점만 이야기 하겠다.

셰이더 기반 스키닝은 인덱스 스키닝 방식에 기반을 두고 있다.

팔레트 매트릭스들을 참조하기 위해 사용되는 IDirect3DDevice9::SetTransform 함수 대신에 셰이더 스키닝에서는 ID3DXBaseEffect::SetMatrixArray 함수를 사용하여 팔레트 매트릭스를 전달한다.

셰이더를 처리하는 클래스는 EShaderBoneMesh, EShaderBone 두 개의 클래스이다.

CreateVertexBuffer()에서 정점 버터를 만들때, 참조 행렬 인덱스( boneIndex)는 갯수만큼 정점버퍼에 저장하지만 가중치는 갯수보다 하나 적게 저장한다. 가중치의 합은 1이기 때문에 마지막 가중치는 1에서 이전 가중치를 빼면 된다.

int EShaderBoneMesh::CreateVertexBuffer( XmlNode* pXmlNode )

{

    ........

    m_pMeshVerts = new ShaderBlendVertex[ m_nVertex ];

    memset( m_pMeshVerts, 0, sizeof(ShaderBlendVertex) * m_nVertex );

    for( int i = 0; i < n; ++i )

    {

        m_pMeshVerts[i].p.x = xmlVx[i].p.x;

        m_pMeshVerts[i].p.y = xmlVx[i].p.y;

        m_pMeshVerts[i].p.z = xmlVx[i].p.z;

 

        int count = (int)xmlVx[i].boneIndex.size();

 

        for( int j = 0; j < count; ++j )

        {

            //가중치가 3보다 작을때만 대입한다. 예를들면 4개의 가중치는 1 = a + b + c + d일때,

            //마지막 4번째 가중치 d는 d = 1 - ( a + b + c )처럼 빼면 된다.

            if( j >= 4 )

                break;

            m_pMeshVerts[i].boneIndex[j] =  xmlVx[i].boneIndex[j];   

            if( j < 3 )

                m_pMeshVerts[i].weight[j] = xmlVx[i].boneWeight[j];

        }

    }

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

렌더링시 이펙트 관련(HLSL) 설정을 한다.
렌더링 단계에서 정점 선언, 테크닉 설정, 이펙트 상수 설정, 렌더링, FX설정값 NULL로 지정 순서로 진행한다.

int EShaderBoneMesh::OnRender()

{

    if( m_pMeshVerts == NULL )

        return 0;

 

    m_pDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME);

    m_pDevice->SetSoftwareVertexProcessing(TRUE);

 

    D3DXMATRIX    matView, matProj;

    LPD3DXEFFECT pShaderEffect = Shader::Instance()->GetEffect();

    HRESULT hr = pShaderEffect->SetTechnique("Tech");

    hr = m_pDevice->GetTransform(D3DTS_VIEW, &matView);

    hr = m_pDevice->GetTransform(D3DTS_PROJECTION, &matProj);

 

    hr = pShaderEffect->SetMatrix("m_mtViw", &matView);   

    hr = pShaderEffect->SetMatrix("m_mtPrj", &matProj);

 

    //모델 축소

    D3DXMATRIXA16 scaleMat;  D3DXMatrixIdentity( &scaleMat );  D3DXMatrixScaling( &scaleMat, 0.4f, 0.4f, 0.4f );

 

    hr = pShaderEffect->SetMatrix("m_mtWld", &scaleMat);        // 월드 행렬 설정

    hr = pShaderEffect->SetMatrixArray("m_mtBlnd", m_matBlend, MAX_BLEND);    // Blending 행렬 설정

 

    UINT cPass;

    hr = pShaderEffect->Begin( &cPass, 0 );

    hr = pShaderEffect->BeginPass( 1 );

 

    hr = m_pDevice->SetVertexDeclaration( Shader::Instance()->GetMeshDecl() );

 

    m_pDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST,

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

 

    pShaderEffect->EndPass();

    pShaderEffect->End();

 

    m_pDevice->SetVertexDeclaration(NULL);

    m_pDevice->SetVertexShader(NULL);

    m_pDevice->SetPixelShader(NULL);

    m_pDevice->SetSoftwareVertexProcessing(FALSE);

    m_pDevice->SetTexture(0, NULL);

    return 1;

}

 

프로젝트: viewer_shaderSkin.zip