Working with skeletal animation(8)

Working with skeletal animation(8)

As shown in Figure 4.5, the SkeletalAnim mesh demonstrates what you learned in this chapter by loading a skinned mesh (the Tiny.x mesh provided in the DirectX SDK samples) and rendering it to the display.

Working with skeletal animation(8)_第1张图片

Figure 4.5: Meet Tiny, Microsoft's woman of skeletal meshes. She is constructed from a single mesh and an underlying hierarchy of invisible bones.

source added into Direct3D.cpp:

// -------------------------------------------------------------------------------------------
//  Declare an internal .X file parser class for loading meshes and frames.
// -------------------------------------------------------------------------------------------
class  cXInternalParser
{
public :
    
//  information passed from calling function
    IDirect3DDevice9 *         m_device;
    
const   char *                 m_texture_path;
    DWORD                    m_new_fvf;
    DWORD                    m_load_flags;

    DWORD                    m_flags;    
//  flags for which data to load: 1 = mesh, 2 = frames, 3 = both.

    
//  hierarchies used during loading
    D3DXMESHCONTAINER_EX *     m_root_mesh_container;
    D3DXFRAME_EX
*             m_root_frame;

protected :
    
void  parse_object(ID3DXFileData *  xfile_data,
                      ID3DXFileData
*  parent_xfile_data,
                      DWORD   depth,
                      
void **   data,
                      
bool       force_ref);

    
void  parse_child_object(ID3DXFileData *  xfile_data, DWORD depth,  void **  data,  bool  force_ref);

public :
    cXInternalParser();
    
~ cXInternalParser();

    
bool   parse( const   char *  filename,  void **  data);
    
char *  get_name(ID3DXFileData *  xfile_data);
};

// ==============================================================================================
//  Generic .X parser class code
// ==============================================================================================

cXInternalParser::cXInternalParser()
{
    ZeroMemory(
this sizeof ( * this ));
}

cXInternalParser::
~ cXInternalParser()
{
    delete m_root_mesh_container;    m_root_mesh_container 
=  NULL;
    delete m_root_frame;            m_root_frame 
=  NULL;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

bool  cXInternalParser::parse( const   char *  filename,  void **  data)
{
    
if (filename  ==  NULL)
        
return   false ;

    ID3DXFile
*  xfile;

    
if (FAILED(D3DXFileCreate( & xfile)))
        
return   false ;

    
//  register standard templates
     if (FAILED(xfile -> RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
    {
        xfile
-> Release();
        
return   false ;
    }

    ID3DXFileEnumObject
*  xfile_enum;

    
if (FAILED(xfile -> CreateEnumObject(filename, DXFILELOAD_FROMFILE,  & xfile_enum)))
    {
        xfile
-> Release();
        
return   false ;
    }

    SIZE_T num_child;
    xfile_enum
-> GetChildren( & num_child);

    
//  loop through all top-level objects, breaking on errors.
     for (SIZE_T i  =   0 ; i  <  num_child; i ++ )
    {
        ID3DXFileData
*  xfile_data;
        xfile_enum
-> GetChild(i,  & xfile_data);

        parse_object(xfile_data, NULL, 
0 , data,  false );
        release_com(xfile_data);
    }

    release_com(xfile_enum);
    release_com(xfile);

    
return   true ;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

void  cXInternalParser::parse_object(ID3DXFileData *  xfile_data, 
                                    ID3DXFileData
*  parent_xfile_data, 
                                    DWORD depth, 
void **  data,  bool  force_ref)
{
    GUID type;
    xfile_data
-> GetType( & type);

    
//  process templates based on their type
     if (type  ==  TID_D3DRMFrame  &&  (m_flags  &  PARSE_FRAME)  &&  force_ref  ==   false )
    {
        D3DXFRAME_EX
*  frame  =   new  D3DXFRAME_EX;
        frame
-> Name  =  get_name(xfile_data);

        
//  link frame into hierarchy
         if (data  ==  NULL)
        {
            
//  link as sibling of root
            frame -> pFrameSibling  =  m_root_frame;
            m_root_frame 
=  frame;
            frame 
=  NULL;

            data 
=  ( void ** & m_root_frame;
        }
        
else
        {
            
//  link as child of supplied frame
            D3DXFRAME_EX *  frame_ptr         =  (D3DXFRAME_EX * ) * data;
            frame
-> pFrameSibling         =  frame_ptr -> pFrameFirstChild;
            frame_ptr
-> pFrameFirstChild  =  frame;
            frame 
=  NULL;

            data 
=  ( void ** ) & frame_ptr -> pFrameFirstChild;
        }
    }
    
else   if (type  ==  TID_D3DRMFrameTransformMatrix  &&  (m_flags  &  PARSE_FRAME)  &&  data  &&  force_ref  ==   false )
    {
        D3DXFRAME_EX
*  frame  =  (D3DXFRAME_EX * ) * data;

        
if (frame)
        {
            SIZE_T size;
            
const   void *  tran_matrix;

            xfile_data
-> Lock( & size,  & tran_matrix);

            frame
-> TransformationMatrix  =   * (( const  D3DXMATRIX * ) tran_matrix);
            frame
-> mat_original             =  frame -> TransformationMatrix;

            xfile_data
-> Unlock();
        }
    }
    
else   if (type  ==  TID_D3DRMMesh  &&  (m_flags  &  PARSE_MESH))     //  load a mesh (skinned or regular)
    {
        
if (force_ref  ==   false )
        {
            D3DXMESHCONTAINER_EX
*  mesh_container;
            load_mesh(
& mesh_container, m_device, xfile_data, m_texture_path, m_new_fvf, m_load_flags);

            
//  link mesh to head of list of meshes0
             if (mesh_container)
            {
                mesh_container
-> pNextMeshContainer  =  m_root_mesh_container;
                m_root_mesh_container 
=  mesh_container;
                mesh_container 
=  NULL;

                
//  link mesh to frame if needed
                 if (data)
                {
                    D3DXFRAME_EX
*  frame  =  (D3DXFRAME_EX * * data;

                    
if ((m_flags  &  PARSE_FRAME)  &&  frame)
                        frame
-> pMeshContainer  =  m_root_mesh_container;
                }
            }
        }
        
else      //  referenced, then check if wanting to link to frame.
        {
            
if (data)
            {
                D3DXFRAME_EX
*  frame  =  (D3DXFRAME_EX * * data;

                
if ((m_flags  &  PARSE_FRAME)  &&  m_root_mesh_container  &&  frame)
                {
                    
char *  name  =  get_name(xfile_data);

                    
if (name)
                    {
                        frame
-> pMeshContainer  =  m_root_mesh_container -> find(name);

                        delete[] name;
                        name 
=  NULL;
                    }
                }
            }
        }
    }
    
    parse_child_object(xfile_data, depth, data, force_ref);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

void  cXInternalParser::parse_child_object(ID3DXFileData *  xfile_data, 
                                          DWORD depth, 
void **  data,  bool  force_ref)
{
    SIZE_T num_child;
    xfile_data
-> GetChildren( & num_child);

    
//  scan for embedded templates
     for (SIZE_T i  =   0 ; i  <  num_child; i ++ )
    {
        ID3DXFileData
*  child_xfile_data;
        xfile_data
-> GetChild(i,  & child_xfile_data);

        
if (child_xfile_data -> IsReference())
            force_ref 
=   true ;

        parse_object(child_xfile_data, xfile_data, depth
+ 1 , data, force_ref);
        release_com(child_xfile_data);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////

char *  cXInternalParser::get_name(ID3DXFileData *  xfile_data)
{
    
if (xfile_data  ==  NULL)
        
return  NULL;

    DWORD size;

    
if (FAILED(xfile_data -> GetName(NULL,  & size)))
        
return  NULL;

    
char *  name  =  NULL;

    
if (size  >   1 )
    {
        name 
=   new   char [size];
        xfile_data
-> GetName(name,  & size);
    }

    
return  name;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

HRESULT load_mesh(D3DXMESHCONTAINER_EX
**  ret_mesh_container,
                  D3DXFRAME_EX
**  ret_frame,
                  IDirect3DDevice9
*  device,
                  
const   char *  filename,
                  
const   char *  texture_path,
                  DWORD new_fvf,
                  DWORD load_flags)
{
    
//  error checking
     if (device  ==  NULL  ||  filename  ==  NULL  ||  texture_path  ==  NULL)
        
return  E_FAIL;

    cXInternalParser parser;

    
//  set parser data
    parser.m_device             =  device;
    parser.m_texture_path    
=  texture_path;
    parser.m_new_fvf        
=  new_fvf;
    parser.m_load_flags        
=  load_flags;
    parser.m_flags            
=  ((ret_mesh_container  ==  NULL)  ?  PARSE_NONE : PARSE_MESH)  |
                              ((ret_frame 
==  NULL)  ?  PARSE_NONE : PARSE_FRAME);

    
//  clear mesh and frame pointers
    parser.m_root_frame  =  NULL;
    parser.m_root_mesh_container 
=  NULL;

    
if ( !  parser.parse(filename, NULL))
        
return  E_FAIL;

    
//  Map the matrices to the frames and create an array of bone matrices,
    
//  but only if user passed pointers to receive and the loader found some meshes and frames.
     if (ret_mesh_container  &&  ret_frame  &&  parser.m_root_mesh_container  &&  parser.m_root_frame)
    {
        
//  scan through all meshes

        D3DXMESHCONTAINER_EX
*  mesh_container  =  parser.m_root_mesh_container;

        
while (mesh_container)
        {
            
//  does this mesh use skinning?
             if (mesh_container -> pSkinInfo)
            {
                DWORD num_bones 
=  mesh_container -> pSkinInfo -> GetNumBones();

                
//  allocate the matrix pointers and bone matrices
                mesh_container -> frame_combined_matrices  =   new  D3DXMATRIX * [num_bones];
                mesh_container
-> bone_trans_matrices         =   new  D3DXMATRIX[num_bones];

                
//  match matrix poiners to frames
                 for (DWORD i  =   0 ; i  <  num_bones; i ++ )
                {
                    
const   char *  bone_name  =  mesh_container -> pSkinInfo -> GetBoneName(i);
                    D3DXFRAME_EX
*  frame    =  parser.m_root_frame -> find(bone_name);

                    
//  match frame to bone
                     if (frame)
                        mesh_container
-> frame_combined_matrices[i]  =   & frame -> mat_combined;
                    
else
                        mesh_container
-> frame_combined_matrices[i]  =  NULL;
                }
            }

            
//  go to next mesh
            mesh_container  =  (D3DXMESHCONTAINER_EX * ) mesh_container -> pNextMeshContainer;
        }
    }

    
if (ret_mesh_container)
    {
        
//  copy the pointer into passed variables
         * ret_mesh_container  =  parser.m_root_mesh_container;
        parser.m_root_mesh_container 
=  NULL;
    }
    
else
    {
        
//  delete list of meshes in case any were not needed.
        delete parser.m_root_mesh_container;
        parser.m_root_mesh_container 
=  NULL;
    }

    
if (ret_frame)
    {
        
//  assign frame hierarchy pointer
         * ret_frame  =  parser.m_root_frame;
        parser.m_root_frame 
=  NULL;
    }
    
else
    {
        
//  delete frame hierarchy in case it was loaded and it was not needed.
        delete parser.m_root_frame;
        parser.m_root_frame 
=  NULL;
    }

    
return  S_OK;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

HRESULT update_skin_mesh(D3DXMESHCONTAINER_EX
*  mesh_container)
{
    
if (mesh_container  ==  NULL)
        
return  E_FAIL;

    
if (mesh_container -> MeshData.pMesh  ==  NULL  ||  mesh_container -> skin_mesh  ==  NULL  ||  mesh_container -> pSkinInfo  ==  NULL)
        
return  E_FAIL;

    
if (mesh_container -> bone_trans_matrices  ==  NULL  ||  mesh_container -> frame_combined_matrices  ==  NULL)
        
return  E_FAIL;

    
//  copy the bone matrices over (must have been combined before call draw_mesh)
     for (DWORD i  =   0 ; i  <  mesh_container -> pSkinInfo -> GetNumBones(); i ++ )
    {
        
//  start with bone offset matrix
        mesh_container -> bone_trans_matrices[i]  =   * (mesh_container -> pSkinInfo -> GetBoneOffsetMatrix(i));

        
//  apply frame transformation
         if (mesh_container -> frame_combined_matrices[i])
            mesh_container
-> bone_trans_matrices[i]  *=  ( * mesh_container -> frame_combined_matrices[i]);
    }

    
void *  src_vertices;
    
void *  dest_vertices;

    mesh_container
-> MeshData.pMesh -> LockVertexBuffer(D3DLOCK_READONLY, ( void ** ) & src_vertices);
    mesh_container
-> skin_mesh -> LockVertexBuffer( 0 , ( void ** ) & dest_vertices);

    
//  update the skinned mesh using provided transformations
    mesh_container -> pSkinInfo -> UpdateSkinnedMesh(mesh_container -> bone_trans_matrices, NULL, src_vertices, dest_vertices);

    mesh_container
-> MeshData.pMesh -> UnlockVertexBuffer();
    mesh_container
-> skin_mesh -> UnlockVertexBuffer();    

    
return  S_OK;
}

 

WinMain.cpp:

#include  < windows.h >
#include 
< d3d9.h >
#include 
< d3dx9.h >
#include 
" Direct3D.h "

IDirect3D9
*                 g_d3d;
IDirect3DDevice9
*         g_device;
D3DXMESHCONTAINER_EX
*     g_mesh_container;
D3DXFRAME_EX
*             g_frame;

float  g_mesh_radius  =   0.0f ;     //  bounding radius of mesh

const   char  CLASS_NAME[]  =   " SkeletalClass " ;
const   char  CAPTION[]     =   " Skeletal Demo " ;

////////////////////////////////////////////////////////////////////////////////////////////////

LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

bool  do_init(HWND hwnd);
void  do_shutdown();
void  do_frame();


///////////////////////////////////////////////////////////////////////////////////////////// /

int  PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR,  int  cmd_show)
{      
    CoInitialize(NULL);    
//  Initialize the COM system

    
//  Create the window class here and register it

    WNDCLASSEX win_class;  

    win_class.cbSize        
=   sizeof (win_class);
    win_class.style         
=  CS_CLASSDC;
    win_class.lpfnWndProc   
=  window_proc;
    win_class.cbClsExtra    
=   0 ;
    win_class.cbWndExtra    
=   0 ;
    win_class.hInstance     
=  inst;
    win_class.hIcon         
=  LoadIcon(NULL, IDI_APPLICATION);
    win_class.hCursor       
=  LoadCursor(NULL, IDC_ARROW);
    win_class.hbrBackground 
=  NULL;
    win_class.lpszMenuName  
=  NULL;
    win_class.lpszClassName 
=  CLASS_NAME;
    win_class.hIconSm       
=  LoadIcon(NULL, IDI_APPLICATION);

    
if ( ! RegisterClassEx( & win_class))
        
return   - 1 ;

    
//  Create the main window
    HWND hwnd  =  CreateWindow(CLASS_NAME, CAPTION, WS_CAPTION  |  WS_SYSMENU  |  WS_MINIMIZEBOX,
                             
0 0 640 480 , NULL, NULL, inst, NULL);

    
if (hwnd  ==  NULL)
        
return   - 1 ;

    ShowWindow(hwnd, cmd_show);
    UpdateWindow(hwnd);

    
//  Call init function and enter message pump
     if (do_init(hwnd)) 
    {
        MSG msg;    
        ZeroMemory(
& msg,  sizeof (MSG));

        
//  Start message pump, waiting for user to exit
         while (msg.message  !=  WM_QUIT) 
        {
            
if (PeekMessage( & msg, NULL,  0 0 , PM_REMOVE)) 
            {
                TranslateMessage(
& msg);
                DispatchMessage(
& msg);
            }
            
            do_frame();    
//  Render a single frame
        }
    }
  
    do_shutdown();
    UnregisterClass(CLASS_NAME, inst);
    CoUninitialize();

    
return   0 ;
}

LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    
//  Only handle window destruction messages
     switch (msg) 
    {
    
case  WM_DESTROY:
        PostQuitMessage(
0 );
        
break ;

    
case  WM_KEYDOWN:
        
if (wParam  ==  VK_ESCAPE)
            DestroyWindow(hwnd);

        
break ;
    }

    
return  DefWindowProc(hwnd, msg, wParam, lParam);
}

bool  do_init(HWND hwnd)
{
    init_d3d(
& g_d3d,  & g_device, hwnd,  false false );

    
if (FAILED(load_mesh( & g_mesh_container,  & g_frame, g_device,  " ..\\Data\\tiny.x " " ..\\Data\\ " 0 0 )))
        
return   false ;

    
//  get the bounding radius of the object

    g_mesh_radius 
=   0.0f ;

    D3DXMESHCONTAINER_EX
*  mesh_container  =  g_mesh_container;

    
while (mesh_container)
    {
        ID3DXMesh
*  mesh  =  mesh_container -> MeshData.pMesh;

        
if (mesh)
        {
            
//  lock the vertex buffer, get its radius, and unlock buffer.

            D3DXVECTOR3
*  vertices;
            D3DXVECTOR3  center;
            
float          radius;

            mesh
-> LockVertexBuffer(D3DLOCK_READONLY, ( void ** ) & vertices);

            D3DXComputeBoundingSphere(vertices, mesh
-> GetNumVertices(), D3DXGetFVFVertexSize(mesh -> GetFVF()),
                                      
& center,  & radius);
            
            mesh
-> UnlockVertexBuffer();

            
//  update radius
             if (radius  >  g_mesh_radius)
                g_mesh_radius 
=  radius;
        }

        
//  goto next mesh
        mesh_container  =  (D3DXMESHCONTAINER_EX * ) mesh_container -> pNextMeshContainer;
    }

    
return   true ;
}

void  do_shutdown()
{
    
//  free mesh data
    delete g_mesh_container;    g_mesh_container  =  NULL;
    delete g_frame;                g_frame 
=  NULL;
    
    
//  release D3D objects
    release_com(g_device);
    release_com(g_d3d);
}

void  do_frame()
{
    
//  calculate a view transformation matrix using the mesh's bounding radius to position the viewer

    
float  distance  =  g_mesh_radius  *   3.0f ;
    
float  angle        =  timeGetTime()  /   2000.0f ;        

    D3DXMATRIX  mat_view;
    D3DXVECTOR3 eye(cos(angle) 
*  distance, g_mesh_radius, sin(angle)  *  distance);
    D3DXVECTOR3 at(
0.0f 0.0f 0.0f );
    D3DXVECTOR3 up(
0.0f 1.0f 0.0f );

    D3DXMatrixLookAtLH(
& mat_view,  & eye,  & at,  & up);
    g_device
-> SetTransform(D3DTS_VIEW,  & mat_view);

    
//  rebuild the frame hierarchy transformations
     if (g_frame)
        g_frame
-> update_hierarchy(NULL);

    
//  rebuild the mesh
    update_skin_mesh(g_mesh_container);

    
//  clear the device and start drawing the scene

    g_device
-> Clear( 0 , NULL, D3DCLEAR_TARGET  |  D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA( 0 0 64 255 ),  1.0f 0 );

    g_device
-> BeginScene();

    D3DXMATRIX mat_world;
    D3DXMatrixIdentity(
& mat_world);
    g_device
-> SetTransform(D3DTS_WORLD,  & mat_world);

    draw_mesh(g_mesh_container);

    g_device
-> EndScene();

    g_device
-> Present(NULL, NULL, NULL, NULL);
}

 

download source file


你可能感兴趣的:(Working with skeletal animation(8))